- Revised: 2026-09-18 by #27 — the gate was measured, and C is not used by any page
- Revised: 2026-09-27 by ADR 0016 — the gate is superseded: the pages that filter take path C
Context
With no request-time server (ADR 0001),
data can be read in two places: in server components while next build runs, or
in the browser after the page loads. Most of the site is static — a profile, a
CV, a list of projects. Some of it is interactive — filtering the tech radar,
tailoring a CV before printing.
Decision
Two paths, chosen per component:
- A — static content is loaded at build time. It runs entifix use cases
in server components during
next build. The HTML carries the data; no entifix, Effect or adapter code reaches the browser. - C — interactive parts load in the browser. They run the same static
adapter there, over JSON files the build writes into the export (
/data/<entity>.json, produced byforce-staticroute handlers from the same repositories the pages read, so the two cannot disagree).
C is where a backend slots in later: its adapter becomes a REST adapter pointed at the backend, a URL change at the composition root.
Gate
Before any page depends on C, the gzipped client cost of Effect,
@entifix/core, @entifix/business and the adapter is measured and written
into this record. If it is not acceptable, interactive parts filter data passed
down as props from build time instead, and this record is revised.
Measured (2026-09-18, #27)
The JavaScript each exported page loads, gzipped at level 9, summed over every
/_next/static/**/*.js its HTML references:
| Page | Without C | With C | Change |
|---|---|---|---|
/en/ | 217.2 KB | 217.3 KB | — |
/en/tech-radar/ | 217.2 KB | 295.6 KB | +78.3 KB (+36%) |
"With C" is the radar page carrying one client component that fetched every
/data/*.json, rebuilt the repositories, and ran the load use case to list
the radar's entries. It worked in Chromium against the export served like the
bucket: twenty entries, from the files alone.
Not acceptable, so no page uses C. Superseded by ADR 0016, which takes C on the pages that filter, for maintainability over bytes. Seventy-eight kilobytes is what
ADR 0006 spent its effort removing, and
here it would buy a filter over twenty records whose data is already in the
HTML. Interactive parts — the radar's filter first (#41) — filter props passed
down from build time. Path A pages ship no entifix code: neither the landing
page nor the radar references a chunk that contains EntityRepositoryTag or
loadUCFactory.
What stays is the seam: force-static route handlers still write every entity
to /data/<key>.json, from the same repositories and through the same use case
the pages read, and cost the browser nothing. A browser composition over them
was twenty lines, and is the first thing to try again when a page needs more
than props can carry, or when a backend makes the network the source anyway.
Alternatives
- Everything in the browser — the old app's shape. Ships the runtime and all content to every visitor, and search engines see less.
- Everything at build — cheapest, but the radar's filtering would not go through entifix at all, and the backend path would have no seam.