Skip to content

Bank report wizard: editable HTML preview before export #1900

Description

@steilerDev

As a homeowner about to send a report to my bank, I want to edit the report's wording — the table's descriptive text and the whole cover letter — directly in the preview before exporting so that I can correct or tailor anything the generated text got wrong without leaving the wizard or hand-editing a PDF.

Part of the Bank Report Wizard — Refinement Round 2 mini-epic. Source: direct user verification of the merged wizard. Scope decomposed and approved during mini-epic planning.

Priority: Must Have
Blocked by: #1898 (report table refinements), #1899 (settings step + report language)
Blocks: #1901 (AI generation)

Settled decisions (do not re-litigate): Step 5 is an HTML edit surface with on-demand PDF — there is no live side-by-side PDF pane. "Letterhead" means the full cover letter: sender, recipient, reference, subject, and body blocks are all editable. Amounts and totals stay read-only because they are derived.


Acceptance Criteria

1. Editable report content in Step 5

  • Given I reach Step 5 "Preview & Export", when it renders, then it shows the full report content as editable HTML rather than only a rendered PDF frame.
  • Given the editable report table, when it renders, then it shows one row per included invoice with the report's columns: vendor, invoice number, date, status (only where the report type keeps it, per Bank report: Usage column, attachment notes, deposit footnote & column cleanup #1898), usage text, attachments note, and amounts.
  • Given invoices excluded in Step 3, when the editable table renders, then they are absent from it — the editable content reflects the Step-3 selection and line exclusions exactly.
  • Given the "include cover letter" option is on, when Step 5 renders, then the complete cover letter is shown with separately editable fields for sender, recipient, reference, subject, and body.
  • Given the "include cover letter" option is off, when Step 5 renders, then no cover-letter fields are shown and no cover letter is exported.
  • Given the editable surface, when I use only a keyboard, then every editable field is reachable, has an accessible label, and shows a visible focus indicator; the surface works at desktop, tablet, and mobile viewports.
  • Given the editable surface, when it renders, then it uses design tokens and existing shared components — no hardcoded colours, spacing, radii, or font sizes — and renders correctly in dark mode.

2. What is editable vs. read-only

  • Given any wording/text field in Step 5 (usage text, attachments note, and every cover-letter block), when I click into it, then I can edit it freely.
  • Given any amount cell (per-invoice invoice amount and allocated amount), when I attempt to edit it, then it is read-only — it cannot be typed into, and it is visually and programmatically marked as non-editable.
  • Given any total or subtotal cell, when I attempt to edit it, then it is read-only, and its value continues to be derived from the Step-3 selection and exclusions.
  • Given read-only amounts, when the report is exported, then the exported figures are byte-for-byte the derived values — no user input path can alter a number.

3. Baseline, regeneration, and warning

  • Given I first arrive at Step 5, when the editable content renders, then it is populated from a generated baseline (the same content the report would produce today, in the language chosen in Step 4).
  • Given I have made edits and I go back and change something in Steps 1–4 (report type, source, invoice/line selection, report language, or the export toggles), when I return to Step 5, then the baseline is regenerated and my edits are cleared.
  • Given I have unsaved edits and I attempt a Step 1–4 change that would regenerate the baseline, when I trigger it, then I am shown an explicit confirmation warning that my edits will be lost, and I can cancel to keep them.
  • Given I have made no edits, when I change something in Steps 1–4, then no warning is shown (the warning only appears when there is something to lose).
  • Given I confirm the regeneration, when Step 5 re-renders, then the content matches a freshly generated baseline with no residue of the discarded edits.
  • Given edits are modelled as overrides on a generated baseline, when a field is untouched, then it continues to track the baseline (it is not silently frozen at the first render).

4. On-demand PDF

  • Given Step 5, when it renders, then there is no continuously regenerating background PDF and no live PDF pane — the PDF is produced only on demand.
  • Given Step 5, when I trigger the "Preview PDF" action, then a PDF is generated from the currently edited content and shown to me.
  • Given I have edited content, when I download the report, then the produced PDF reflects every edit I made.
  • Given I have edited content, when I upload to Paperless, then the uploaded PDF reflects every edit I made.
  • Given I have edited content, when I trigger mark claimed, then the PDF generated for that flow reflects every edit I made, and the mark-claimed behaviour itself (including the excluded-lines warning from Bank report wizard follow-up: blob: CSP for preview, status chip sizing, expandable invoice rows & deposit budget source #1891) is unchanged.
  • Given the PDF preview, when it renders, then it displays actual content in the frame — the assertion is that the frame renders, not merely that a blob: URL was assigned (the CSP regression class from Bank report wizard follow-up: blob: CSP for preview, status chip sizing, expandable invoice rows & deposit budget source #1891 must not reappear).
  • Given a PDF generation failure, when it occurs, then the error is surfaced to me clearly and my edited content is preserved.

5. Translations

  • Given every new user-facing string (labels, the regeneration warning, the Preview PDF action, read-only affordances), when it renders, then it comes from t() and resolves in both en and de.
  • Given the wizard chrome vs. report content, when both render, then the chrome follows the UI locale and the report content follows the Step-4 report language (per Bank report wizard: Settings step with report language selection #1899).

Out of scope

Notes

  • Step 5 surface: client/src/pages/ReportWizardPage/, client/src/components/reports/ReportPdfPreview.tsx, ReportInvoiceList.tsx.
  • PDF pipeline: client/src/lib/reportPdf/ — today overviewPdf.ts / coverLetterPdf.ts build content directly from the report response. This story inserts an intermediate, editable content model between the response and the PDF builders; the builders must consume that model so preview and every export path share one source.
  • Derived-amount contract facts still apply: allocatedAmount is negative for lineKind: 'refund-adjustment' (never re-negate), and report.totalAmount is not the grand total once invoices are excluded — the included total comes from merge.ts.
  • Testing: extend realRender.test.ts to assert that an edited baseline reaches the rendered PDF and that excluded rows stay out of the totals. Any "preview renders" assertion must check rendered content, not a src attribute.

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions