docs(architecture): record Phase 4.5 builder polish
CI and Deploy / test (push) Failing after 2m4s
CI and Deploy / deploy (push) Has been skipped

cv-builder.md (outline-driven Content tab, DnD, rich text, preview page nav,
public-CV routing fix + deployment note), cv-theme-engine.md (rich text/ATS/
print), roadmap Phase 4.5 shipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
cesnimda
2026-07-18 14:48:33 +02:00
parent 582c4e07e9
commit 074c78a7ef
3 changed files with 51 additions and 15 deletions
+27 -12
View File
@@ -60,9 +60,19 @@ tenant filter — there is no current user). Unknown/private slug → 404
`/career/builder` lists variants (`CvBuilderPage`); the editor (`CvBuilderEditor`) is three tabs —
**Content**, **Customize**, **AI Tools** (plus **History**) — beside an always-on live preview that
re-renders through `POST /api/cv/preview` on a 350 ms debounce. Edits autosave on an 800 ms debounce
(`source: autosave`), appending a version each save. `/cv/:slug` (`PublicCvPage`) renders a public CV
in a sandboxed iframe.
re-renders through `POST /api/cv/preview` on a 300 ms debounce. Edits autosave on an 800 ms debounce
(`source: autosave`), appending a version each save; the header shows Unsaved / Saving / Saved.
`/cv/:slug` (`PublicCvPage`) renders a public CV in a sandboxed iframe.
**Content tab** reads `GET /api/cv/outline` (the master profile as sections+entries with ItemKeys).
Sections and entries reorder by native drag-and-drop (`useDragReorder`, no dependency) or arrow
buttons (the keyboard-accessible path); entry order is stored per section as `ItemOrder` on the
variant, never on the profile. Each entry exposes hide, title/subtitle override, and rich-text bullet
editing (`RichTextField` — a markdown toolbar over a textarea; storage stays plain text, the server
renderer converts the `**bold** *italic* __underline__ [text](url)` whitelist to safe HTML).
**Preview** has zoom presets (±, slider, Fit), a measured page count with prev/next page navigation
and dashed page-break indicators, and an "updating…" chip. **Customize** badges ATS-friendly themes.
## AI
@@ -75,14 +85,19 @@ carries "preserve every factual claim — never invent" (MASTER_IMPLEMENTATION_G
- **New theme**: append a `CvTheme` to the catalog (`cv-theme-engine.md`). No renderer change.
- **New section kind**: add a builder in `CvVariantResolver` + a `Kind` branch in `ThemedCvRenderer`.
- **DOCX export**: add an `IDocxExporter` consuming the same `CvRenderModel`; the model is format-neutral.
- **Rich text / page numbers**: see `cv-theme-engine.md` "Deliberately not here (yet)".
- **PDF page numbers**: `ShowPageNumbers` is carried but the footer is a Playwright `footerTemplate`
concern, not CSS — see `cv-theme-engine.md`.
## Known limitation
## Deployment — public CV routing (fixed 2026-07-18)
Direct external loads of any deep link (including `/cv/{slug}`) currently bounce to the app root — the
CSR lift-and-shift Next.js static-export setup only prerenders `/`, so a hard navigation to a deep path
doesn't reach the react-router route (in-app client navigation works). This affects the whole SPA, not
just public CVs, but public CVs are the first feature that depends on external direct links working.
Fix path: serve `index.html` for all non-`/api` paths so react-router owns routing (nginx already has
`try_files $uri /index.html`; the redirect is client-side in the Next shell). Tracked as a follow-up —
see `docs/architecture/frontend.md` / the Next.js migration note.
`/cv/{slug}` (and every deep link) must work on direct navigation, refresh, and shared links. The app
is a React Router SPA behind Next.js `output: export`, which previously prerendered only `/`, so a hard
load of any deep path hit Next's client not-found before React Router could route it.
**Fix:** the single `app/page.tsx` is now an optional catch-all `app/[[...slug]]/` (a server
`page.tsx` exporting `generateStaticParams` + a `"use client"` `ClientShell`, because
`generateStaticParams` can't live in a client file). The catch-all matches every client path, so React
Router owns routing on any hard load. Build still emits just `index.html`; nginx serves it for all
unknown paths via `try_files $uri /index.html` (unchanged). **No infra/nginx change was required**
the fix is entirely in the frontend build. Verified live: `/login` and `/cv/{slug}` both resolve on
direct navigation.