Editor
The editor module is the editor-facing surface of the platform — the interface a newsroom editor would actually use to tune the recommender’s behaviour. It is deliberately ordinary: server-rendered HTML with HTMX for partial-page updates, no SPA framework, no JavaScript build pipeline for its UI layer.
The shape decisions are recorded in two ADRs:
- ADR-0005: TypeScript + Express, swappable by design — the swap is the architectural argument, not the editor itself.
- ADR-0011: SSR + HTMX, no SPA. The aesthetic should match real CMS admin panels, not flashy demos.
The whole TypeScript half of the tutorial lives under
editor/.
The runnable rep
Section titled “The runnable rep”Rep #9 is the only rep in TypeScript, and it makes the editor’s defining property concrete: the editor renders, the platform ranks.
make -C editor run # render the recommendation-preview surface to HTML (no server)make -C editor check # the editor vitest suite (113 tests)make -C editor clean # remove test cachesmake -C editor dev # the live HTMX editor against the app contract (optional)editor/demo-preview.ts
builds a sample app-contract response and renders the editor surface to HTML —
the controls form and the slate — without starting Express. Read the output and
you will see the five editorial constraints as range/number/switch controls, and
the form wired with hx-post="/preview", hx-target="#recommendation-preview",
hx-swap="outerHTML".
The checkpoint, worked
Section titled “The checkpoint, worked”Where does the ranking happen — in this editor, or behind the app contract?
Behind the app contract. The editor never re-orders a slate. When a slider
moves, the form hx-posts the new constraint values to the platform’s
/preview endpoint; the platform re-ranks and returns a fresh
#recommendation-preview partial that HTMX swaps in. The editor’s only jobs are
rendering the slate and posting the controls. That is exactly what makes it
swappable (ADR-0005):
a Streamlit demo or a real CMS could replace this client without the platform
changing, because the editorial logic lives in the contract, not the UI.
What makes this a good rep
Section titled “What makes this a good rep”Following the foundations template (ADR-0033), in the TS
idiom: make run renders the surface deterministically with no server or fetch,
make check runs the 113-test vitest suite as the correctness gate, and the
live UI is one make dev away. The reps you drill here are SSR + HTMX rendering
and the swappable-client boundary — the part of the stack with the most
transferable value.
What an editor sees
Section titled “What an editor sees”The editor interface presents a configuration to the editor: sliders for
the three soft constraints (diversity, recency, sentiment), toggles + a
threshold for the sensitive-topic guard, and a list management UI for
editorial promotion. A preview pane shows the recommendation list a sample
user would see under the current configuration. Moving any control
issues an HTMX hx-post to /preview, which refreshes the preview pane
in place — no page reload, no JavaScript framework.
That live-preview shape is the operational form of editorial accountability: an editor sees the effect of a change before they commit the change.
How the code is laid out
Section titled “How the code is laid out”src/server.tswires the Express app together.src/routes/contains one file per editor surface — recommendations, configurations, preview, change-explainer partial.src/configurations/,src/recommendations/, andsrc/articles/are typed thin shells over the FastAPI client: repository + view + types.src/schemas.tsis where Zod schemas validate every form post.
The TypeScript client types are generated from the canonical OpenAPI
catalog in
editor/openapi/app-contract-sources.json
(ADR-0006).
That means a contract change makes the editor fail at compile time, not in
production.
Tests cover the surface
Section titled “Tests cover the surface”editor/tests/
holds 76 Vitest tests, all passing. Render tests confirm the HTML output
shape; repository tests confirm the API integration; route tests confirm
form submission flows. The HTMX partials are tested by asserting the
returned HTML fragment shape.
Type safety end-to-end
Section titled “Type safety end-to-end”The Express side uses strict TypeScript, the generated OpenAPI client preserves the catalogued app-contract schemas, and the Zod validators at form boundaries ensure even editor-input data is checked before it reaches the API. That keeps the OpenAPI contract visible from the HTTP boundary to the rendered HTML — which is the production-realism payoff of ADR-0005’s TypeScript choice.
After this module
Section titled “After this module”The assistants module hangs its UI partials inside the
editor — when an editor changes a slider, the recommendations partial
refreshes and an HTMX hx-get triggers the change-explainer partial to
describe why the list moved.