Repository navigation
editor-ux: a faster, truthful and accessible invoice editor - #9
Merged
Merged
Conversation
Spec for editor-ux (specify + clarify sweep): - spec.md, .size (M), .route (standard); brief adds U13 (Retry bypasses save flow) and U14 (editor confirmation dialog placement) - CONTEXT.md: new glossary role Contributor - mcp-server §8: Retry open question closed, absorbed as editor-ux U13 Clarify tightened §1 (calendar-day dates), AC-01/NFR (no PDF toolkit on any signed-in page but the editor), new AC-02b (stale tab / generation failure), AC-04 (one totals rule, edit counter), AC-05b, AC-05c (Retry repeats the failed action with the current form), AC-06, AC-07 (bfcache, Visitor), AC-08, AC-11, AC-13/14, AC-15. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es, ADR-0001..0006 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… restore Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gets Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI e2e job for the date matrix and accessibility suites; editor idle warm-up aligned across §4/ADR-0001; strawman options replaced (ADR-0006) or removed (ADR-0004); §5 lists playwright projects, README and package.json changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
loadPdfKit() imports lib/pdf/invoice-pdf-kit once per visit, clears the cache on failure, and classifies a failed import as offline or new-version by probing the origin. @react-pdf/renderer is now imported only by the kit; the old helper and document paths stay as shims until T2 rewires triggers. SDD-Task: T1 SDD-AC: AC-01 SDD-AC: AC-02 SDD-AC: AC-02b Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
usePdfAction loads the toolkit via loadPdfKit on each run and shows preparing / try again / reload states; generation failures go to Sentry with pdf.stage. The editor warms the toolkit when idle. Lint forbids importing @react-pdf/renderer or the kit outside lib/pdf. SDD-Task: T2 SDD-AC: AC-01 SDD-AC: AC-02 SDD-AC: AC-02b Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scripts/check-pdf-chunks.ts fails CI when a non-editor route's initial chunks carry the PDF toolkit. The e2e covers no fetch on open, reuse, offline, a missing chunk and the 20-run p95 (875 ms at 10 Mbit/s). The e2e exposed a misclassification: the origin probe followed the signed-in redirect, so it now uses redirect: 'manual'. SDD-Task: T3 SDD-AC: AC-01 SDD-AC: AC-02 SDD-AC: AC-02b Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… theme toggle Deletes 16 unreachable components/ui files and the packages only they used (embla-carousel-react, input-otp, vaul), replaces uuid with crypto.randomUUID(), and serves the landing page and the app from one components/theme-toggle.tsx. The AC-27 release-gate test now asserts uuid is absent instead of pinned. SDD-Task: T4 SDD-AC: AC-16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l container InvoiceEditorModalContainer now renders the totals ConfirmationModal next to the other editor dialogs, keeping the F-47 onClose. The changed-elsewhere component test renders the container as the route layout does. SDD-Task: T5 SDD-AC: AC-16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README now copies env.example, asks for the Contributor's own empty PostgreSQL and the required settings, says which tests need Docker or a database, and links tests/README.md. Verified verbatim in a fresh clone against a throwaway Postgres; the run log is in _audit/. SDD-Task: T6 SDD-AC: AC-15 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in en-US formatMoney, formatDay (always the UTC calendar day) and formatMoment (the given zone, UTC when null) pass 'en-US' explicitly, so output does not depend on the server or browser locale or time zone. formatCurrency and formatStoredDay now delegate to them. SDD-Task: T7 SDD-AC: AC-08 SDD-AC: AC-09 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Editor totals, line totals, the paid badge, member-since, custom-price dates, assistant keys, debtor and sender-account figures now use formatMoney / formatMoment / formatNumber / formatPercent. A no-restricted-syntax rule rejects toFixed and toLocale*String in components/ and app/ (pdf-preview-document is ignored until T10). SDD-Task: T8 SDD-AC: AC-08 SDD-AC: AC-09 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r T90-T91 (two runs, 115 passed, 1 skipped, raw Playwright lines) and point the test plan at it SDD-Task: T92 SDD-AC: AC-14 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… T93–T94 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vider test checks and name the tests for the days, the default sender and bank, and hydration SDD-Task: T93 SDD-AC: AC-06 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Cancel, and make the totals-cancel row say the notes edit stays in the form SDD-Task: T94 SDD-AC: AC-05d Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… T95–T96 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…essed while a save is running SDD-Task: T95 SDD-AC: AC-05d Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…try-through-save-command test SDD-Task: T96 SDD-AC: AC-05d Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… T97–T100 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…edited states and a saved form shows the stored figures SDD-Task: T97 SDD-AC: AC-04 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…preparing state, like Download SDD-Task: T98 SDD-AC: AC-01 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…for every text and amount field Covers Invoice Number, PO Number, line Price and Quantity, Discount, Shipping, Tax, Notes, Payment Terms and Terms. Mutation check: removing data-field fails Discount, Shipping and Tax; the other fields fall back to a unique placeholder or aria-label, and fail once that stable name is removed too. SDD-Task: T99 SDD-AC: AC-03 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…delity and assert it matches the PDF SDD-Task: T100 SDD-AC: AC-10 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… T101–T103 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…for the custom line's Product name The T99 fixture's line is custom, so its free-text Product name is on screen and is found again only through the aria-label/placeholder fallback. Mutation check: dropping aria-label and placeholder from NAMING_ATTRS fails on "product name". SDD-Task: T101 SDD-AC: AC-03 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…instead of a layout scan SDD-Task: T102 SDD-AC: AC-10 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s) and point the NFR line at it E2E_TIMING=1 run of pdf-on-demand.spec.ts "first PDF timing" against the production build at e19054e: 20 runs at 10 Mbit/s, p95 1107 ms within the 3 s limit. SDD-Task: T103 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1, O2 only); N3 deferred to PR CI Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ally before ship Owner decision at editor-ux ship: CI keeps unit, integration, lint, tsc, audit, next build and the PDF chunk check. The full `CI=1 pnpm test:e2e` runs locally before each ship. Spec §6 NFR measurements, the SAD, the test plan, the test READMEs and the ship notes now say so; test:e2e:ci is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The integration and e2e helpers mount /var/lib/postgresql/data as tmpfs, so a test database never writes to disk and no anonymous volume is left behind, even when a run is killed before stop(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The real-iPhone keypad check (T25) and the owner review of the Linux layout baselines (T53) are waived by the owner on 2026-10-11. Tracker gains a `skipped` state; spec §8, the test plan and the ship notes say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Editor UX — feature description
Source:
docs/features/editor-ux/_ship/feature.md1. Purpose
The Freelancer uses the invoice editor and the invoice lists each day. A person who examines the product also sees them first. This feature makes them fast, correct and accessible before the public release.
This feature does not change a business rule. The rules of
invoice-integritystay the same. The feature changes only how the app loads, shows and announces the data.2. Terms
3. Rules
3.1 PDF toolkit
Only Download and Print load the PDF toolkit. The dashboard, the lists, the Customer pages and the sender profile pages do not load it.
The app loads the PDF toolkit one time in each visit. After that, Download and Print use the loaded toolkit.
The preview does not use the PDF toolkit.
The editor can load the PDF toolkit after it opens. Thus, Download and Print in the editor seldom wait.
3.2 PDF errors
If the connection stops, the app shows the message "the PDF could not be prepared". The message has a Try again button.
If a new version of the app was released after the page opened, the app shows the message "a newer version is available". The message has a Reload button.
If the PDF fails during its generation, the app shows the "could not be prepared" message. The app also sends an error report to the team.
In all of these cases, the page stays usable. Nothing else on the page changes.
3.3 Save
You can continue to type while the app saves the invoice.
A change that you make during a save is never lost. The app does not mark this change as saved. The next Save stores it.
The totals on the screen always agree with the lines on the screen. The app calculates them with the same rule as the stored totals.
If you click Save and issue and change a line during the save, the invoice becomes issued with its old lines. A warning tells you that the app did not save your change. You can close the warning.
3.4 Retry
If a save fails, the message has a Retry button.
Retry does the same action as the action that failed (Save, or Save and issue). It uses the form as it is when you click Retry.
Retry gives the same result as Save:
3.5 First display
The editor shows the correct invoice on the first display. The data does not change when the page becomes interactive.
A new invoice shows its default values on the first display:
The invoice number can show after the first display. Until then, the field shows that it is loading. The layout does not move when the number shows.
3.6 Shared browser
The app does not keep signed-in pages in the browser cache.
If the browser shows a signed-in page again from its back/forward cache, the app hides the page and reloads it.
Thus, after Freelancer A signs out, a Visitor or Freelancer B cannot see the invoices of Freelancer A. This rule also applies when they click Back or Forward.
3.7 Dates
Each place shows the issue date and the due date as the calendar day that the invoice stores. The time zone of the Freelancer and the time zone of the browser do not change this day.
The creation date of a custom price shows in the Freelancer time zone.
3.8 Money
Each place shows money in one format: for example, "$1,234.50" and "UAH 1,234.50". The language of the device does not change this format.
The preview and the PDF use the same document model. Thus, they always show the same words, dates and amounts.
3.9 Amount fields
The price, quantity, discount, tax rate and shipping fields open a numeric keypad.
These fields accept only a point "." as the decimal separator. If you type or paste a comma, the field does not accept it. A note next to the field tells you to use a point.
4. What the Freelancer sees
The Contributor sees these changes:
5. Release procedure
unitandintegrationjobs of this pull request are green.6. Rollback procedure
7. Checks after the release
8. Related documents
spec.mdsad.mdadr/data-model.mdtest-plan.mdchangelog.mdSummary
The invoice editor and the lists around it are now fast, truthful and accessible, and the repository works as written. Signed-in list pages no longer load the PDF toolkit, a change typed during a save is never lost, Retry behaves exactly like Save, the editor draws the right invoice from the server's first HTML, dates and money look the same everywhere, and the editor works with a screen reader and on a phone. No business rule changes: every
invoice-integrityacceptance test still passes. See the spec and the changelog.Acceptance criteria
Design
docs/features/editor-ux/spec.mddocs/features/editor-ux/sad.mddocs/features/editor-ux/adr/(ADR-0001 … ADR-0007)docs/features/editor-ux/data-model.md(no schema change, no migration)ux-flows.md; test plan:test-plan.md_review/review-2026-10-11-r18.md(CHANGES REQUESTED only for owner actions O1, O2; no code change requested)Tasks (SDD-Task trailers)
T1–T105, 153 commits.
git log main..feature/editor-ux --grep SDD-Task:All 105 tasks
Verification
All runs on
dff223d, macOS, Node 22, Docker up.vitest211 files, 2016/2016 passedtsc --noEmitclean;eslint0 errors, 4 warnings (none new)pnpm audit --prod --audit-level=high— no high or critical advisory (2 low, 3 moderate)pnpm check:pdf-chunks— "30 routes checked, no toolkit leak"CI=1 pnpm test:e2ebuilt and started the real production app against a throwaway Postgres and drove it in Chromium and WebKit. 113 passed, 3 skipped. Observed:uk-UAandde-DE, the editor, preview, PDF and Debtors showed "$1,234.50" and "UAH 1,234.50".47969a0, T103).Operational notes
CI=1 pnpm test:e2elocally before each ship.🤖 Generated with Claude Code