diff --git a/docs/decisions.md b/docs/decisions.md index eafdf2e..6c57e4a 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -178,3 +178,10 @@ says so. preference. The limiter is keyed by email rather than IP (a proxy would mean trusting `X-Forwarded-For`) and locks the *attempt rate*, not the account, so nobody can lock someone else out by trying. +43. **The JSON API is deferred entirely, not built on demand.** Decision 17 kept the contract fixed + and expected handlers to appear one at a time; in practice nothing consumes `/api` at all, so + even that trickle would be handlers with no callers, plus golden tests guarding shapes nothing + reads. The contract in [spec.md](./spec.md) stays as the design — it is what stops the shape + changing under a future client — and the first endpoint gets built the day something actually + calls it. Both surfaces being thin adapters over one data function is already true of the page + handlers, so adding the JSON side later stays a one-line-per-route job. diff --git a/docs/later.md b/docs/later.md index 47c7b72..d0e255f 100644 --- a/docs/later.md +++ b/docs/later.md @@ -151,6 +151,23 @@ Notes for whoever builds it: --- +## The JSON API + +Designed and specified in [spec.md §8](./spec.md) — object shapes, endpoints, error codes, +pagination — and deliberately not implemented, because nothing calls it (decision 43). + +When something does: + +- Build only the endpoints that consumer needs, as `jsonOf(...)` adapters over the same data + functions the pages already use, so the domain rules cannot diverge between the surfaces. +- Add the golden-file tests at the same time, one per object shape. They are what makes a renamed + field a test failure rather than a silent break in a client you cannot update. +- CORS is a one-line middleware, added the day the consumer is on a different origin. Not before. +- The most likely first consumer is a native client (see above), and the endpoints it needs are + login, the queue, a song with its reviews, and posting a review — four routes, not twenty-one. + +--- + ## Filters on the browse list `/songs` is newest-first with no filters. Once there are a couple of hundred songs, "which ones diff --git a/docs/spec.md b/docs/spec.md index f5dee5f..027bbc4 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -509,8 +509,10 @@ file. ## 8. API contract -Fixed before implementation, because the shape is the expensive thing to change once a client is -installed somewhere you cannot update. +**Not built.** Nothing consumes `/api` — the browser talks HTML to the page surface — so this +section is a design, not a description of running code (decision 43). It stays here because the +shape is the expensive thing to change once a client is installed somewhere you cannot update, and +the first endpoint is one line over a data function that already exists. **Conventions** @@ -727,4 +729,4 @@ panel, so the admin surface comes first — before a single member can exist. this step.** 5. **YouTube path** — yt-dlp metadata and download, slotted into a pipeline that already works. 6. **Stats, profiles, avatars, palaute.** -7. **API endpoints and golden tests**, once something wants them. +7. **API endpoints and golden tests** — deferred until something wants them (decision 43).