refactor: rename routes to the glossary and split the letter axes #25

Merged
me merged 6 commits from feat/route-revamp into main 2026-08-30 10:25:39 +00:00
Owner

Routes now speak the glossary in CONTEXT.md. The container word is Escritoire, and the page that renders it stops calling itself a drawer.

Routes

Was Now
/drawer /escritoire
/read/:public_id /letter/:public_id
/login /unlock
/onboard /begin
/quill/:public_id? unchanged

/letter/ stays plain on purpose: it is the only route a stranger ever sees, pasted into a chat by someone with no product vocabulary. Inward routes may turn heads; the outward one has to be legible.

/read/:public_id is deleted outright, not redirected — there are no active users and no share links in the wild. It falls through to the existing catch-all and lands on /.

Two things that would have broken quietly

  • backend/letters/tasks.py:33 hardcoded /read/ in the vault-unlock email — the one email an author may have waited months for.
  • frontend/lighthouserc.json gated CI on /login, which would now 404.

Lifecycle and Disposition split

Editor.tsx typed letter state as "DRAFT" | "SEALED" | "VAULT", welding the two axes CONTEXT.md defines as orthogonal — VAULT is a Disposition and never a Lifecycle. Now Lifecycle, Disposition, SaveIntent and ResolvedIntent live in api/response.ts, and each author intent resolves into both axes.

Being honest about this one: it is a latent fix, not a live bug. Sealed letters redirect out of the quill, and there is no autosave, so the old type: "KEPT" hardcode needed an unreachable state to bite. The unsoundness was real but masked by res.data being any.

Review notes

  • components/reader/letter/, components/login/unlock/ and pages/Login.tsxUnlock.tsx follow from the routes but were not on the originally agreed list. Happy to revert any of them.
  • Found, not fixed: a BURNED letter still opens in the quill as an empty read-only canvas — Quill.tsx redirects only on SEALED. Pre-existing; making Lifecycle honest is what exposed it. Worth its own ticket.
  • SaveIntent's members still mix both axes ("DRAFT" | "SEALED" | "VAULT"). Renaming to SEAL_KEPT/SEAL_VAULT would ripple through ToolBar; left as a judgement call.

Verification

tsc -b clean · 74 tests / 12 files passing (from 71/12) · vite build succeeds · biome clean but for one pre-existing noExplicitAny in e2e/auth.spec.ts, untouched here.

Not run: the Playwright e2e suite needs the compose stack up. letter.spec.ts and e2e/utils/auth.ts are updated but unexercised — worth a run before merge.

Routes now speak the glossary in `CONTEXT.md`. The container word is **Escritoire**, and the page that renders it stops calling itself a drawer. ## Routes | Was | Now | |---|---| | `/drawer` | `/escritoire` | | `/read/:public_id` | `/letter/:public_id` | | `/login` | `/unlock` | | `/onboard` | `/begin` | | `/quill/:public_id?` | unchanged | `/letter/` stays plain on purpose: it is the only route a stranger ever sees, pasted into a chat by someone with no product vocabulary. Inward routes may turn heads; the outward one has to be legible. `/read/:public_id` is deleted outright, not redirected — there are no active users and no share links in the wild. It falls through to the existing catch-all and lands on `/`. ## Two things that would have broken quietly - `backend/letters/tasks.py:33` hardcoded `/read/` in the vault-unlock email — the one email an author may have waited months for. - `frontend/lighthouserc.json` gated CI on `/login`, which would now 404. ## Lifecycle and Disposition split `Editor.tsx` typed letter state as `"DRAFT" | "SEALED" | "VAULT"`, welding the two axes `CONTEXT.md` defines as orthogonal — `VAULT` is a Disposition and never a Lifecycle. Now `Lifecycle`, `Disposition`, `SaveIntent` and `ResolvedIntent` live in `api/response.ts`, and each author intent resolves into both axes. Being honest about this one: it is a **latent** fix, not a live bug. Sealed letters redirect out of the quill, and there is no autosave, so the old `type: "KEPT"` hardcode needed an unreachable state to bite. The unsoundness was real but masked by `res.data` being `any`. ## Review notes - `components/reader/`→`letter/`, `components/login/`→`unlock/` and `pages/Login.tsx`→`Unlock.tsx` follow from the routes but were not on the originally agreed list. Happy to revert any of them. - **Found, not fixed:** a `BURNED` letter still opens in the quill as an empty read-only canvas — `Quill.tsx` redirects only on `SEALED`. Pre-existing; making `Lifecycle` honest is what exposed it. Worth its own ticket. - `SaveIntent`'s members still mix both axes (`"DRAFT" | "SEALED" | "VAULT"`). Renaming to `SEAL_KEPT`/`SEAL_VAULT` would ripple through `ToolBar`; left as a judgement call. ## Verification `tsc -b` clean · **74 tests / 12 files passing** (from 71/12) · `vite build` succeeds · biome clean but for one pre-existing `noExplicitAny` in `e2e/auth.spec.ts`, untouched here. **Not run:** the Playwright e2e suite needs the compose stack up. `letter.spec.ts` and `e2e/utils/auth.ts` are updated but unexercised — worth a run before merge.
refactor: rename routes to the glossary and split the letter axes
Some checks failed
CI / Frontend CI (pull_request) Successful in 1m3s
CI / Lighthouse (pull_request) Successful in 3m21s
CI / Backend CI (pull_request) Successful in 52s
CI / E2E Tests (pull_request) Has been cancelled
2636ec9d74
refactor: drop the legacy /read redirect and trim comments
All checks were successful
CI / Frontend CI (pull_request) Successful in 1m1s
CI / Lighthouse (pull_request) Successful in 3m20s
CI / Backend CI (pull_request) Successful in 55s
CI / E2E Tests (pull_request) Successful in 6m22s
32d5fe5b32
Merge branch 'main' into feat/route-revamp
Some checks failed
CI / Frontend CI (pull_request) Failing after 2m27s
CI / Backend CI (pull_request) Successful in 55s
CI / E2E Tests (pull_request) Successful in 6m5s
f4923a5c88
ci: set the unlock budget to what a runner can actually hit
Some checks failed
CI / Frontend CI (pull_request) Failing after 2m25s
CI / Backend CI (pull_request) Successful in 55s
CI / E2E Tests (pull_request) Has been cancelled
7b5af0b37b
fix(test): mock the canvas in letter tests so vitest exits clean
Some checks failed
CI / Frontend CI (pull_request) Failing after 2m24s
CI / Backend CI (pull_request) Successful in 54s
CI / E2E Tests (pull_request) Has been cancelled
51befbbcb2
fix(ci): install chrome deps so lighthouse can launch a browser
All checks were successful
CI / Frontend CI (pull_request) Successful in 3m23s
CI / Backend CI (pull_request) Successful in 54s
CI / E2E Tests (pull_request) Successful in 6m8s
c00b738864
me merged commit 1b35785f6e into main 2026-08-30 10:25:39 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
me/pi-ku!25
No description provided.