Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

183 lines
10 KiB
Markdown

# PRD — Invoice Designer Paper Presets and Margins
- Slug: `invoice-designer-paper-presets-and-margins`
- Date: `2026-03-14`
- Status: Draft
## Summary
Add first-class print settings to the invoice template designer so template authors can choose a named paper preset and a configurable uniform page margin, and have the designer canvas, preview surface, and generated PDFs all honor the same settings.
V1 scope is intentionally constrained:
- named paper presets only
- one uniform page margin value in millimeters
- no custom paper sizes
- no per-side margin controls
The implementation should introduce a shared print-settings model and a shared PDF print-options resolver so both current PDF generation paths behave consistently without requiring a full service consolidation in the same change.
## Problem
The invoice template designer currently has no intentional page-setup model.
Instead, page size and printable area are split across unrelated hard-coded implementations:
- the design canvas uses a fixed `816 x 1056` surface, which is US Letter at `96dpi`
- the page node defaults include `40px` padding that acts like a content margin
- the preview shell uses a separate fixed “paper” chrome with different dimensions and padding
- one PDF generation path hard-codes `A4` with explicit `10mm` margins
- another PDF generation path hard-codes `A4` with no explicit margin block
This creates three user-facing failures:
1. template authors cannot intentionally choose a target sheet size
2. PDF output margin behavior is inconsistent and not user-configurable
3. designer, preview, and exported PDF can disagree about what the page actually is
## Goals
- Let template authors choose a named paper preset from the designer UI.
- Let template authors set a uniform page margin value for the template.
- Make the designer artboard reshape immediately when the selected paper preset changes.
- Make the preview shell reflect the same page dimensions and printable inset as the selected settings.
- Make both current PDF generation paths honor the same resolved paper preset and margin settings.
- Preserve compatibility for existing templates without requiring a database migration.
- Keep one authoritative template-level source of truth for print settings.
## Non-goals
- Custom paper sizes in v1.
- Separate top/right/bottom/left margin controls in v1.
- Full multi-page pagination or page-break authoring improvements.
- Full consolidation of the package-level and server-level PDF services in this plan.
- New observability, metrics, rollout flags, or operational tooling beyond normal validation and regression coverage.
## Users and Primary Flows
### Primary users
- Billing admins authoring invoice templates.
- Implementers validating that visual designer output matches exported PDFs.
### Primary flows
1. **Choose a paper preset**
- User opens the invoice template designer.
- User selects `Letter`, `A4`, or `Legal`.
- The artboard, rulers, and visible page chrome reshape immediately.
2. **Adjust page margin**
- User edits the page margin in millimeters.
- The printable area inset updates in the designer and preview.
- Saving the template persists the setting.
3. **Preview with production parity**
- User opens preview for a sample or existing invoice.
- Preview reflects the same sheet size and margin as the design surface.
4. **Generate a PDF**
- User generates or downloads a PDF through any existing invoice PDF flow.
- The generated PDF uses the selected paper preset and margin instead of hard-coded defaults.
5. **Open an older template**
- User opens an existing template that predates explicit print settings.
- The system infers or falls back to sensible resolved settings without breaking load, preview, save, or PDF generation.
## UX / UI Notes
- Print settings must be reachable even though the `page` node is not normally selectable on the canvas.
- V1 should expose page setup in a dedicated, obvious control surface in the designer, such as:
- a document/page settings section in the inspector when no specific child node is selected, or
- a page setup control area in the designer shell/toolbar
- Paper preset control:
- dropdown/select with named presets
- initial preset list for v1: `Letter`, `A4`, `Legal`
- Margin control:
- numeric input in millimeters
- one value applied uniformly to all sides
- live updates while editing, with validation/clamping for obviously invalid values
- The preview paper shell should stop using independent fixed dimensions and instead derive its chrome from resolved print settings.
- The code tab remains generated/read-only; no raw print-settings JSON editor is needed in v1.
## Requirements
### Functional Requirements
- `FR-001` Add a shared invoice print preset registry for at least `Letter`, `A4`, and `Legal`.
- `FR-002` Represent template print settings as first-class invoice template AST metadata, including paper preset identity and uniform margin.
- `FR-003` Keep print settings additive and backward-compatible so templates without explicit print metadata still load and render.
- `FR-004` Infer legacy/resolved print settings from existing page/document width, height, and padding when explicit metadata is absent and known preset dimensions are detected.
- `FR-005` Preserve print settings through designer workspace import/export, save, reopen, and preview flows.
- `FR-006` Add a designer store action that applies print settings by synchronizing runtime geometry and authored style/layout state for the hidden document/page nodes.
- `FR-007` Initialize new designer workspaces with default print settings and matching document/page geometry.
- `FR-008` Add reachable UI controls for selecting a named paper preset in the visual designer.
- `FR-009` Add reachable UI controls for editing a uniform margin value in millimeters.
- `FR-010` Validate paper preset and margin input so invalid settings are rejected or corrected before they produce broken layout/PDF output.
- `FR-011` Update the design canvas, artboard bounds, and rulers to derive dimensions from resolved print settings instead of fixed constants alone.
- `FR-012` Update the preview paper shell to derive visible sheet dimensions and printable inset from resolved print settings instead of hard-coded CSS dimensions and padding.
- `FR-013` Ensure authoritative preview export/render uses the resolved page size and margin so preview content matches the configured print settings.
- `FR-014` Introduce a shared resolver that converts template print settings into Puppeteer PDF options.
- `FR-015` Wire the server-side invoice PDF generation service to the shared print-settings resolver instead of hard-coded `A4`/margin defaults.
- `FR-016` Wire the package-level billing PDF generation service to the same shared print-settings resolver instead of hard-coded `A4` defaults.
- `FR-017` Ensure both current PDF generation paths produce the same paper preset and margin behavior for the same template settings.
- `FR-018` Preserve older templates with no explicit print metadata through preview and PDF generation without schema migration or manual repair.
### Non-functional Requirements
- `NFR-001` Mapping from named paper preset -> designer size -> preview shell -> Puppeteer options must be deterministic and centralized.
- `NFR-002` Existing invoice templates must remain loadable and editable without a breaking schema migration.
- `NFR-003` The designer should reshape quickly enough that switching paper presets feels immediate in normal editing flows.
- `NFR-004` Print setting changes must not create parity drift between preview and generated PDFs.
- `NFR-005` V1 should minimize scope by reusing the existing template AST, workspace import/export, preview pipeline, and PDF generation entry points.
## Data / API / Integrations
- Extend invoice template AST metadata to include a print-settings shape, for example:
- `paperPreset`
- `marginMm`
- Keep template-level metadata as the semantic source of truth.
- Continue exporting resolved width/height/padding into the AST layout/styles needed by the current renderer paths so existing HTML/CSS rendering behavior stays compatible.
- Add a shared preset/dimension utility that can:
- map preset -> physical size in mm
- map preset -> editor size in px at `96dpi`
- convert uniform margin mm -> preview/canvas padding representation
- convert resolved settings -> Puppeteer `format` and `margin`
- Update the workspace import/export layer so explicit metadata wins, while legacy width/height/padding can still be interpreted when metadata is absent.
- No new external API endpoints are required for v1.
## Security / Permissions
- No new permission model is introduced.
- Existing invoice template edit permissions continue to govern who can change print settings.
- Existing invoice/PDF read or generate permissions continue to govern who can preview or export invoices.
## Observability
- No new observability scope is included in v1 beyond normal editor validation states and existing error surfacing.
## Rollout / Migration
- No database migration is required.
- Existing templates without explicit print metadata should load through inference or fallback behavior.
- New templates should initialize with explicit print settings so they no longer depend on legacy hard-coded geometry alone.
- This plan does not require immediate consolidation of the two PDF services, but it does require both services to share one print-settings resolution path.
## Open Questions
- None blocking for the v1 plan. The selected scope is:
- named presets only
- uniform margin only
- no custom sizes
## Acceptance Criteria (Definition of Done)
- A template author can choose a named paper preset in the invoice designer.
- A template author can set a uniform page margin in millimeters.
- Changing the selected preset reshapes the designer canvas to the matching page size.
- Preview reflects the same page size and printable inset as the selected settings.
- Both current PDF generation paths honor the same selected preset and margin instead of hard-coded defaults.
- Existing templates without explicit print settings still load, preview, save, and export successfully.
- Saving and reopening a template preserves the configured paper preset and margin.
- Automated coverage exists for schema/import-export behavior, canvas reshape behavior, preview shell behavior, and both PDF paths.