|
|
|
@ -90,20 +90,52 @@ button (real puppeteer render) for the rare must-be-one-page quote. The ~5-line
|
|
|
|
print media" comment), not injected client-side, so the paper itself is template-owned;
|
|
|
|
print media" comment), not injected client-side, so the paper itself is template-owned;
|
|
|
|
only preview *chrome* (guides, pulses, tags) is client overlay.
|
|
|
|
only preview *chrome* (guides, pulses, tags) is client overlay.
|
|
|
|
|
|
|
|
|
|
|
|
## 4. Three cheap sibling surfaces (same round)
|
|
|
|
## 4. Editable template data (founder addition, 2026-07-13)
|
|
|
|
|
|
|
|
|
|
|
|
All reuse the one preview route/mechanism — each is S effort:
|
|
|
|
**All the text the letterhead prints must be DB-editable from a page — one fixed
|
|
|
|
1. **Company profile editor** — live letterhead (header, GSTIN, bank box, signatory)
|
|
|
|
(well-designed) layout for now, not a visual layout editor** (that is the store
|
|
|
|
rendered from a hardcoded sample doc as the owner edits `company.*`. Errors here
|
|
|
|
product's "Print Templates" surface, doc 09, out of scope). GST split logic
|
|
|
|
corrupt *every* document, so seeing it matters.
|
|
|
|
(CGST/SGST vs IGST) is already derived from `company.state_code` vs the client state and
|
|
|
|
2. **Module quote-content editor** (Modules page) — live render of how the "what's
|
|
|
|
stays automatic; this is about the *displayed* data and boilerplate text.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Model:** everything is a setting row (the existing `setting` table + `getSetting`/
|
|
|
|
|
|
|
|
`setSetting`), so a change is a DB write that the next render (and the live preview)
|
|
|
|
|
|
|
|
reflects immediately — no release. Existing `company.*` (name, address, gstin,
|
|
|
|
|
|
|
|
state_code, phone, email, bank) already work; **add** these keys:
|
|
|
|
|
|
|
|
- `template.terms` (multi-line terms & conditions)
|
|
|
|
|
|
|
|
- `template.declaration` (GST declaration line, e.g. "We declare that this invoice shows
|
|
|
|
|
|
|
|
the actual price of the goods/services described and that all particulars are true.")
|
|
|
|
|
|
|
|
- `template.jurisdiction` (e.g. "Subject to <city> jurisdiction")
|
|
|
|
|
|
|
|
- `template.footer_note` (thank-you / support line)
|
|
|
|
|
|
|
|
- `template.signatory_label` (e.g. "For <Company> — Authorised Signatory")
|
|
|
|
|
|
|
|
- `template.logo` (image as a data: URI stored in the setting — no file store needed;
|
|
|
|
|
|
|
|
size-capped on upload)
|
|
|
|
|
|
|
|
- `template.title_<doctype>` (optional per-type title override; falls back to the
|
|
|
|
|
|
|
|
built-in TAX INVOICE / QUOTATION / PROFORMA INVOICE / CREDIT NOTE / RECEIPT)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`templates.ts` renders these where it currently hardcodes/omits them. All are optional —
|
|
|
|
|
|
|
|
absent keys render the sensible built-in default, so nothing breaks pre-configuration.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Edit surface:** a **Document Template** page in hq-web (owner-gated, audited), grouping
|
|
|
|
|
|
|
|
the company block + the new `template.*` fields, with the **live letterhead preview beside
|
|
|
|
|
|
|
|
the form** (same preview mechanism as the composer, sample doc) so every edit is seen on
|
|
|
|
|
|
|
|
the page as it prints. This supersedes the smaller "company profile editor preview" idea
|
|
|
|
|
|
|
|
below — the Company Profile page's letterhead fields fold into this one Document Template
|
|
|
|
|
|
|
|
page. Routes: extend `GET/PUT /api/settings/company` to a `GET/PUT /api/settings/template`
|
|
|
|
|
|
|
|
covering both groups (owner-gated, each field audited via `setSetting`), plus a small
|
|
|
|
|
|
|
|
`POST /api/settings/template/logo` that validates + stores the data URI.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 5. Two more cheap sibling surfaces (same round)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Both reuse the one preview route/mechanism — each is S effort:
|
|
|
|
|
|
|
|
1. **Module quote-content editor** (Modules page) — live render of how the "what's
|
|
|
|
included" bullets actually print (the 10px grey `ul.line-content`), using a one-line
|
|
|
|
included" bullets actually print (the 10px grey `ul.line-content`), using a one-line
|
|
|
|
sample doc. Today they're written blind.
|
|
|
|
sample doc. Today they're written blind.
|
|
|
|
3. **Reminder email preview** (manual queue / send) — the exact outgoing email (subject +
|
|
|
|
2. **Reminder email preview** (manual queue / send) — the exact outgoing email (subject +
|
|
|
|
body from the pure `reminderEmail(kind, ctx)`), via `GET /api/reminders/:id/preview`.
|
|
|
|
body from the pure `reminderEmail(kind, ctx)`), via `GET /api/reminders/:id/preview`.
|
|
|
|
Staff currently fire client-facing dunning mail unseen.
|
|
|
|
Staff currently fire client-facing dunning mail unseen.
|
|
|
|
|
|
|
|
|
|
|
|
## 5. Deliberately NOT this round
|
|
|
|
## 6. Deliberately NOT this round
|
|
|
|
|
|
|
|
|
|
|
|
Credit-note & receipt preview (mechanically derived, low value now); **store-product
|
|
|
|
Credit-note & receipt preview (mechanically derived, low value now); **store-product
|
|
|
|
surfaces** — documented as handoff to that workstream, not built here: Print Templates
|
|
|
|
surfaces** — documented as handoff to that workstream, not built here: Print Templates
|
|
|
|
@ -112,7 +144,7 @@ Price-list bulk revise, Schemes editor, WhatsApp/message-catalog text, and the *
|
|
|
|
printer-settings receipt preview** (high value — `packages/printing` already renders
|
|
|
|
printer-settings receipt preview** (high value — `packages/printing` already renders
|
|
|
|
42/32-col receipts as pure functions, so it's cheap when that team wants it).
|
|
|
|
42/32-col receipts as pure functions, so it's cheap when that team wants it).
|
|
|
|
|
|
|
|
|
|
|
|
## 6. Files
|
|
|
|
## 7. Files
|
|
|
|
|
|
|
|
|
|
|
|
- `apps/hq/src/repos-documents.ts` — extract `prepareDraft`; `createDraft` calls it.
|
|
|
|
- `apps/hq/src/repos-documents.ts` — extract `prepareDraft`; `createDraft` calls it.
|
|
|
|
- `apps/hq/src/api.ts` — `POST /api/documents/preview`, `GET /api/reminders/:id/preview`.
|
|
|
|
- `apps/hq/src/api.ts` — `POST /api/documents/preview`, `GET /api/reminders/:id/preview`.
|
|
|
|
@ -122,12 +154,15 @@ printer-settings receipt preview** (high value — `packages/printing` already r
|
|
|
|
- `apps/hq-web/src/components/LivePreview.tsx` — new: debounced fetch + double-buffer
|
|
|
|
- `apps/hq-web/src/components/LivePreview.tsx` — new: debounced fetch + double-buffer
|
|
|
|
iframe (kept modest per YAGNI — a composer helper, generalized only if a 2nd/3rd
|
|
|
|
iframe (kept modest per YAGNI — a composer helper, generalized only if a 2nd/3rd
|
|
|
|
surface proves the shape).
|
|
|
|
surface proves the shape).
|
|
|
|
- `apps/hq-web/src/pages/CompanyProfile.tsx`, `Modules.tsx`, dashboard reminder queue —
|
|
|
|
- `apps/hq-web/src/pages/DocumentTemplate.tsx` — new owner-gated page: company block +
|
|
|
|
wire the sibling previews.
|
|
|
|
`template.*` fields + logo upload, live letterhead preview beside the form (supersedes
|
|
|
|
|
|
|
|
the CompanyProfile letterhead preview; keep CompanyProfile or fold it in).
|
|
|
|
|
|
|
|
- `apps/hq/src/api.ts` — `GET/PUT /api/settings/template`, `POST /api/settings/template/logo`.
|
|
|
|
|
|
|
|
- `apps/hq-web/src/pages/Modules.tsx`, dashboard reminder queue — wire the sibling previews.
|
|
|
|
- Tests: string-identity golden + prepareDraft/createDraft parity + preview-permissive /
|
|
|
|
- Tests: string-identity golden + prepareDraft/createDraft parity + preview-permissive /
|
|
|
|
save-strict divergence + route auth.
|
|
|
|
save-strict divergence + route auth.
|
|
|
|
|
|
|
|
|
|
|
|
## 7. Success criteria
|
|
|
|
## 8. Success criteria
|
|
|
|
|
|
|
|
|
|
|
|
Staff draft a quotation and watch the letterhead build itself in under ~400ms per edit,
|
|
|
|
Staff draft a quotation and watch the letterhead build itself in under ~400ms per edit,
|
|
|
|
with GST (incl. IGST split for out-of-state) always shown by the server; the on-screen
|
|
|
|
with GST (incl. IGST split for out-of-state) always shown by the server; the on-screen
|
|
|
|
|