diff --git a/docs/superpowers/specs/2026-07-13-quotation-polish-share.md b/docs/superpowers/specs/2026-07-13-quotation-polish-share.md new file mode 100644 index 0000000..947a20b --- /dev/null +++ b/docs/superpowers/specs/2026-07-13-quotation-polish-share.md @@ -0,0 +1,93 @@ +# Quotation Polish + Share/Download — Design + +**Status:** approved in principle (founder, 2026-07-13). Sequenced to run **after** the +live-preview build (wf live-preview) lands, so it builds on the finished `templates.ts` +rendering + the live preview (every visual change is seen instantly) and never edits the +template file concurrently with that build. + +Two threads: (A) make the document **look beautiful**, (B) **share & download** options. + +## A. Beautiful document (templates.ts `documentHtml`) + +Restyle the one shared letterhead template — this automatically improves the PDF, the +composer live preview, and the Document Template page (one renderer). A print-quality, +professional Indian GST document, not a generic table. Direction (finalised with the +frontend-design skill at build time): + +- **Typography:** a clear type hierarchy — company name prominent, a refined document + title block (TAX INVOICE / QUOTATION), tabular-figure alignment for all money columns + so rupee amounts line up to the paisa. Keep the bundled Segoe/Inter-class stack (renders + identically on the office desktops and the Windows server — no web-font fetch in print). +- **Layout:** a proper letterhead band (logo left via `template.logo`, company block + + GSTIN right), a clean bill-to / ship-to and document-meta row, a well-spaced line table + with subtle row rules (not heavy borders), a totals block visually anchored bottom-right + with the grand total emphasised, amount-in-words, then terms / declaration / jurisdiction + / signatory / footer from the `template.*` fields. +- **Accent:** one restrained accent colour for rules/headers, sourced from a new optional + `template.accent` setting (defaults to a professional slate/indigo) so it's brandable + from the Document Template page later — no hard-coded brand colour. +- **Print discipline:** A4, 14mm margins, avoid row-splitting across page breaks + (`break-inside: avoid` on rows), repeat the table header on page 2+. All screen/print + parity rules from the live-preview design still hold (one renderer, golden test guards). +- **Fidelity:** the existing string-identity golden test continues to guarantee the + beautified preview === the beautified PDF. + +## B. Share & download (all three channels + download) + +On **DocumentView** (and optionally right after composing), an action group: + +1. **Download PDF** — button hitting the existing `GET /api/documents/:id/pdf`, served + with `Content-Disposition: attachment; filename="QT-26-27-0001.pdf"` (doc-no slugged, + `/` → `-`). Trivial; no new endpoint. +2. **Shareable view link** (the load-bearing one — needs a secure public route): + - New table `document_share (id, document_id, token, created_by, created_at, + expires_at NULL, revoked INTEGER DEFAULT 0)` via `CREATE TABLE IF NOT EXISTS`. + - `POST /api/documents/:id/share` (requireAuth) → mints a **cryptographically random** + token (≥32 bytes, `randomBytes`), default `expires_at` = +30 days (configurable), + returns the public URL. Audited. + - **Public** `GET /share/:token` (NO auth, the ONLY unauthenticated read route) → + validates token exists, not revoked, not expired; renders **only that one + document's** PDF (reuse renderPdf) or an HTML view. Serves nothing else — no listing, + no client record, no API. Unknown/expired/revoked → a plain "link expired" page. + - `POST /api/documents/:id/share/:shareId/revoke` (requireAuth, audited) → sets + `revoked=1`. A document's shares are listed on DocumentView so the owner can revoke. + - **Security stance (documented, accepted):** anyone holding the link sees that one + document's contents (client name + amounts) — the intended trade-off of any share + link, mitigated by an unguessable token, optional expiry, and one-click revoke. + Rate-limit `/share/:token` lookups to blunt token brute-forcing. No document data in + the URL beyond the opaque token. +3. **WhatsApp (click-to-chat)** — a `wa.me/?text=` link opening + WhatsApp with a ready message: greeting + doc type/no + total + **the shareable view + link** (so the client taps through to the actual document — this is why the link and + WhatsApp compose). Needs the client's phone (already on the client record); no WhatsApp + Business API. If no share link exists yet, minting one is offered inline. +4. **Native share sheet** — `navigator.share({ title, text, url: shareLink })` where + supported (mobile), sharing the view link to any app; where the File share is + supported, share the PDF blob directly; desktop/unsupported → falls back to Download. + +## Data / files (build time) + +- `apps/hq/src/db.ts` — `document_share` table (CREATE TABLE IF NOT EXISTS; no migrate). +- `apps/hq/src/repos-shares.ts` — mint/validate/revoke/list shares. +- `apps/hq/src/api.ts` — `POST /documents/:id/share`, `POST …/share/:shareId/revoke`; + `GET /api/documents/:id/pdf` gains the attachment filename. +- `apps/hq/src/server.ts` — public `GET /share/:token` mounted OUTSIDE the `/api` + auth router, rate-limited; renders via renderPdf. +- `apps/hq/src/templates.ts` — the beautification (thread A) + optional + `template.accent`. +- `apps/hq-web/src/pages/DocumentView.tsx` — the action group (Download / Link / WhatsApp + / Share) + the shares list with revoke. +- Tests (TDD, server): token mint is random + unguessable; `/share/:token` serves only + the one doc and 404s on unknown/expired/revoked; revoke works; owner-gate/audit; + download filename; beautify keeps the golden string-identity test green. + +## Not this round + +Real WhatsApp Business API sending (click-to-chat only); SMS; share analytics +(opened/viewed tracking) — a nice later addition on the same `document_share` row. + +## Sequence + +1. Live-preview build (in flight) completes and is verified. +2. Plan this doc (writing-plans) → ultracode build → verify. Beauty pass uses the + frontend-design skill for the concrete visual system.