One Domain Rulebook, Concept-Sliced Convex, Standard FSD
Why the codebase uses one runtime-free canonical domain package shared by frontend and Convex, concept-sliced Convex adapters, and standard Feature-Sliced Design for the frontend — and which structural rules each brand promise obliges
Decision
Goldie Blocks uses one runtime-free canonical domain model
(packages/domain) shared by the frontend and Convex, concept-sliced Convex
adapters for persistence and authority, and standard Feature-Sliced Design
(FSD) for the frontend, with Atomic Design retained only for domain-neutral
Shared UI.
In plain terms: one official rulebook states what Documents, Modules, Blocks and Fields are; the Convex vault stores and guards them using that rulebook; and the frontend workbench follows a documented industry filing system rather than a homemade one.
Settled 2026-08-09 by the owner-led architecture grill recorded in
the archived plan 2026-08-09-codebase-architecture,
after independent reviews and a merged tracer
(R3) proved the package, the boundaries, and every enforcement gate — each
observed failing before being trusted green.
The brand pillars are the rationale
Every structural rule in this record exists to make one of three product promises dependable. An abstraction that serves none of them and removes no demonstrated safety risk is ceremony, not architecture.
| Brand pillar | Product mechanisms | Architectural obligation |
|---|---|---|
| A Block for every story — and a story for every Block | Library discovery, classification, signals, readable/About faces | One discovery contract and one two-face domain projection |
| Many views, but only one truth | @ mentions, stable identity, surfaces, agents and outputs | One canonical model; every other representation is a projection or adapter |
| Build on your best work | Working → library, versions and lineage | One reuse lifecycle with immutable pinned versions and no silent source mutation |
Test any proposed structure with four questions: does it make the right Folio easier to find; understandable from both faces; one truth across every reference and view; safer to save, improve and reuse?
The three responsibility areas
packages/domain/ canonical types, rules and projections
↑
├──────── convex/ storage, authority and transactions
└──────── src/ FSD frontend applicationThe domain owns runtime-free, deterministic business meaning: canonical
types, parsing and validation, Proposed Change lifecycle, naming and mention
projections, transitions, numbering, and agent/interview contracts. Purity is
the entry requirement, not the definition of membership — deployment
configuration is not domain meaning and lives in convex/convex.config.ts (or
convex-dev/ for dev-only fixtures and switches).
Convex owns the assembled schema, registered functions, auth and
permission prologues, AuthorityContext construction and enforcement,
transactions, storage, and runtime-only configuration. It is organised by
business concept (convex/folio/, convex/goldie/, convex/library/), never by global
technical buckets. The concepts are the ones the schema has — this record
originally illustrated the rule with convex/blocks/, convex/documents/ and
convex/modules/, three drawers the Folio unification abolishes by making a
document, a module and a block three kinds of one record. The rule is
unchanged; only the example was tier-shaped. The current concept list lives in
Convex rules (owner ruling, 2026-09-01).
Every content-mutating capability receives an explicit
AuthorityContext; a content write without one is not representable.
The frontend follows standard FSD layers — shared, entities,
features, widgets, pages, app — with their documented meanings
unchanged. "Use FSD sparingly" means do not create empty or shallow slices;
it never means altering layer meanings. Atomic Design survives only inside
shared/ui (atoms and molecules); the global organisms/ and templates/
levels are retired because their size-based admission test made them junk
drawers.
Humans and agents are peer operators: different public wrappers where trust or approval differs, but one canonical operation underneath. Agent scope narrows structural reach; it never grants a capability the principal lacks.
Frontend operation placement (owner ruling, 2026-08-27). A Feature and a dispatcher answer different questions and are not competing architectures. A Feature is the reusable frontend home for a user intention used by two or more Pages; its implementation binds the canonical domain operation, policy, persistence, optimistic state and failure handling. Rename, duplicate and delete Document already meet that threshold because Document Home and Document Work both offer them, and a future Project surface must call the same implementation rather than depend on the drafting editor. An intention used only within the drafting editor stays behind a local dispatcher until another consumer exists; speculative reuse does not earn a Feature.
The reusable vocabulary is Folio operation and Folio arrangement, not
"Stack operation". Stack is neutral visual furniture and never owns a
business write; a Substack names only a Stack in a nested relationship. A
menu, drag gesture, keyboard command, Goldie tool or non-Stack surface adapts
its input onto the same operation. Operations on a Folio change that Folio;
insert, move, reorder and remove change its parent's Folio arrangement, while
duplication combines a source-owned copy with placement in that arrangement.
Fields remain ordered parts of a data Block rather than Folios, so Field
authoring is reused through the Block operation boundary instead of inventing
a Field Stack. The domain operation catalogue remains the authority for
vocabulary, availability, capability and destructive posture; frontend
placement must not restage those rules. The glossary's Folio-operation and
Folio-arrangement entries remain the definitions rather than this placement
ruling becoming a second operation catalogue.
Shared plain-text editing
useEditableValue owns draft, cancellation, blur commit and the optimistic
hold for plain-text editors. Only the latest write may settle the hold;
an older refusal cannot replace a newer draft. Callers retain validation,
normalisation and the policy for a refused write. A callback returning a
promise reports settlement; a void callback acknowledges through updated
value props. Presentation never enters the hook.
EditableText is the shared atom for single-line inputs and growing
multiline textareas. Length and appearance are independent: multiline
chooses the native element; variant chooses bare, line or pill. Typography
comes from the surrounding surface. EditableName adds derived-name and
click-to-edit behaviour with header, plain and pill treatments. Field keys
and values keep their domain adapters; About notes keep their resting
presentation. Existing activation is preserved. Rich block content remains
a separate editor so its move to Tiptap does not reshape plain-text controls.
Each family has one variants gallery; behavioural stories remain separate
where they prove distinct interactions (GB-296).
Domain concept chapters
The accepted chapters, each earned by surveyed real code (created only when its code moves in — no empty symmetry):
agent/ · block/ · document/ · field/ · flow/ · folio/ ·
interview/ · mention/ · naming/ · numbering/ · proposed-change/
Two rulings shape the list. interview/ stays separate from agent/:
the interview is the questionnaire — which Fields, what order, what counts as
done — and exists whether a person on the Form surface or Goldie conducts it;
agent/ holds only Goldie's turn machinery. mention/ replaces
reference/ (owner ruling 2026-08-09: "reference" is too general): a
mention is authored in text, binds to stable identity, and survives
renames — one product word from rulebook to screen, matching the
at-mention frontend capability. packages/domain/src/reference/ was
renamed to mention/ 2026-08-11, closing the gap between this ruling and
the code. document/ and flow/ are reserved names, not yet created — no
code has moved into them.
Rules that prevent drift
- One concept, one canonical declaration — adapters translate, never mirror.
- One folder owns one responsibility; no concept has two plausible homes.
- Meaning decides ownership, not technical purity or visual size.
- Shared UI is domain-neutral — product nouns are banned from its public identifiers and CVA keys.
- FSD imports travel downward through slice public APIs; sidesteps are
violations. Cross-Entity presentation uses FSD's documented
@xconvention (Steiger must be observed enforcing it before the first cross-Entity module lands). - Frontend runtime code uses the generated Convex API, never private backend implementation modules.
- Authority is explicit —
AuthorityContextis a required value, not a convention. - No empty symmetry; no accidental renames; no long-lived shims; no big-bang migration.
- A test not observed failing is not evidence.
Enforcement: Steiger (FSD layers, slice isolation, public APIs), Biome (domain/Convex/legacy import bans, Shared UI product-noun ban), TypeScript across every consumer, Vitest domain tests, the generated Convex API as the runtime boundary, and a function-path test for string-based Convex references. Every gate was deliberately broken and observed red before being trusted (R3, 2026-08-09). The one-declaration rule remains partly a review rule — structurally identical types compile.
Where the three areas stand
In plain terms: this section says what is done and what is not. It does not list the folders — the tree does that, and a list in prose drifts the moment someone adds a slice.
packages/domain is populated. Every chapter is under a settled name, and
ls packages/domain/src is the list. field/ owns the canonical stored Field
declaration, the canvas snapshot contract, and the type-to-initial-name
projection; Convex and the frontend consume those declarations rather than
mirroring them.
The frontend's structural move to FSD is complete. Every layer is
populated, the legacy src/components tree went on 2026-08-11, and
src/routes, src/hooks and src/styles do not exist — routes are thin shells
over their Pages. src/lib was removed on 2026-08-14, emptying Steiger's ignore
list so every file under src/ is linted. There are no Atomic-Design
leftovers: the one exception this record permitted, the module card, was
discharged when it became entities/module.
src/features holds a slice only where cross-Page reuse earns it — the
two-Page bar this record's placement ruling sets. duplicate-folio (2026-09-07,
GB-151) met it because Document Home and Document Work both duplicated a
document, each with its own catch block and alert and, on Work, no pending
guard. review-folio-proposal (2026-09-15, GB-201) is the one review controller
for every kind's card: it binds Accept and Reject and holds the pending and
refusal state, the Page subscribes to the open proposal, and the canvas places
the drawn halves on the anchor card. Rename and Delete stay bound at Document
Work until a second surface offers them.
The one open gap is convex/. Concept slicing has begun — folio/,
goldie/ and library/ — and the root still carries the modules nothing has
earned a home for yet. Slicing continues as work earns each move, carrying its
generated and string paths; the move discipline is in
Convex rules. Opportunistic moves alone will not
empty a flat root, so this closes when someone decides it is worth its own work,
not on a schedule.
Both migration plans are archived and this record is authoritative.
Settled vocabulary
- Folio — a Document, Module or Block: stable identity, immutable authored versions, reuse posture, lineage. Field is deliberately excluded — a Field freezes with its Data Block version.
- Mention — authored in text with
@; binds to stable identity; survives renames. Retires "@ reference" in prose. - Proposed Change — the canonical propose → tracked differences → revise → accept/reject → apply lifecycle. One baseline, one diff, one acceptance state, projected on both faces. "Tracked changes" is its visual projection, not a second stored change.
- Canvas — the editable rendering surface where a Document is composed.
- Library — reserved for the product's reusable precedent bank; never a code-file name for anything else.
- Goldie — the agent persona and its agent-specific surfaces; not a
prefix for general UI. Shared UI names stay neutral (
CardFrame,WorkBar,ViewTabs,PromptComposer).
Product documentation does not mirror code folders: docs describe product
truth by concept; the repository map lives in CLAUDE.md.
Open and deferred
About-source lexical fidelity is explicitly deferred (owner, 2026-08-09): whether comments, whitespace and untouched spans of human-authored About source must survive edits byte-for-byte, or semantic round-trip suffices. Standing constraint: no parser or source-editor library may be chosen for the About face until this is ruled — the two behaviours need different machinery. (Tiptap's decided role is the Content facet's editing adapter only; it must not be quietly reused for the About face.)
Proof obligations carried forward: Steiger @x enforcement (before the first
cross-Entity module), and a Document–Module–Block search tracer proving the
discovery folder and query shape before either enters the target tree.
Revisit when
- A Field earns independent lifecycle (own audit trail, routine concurrent editing, cross-library Field queries, or independent reuse) — the Folio boundary then re-opens.
- Durable cross-device queues, concurrent Proposed Changes, or shared review arrive — the evidence for independent Proposed Change persistence.
- The deferred fidelity ruling lands — it constrains the About-face editor choice.
Related
- The archived plan
2026-08-09-codebase-architecture— migration detail, destination manifest, rulings log - Convex rules — the concept-slicing move discipline
- Feature-Sliced Design overview and FSD for LLMs
- Names Are Projections
- Stable IDs Over Handle References
- Block Edits Run Inside One Envelope
- Glossary
Buy the Mechanics, Build the Document Semantics
Which parts of Goldie Blocks lean on established packages, which stay custom because they are the product's own rules, and which frameworks are deliberately not introduced
Component File Partitions Must Preserve Locality
When deep extraction is preferred, when a single-consumer partition is allowed for navigation, and which seams still destroy locality