# Quotes and sales documents

Connect can create and modify documents as new versions, with provenance and an audit entry on each, through one file service both audiences share. What it cannot do is originate the commercial terms inside them: a quote assembles figures that already exist in Knowledge or that a person has decided. There is no separate quote record — a quote is a file attached to the work.

- **Status:** Available
- **Audience:** both
- **In the app:** #/data, #/pipeline, #/knowledge
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/sales/quotes-and-documents/

## What can be produced

Files are created and modified through `file_workspace`, which stores them as `media_assets` — already workspace-scoped and under row-level security, so a document inherits the same isolation as everything else rather than living in a new table with new rules.

| Direction | What is supported | Notes |
|---|---|---|
| Read | PDF, DOCX, XLSX, PPTX, CSV and TSV, TXT, MD, JSON, PNG, JPEG, WebP | PDF is read from its text layer where it has one, otherwise by the model |
| Write | New files, and modifications saved as new versions | The earlier version stays; nothing is overwritten in place |
| Attach | Button, drag and drop, or paste | The same service in both audiences, so behaviour does not diverge |
| Export | CSV from the data grid | Formulas are neutralised on the way out, so a spreadsheet cannot execute what a record contained |

> **Careful** DOCTYPE and ENTITY declarations and zip bombs are refused at the door. A refused upload is the file service working: those two shapes are how a document attacks the reader that opens it.

## What may be inside a quote

The document is new; the terms in it are not. Every figure has to come from somewhere that existed before the customer asked, which in practice means one of three places.

1. **Knowledge** — a rate, a list, a turnaround or a warranty statement your workspace supplied. Quoting it is grounded, and the source is checkable.
2. **A decision a person made** — typically one that came back through Needs You. It is a term because somebody with the authority made it one.
3. **The deal record** — the value already agreed and stored in minor units, formatted for reading at the edge rather than recalculated.

A figure with none of those behind it is refused, exactly as it would be in a reply. Wrapping an invented number in a document does not make it sourced — it makes it harder to notice, which is the more dangerous failure. See [what Connect may say about price and terms](/docs/sales/safe-sales/).

## Versions, provenance and audit

**Every change is a new version** — Modifying a file writes a new version rather than editing the old bytes, so the document you sent last week is still the document you sent last week.
**Provenance travels with it** — Each version records what produced it and from what, which is what makes a document defensible weeks later.
**The audit trail is separate** — `audit.py` holds who asked, under which rule, and what happened — independent of the file store, so a deleted file does not erase the decision.
**The deal keeps the link** — The document is attached to the work it belongs to, so it is reachable from the opportunity and the relationship rather than only from a folder.

> **Note** There is no version history hiding inside the document format. The history is the file service's, which is why exporting a DOCX and re-uploading it starts a new lineage rather than continuing the old one.

## Sending one

1. Produce or attach the document against the deal.
   - Result: It is stored, versioned and visible to anyone in the workspace who can see the deal.
2. Check the figures against their sources before anything leaves.
   - Result: A grounded figure can still be the wrong figure for this customer — grounding is about provenance, not about judgement.
3. Send it on the channel the conversation is on, under that channel's autonomy rules.
   - Result: In `ask_before_send` the message and its attachment wait in Needs You; the attachment does not bypass the approval the message needs.
4. Record what was sent against the deal.
   - Result: The next person to open the opportunity sees which version the customer holds, which is the question that always gets asked.

## Questions

### Is there a quote builder with templates and numbering?

Not as a separate object. A quote is a document produced through the file service and attached to the deal; its versions and provenance come from there. If you need a fixed layout, keep the template as a file and modify it, which preserves the lineage.

### Can Connect fill in a price the customer negotiated on a call?

Only once that figure is a decision somebody made — typically through the escalation queue. A number heard in a conversation is not yet a term, and the document will not treat it as one.

### Where do attachments a customer sends end up?

In the same file service, scoped to your workspace, readable by the Assistant's file tools. Nothing crosses a workspace boundary — the store is under row-level security like every other scoped table.

## Related

- [Price, SLA and warranty: what Connect may say](https://connectbyjbrh.com/docs/sales/safe-sales/)
- [Opportunities: the deal record](https://connectbyjbrh.com/docs/sales/opportunities/)
- [Files and data in Connect](https://connectbyjbrh.com/docs/files-data/)
- [One file service for two audiences](https://connectbyjbrh.com/research/files-through-one-service/)
- [Escalating a commercial decision](https://connectbyjbrh.com/docs/sales/commercial-escalation/)
- [Knowledge in Connect](https://connectbyjbrh.com/docs/knowledge/)

## What this page is based on

- docs-source/sources/GENERAL.md §9 — files, formats, versions and the data grid
- docs-source/sources/CHANNELS.md §6 — safe_sales and stored deal values
- Connect capability registry (docs-source/facts.py) — file_workspace, file_versions
