Skip to content

feat: collections stage 3 store and API (RFC-0042 step 2) - #104

Merged
Madraka merged 1 commit into
mainfrom
feat/stage3-store
Oct 23, 2026
Merged

Madraka merged 1 commit into
mainfrom
feat/stage3-store

Conversation

@Madraka

@Madraka Madraka commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Step 2 of RFC-0042's rollout (ADR-0044), built on #103.

Site writes (only when collections changes; dry runs too)

  • listFields and expiry.field must exist (unknown_field), and the expiry field must be a date or datetime (invalid_expiry, 422).
  • Structured-data presets go through checkPreset: errors are refused with structured_data_invalid (422); warnings are saved.
  • list_field_in_use (409) refuses unlisting, dropping or retyping a field that a contentList section filters or sorts by, and dropping a select option a section compares with. details.pages names the pages. One SQL predicate counts the uses and also guards the site CAS (rule 4); a racing test covers it.

Page writes: changed contentList where/orderBy are checked with checkFieldQuery, so invalid_query (422) comes back with paths. Unchanged sections are not re-checked.

Field operations (RFC-0041)

  • rename_field also renames the field in listFields, expiry, structured-data sources and sections' queries, in one batch. Revert renames them back.
  • remove_field and change_field_type refuse with list_field_in_use while something still references the field.

Queries: queryContentEntries / applyFieldQuery use the shared evaluator over resolveFields.

  • Entries without a value sort last; ties fall back to the collection's sort, then id.
  • A translation reads the original's values.

API: GET /api/sites/:id/entries takes:

  • where: a JSON list of FieldCondition;
  • orderBy: a JSON FieldOrder;
  • limit: 1–100, which switches the answer to {entries, total, nextCursor?};
  • cursor.

Without these the answer is exactly as before. Bad input gets invalid_query with paths.

Note: expiry can be saved but is not applied on the site until step 3 (the renderer gate and the gates: 2 guard). Release only after step 3.

Tests

  • New core-ts suites on sqlite, D1 and DO SQLite: 69/69 in a filtered run.
  • api: 418/418.
  • Typecheck of core-ts, api, mcp-server and studio, size check, MCP doc check and biome are clean.

Changeset: minor (core-ts, api).

🤖 Generated with Claude Code

- updateSite/createSite check listFields, expiry (invalid_expiry) and
  structured-data presets (structured_data_invalid; warnings saved).
  list_field_in_use (409) when a field that contentList sections
  filter or sort by is unlisted, dropped or retyped, guarded on the
  site CAS.
- Page writes check contentList where/orderBy (invalid_query, 422).
- Field operations carry listFields, expiry and structured-data
  references through renames and refuse removals and type changes that
  would break them.
- queryContentEntries / applyFieldQuery with the shared evaluator;
  GET /entries takes where, orderBy, limit and cursor.

Shared suites on sqlite, D1 and DO SQLite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com>
@Madraka
Madraka merged commit 80284fc into main Oct 23, 2026
4 checks passed
@Madraka
Madraka deleted the feat/stage3-store branch October 23, 2026 09:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant