Domain, Data, and State Foundations
Why this chapter matters
Many frontend problems blamed on state management are actually domain modeling problems. The UI does not know what a record means, who owns it, how fresh it must be, which user can change it, or what should happen when two sources disagree.
A frontend architect needs a clear model for domain concepts, data ownership, and state placement before choosing libraries.
The state placement model
| State type | Belongs in | Examples | Common mistake |
|---|---|---|---|
| Addressable navigation state | URL | filters, selected tab, pagination, shareable search | hiding it in component state |
| Server-owned data | server/cache layer | user profile, report rows, permissions, product inventory | copying it into local state and letting it drift |
| Client interaction state | component or UI store | open menu, focused row, draft panel expanded | pushing transient UI details into global state |
| Durable local work | IndexedDB or local durable store | offline drafts, queued commands, uploaded files pending sync | treating local storage as a database without migrations |
| Derived state | computed selectors | totals, grouped rows, filtered visible items | storing duplicate values that become inconsistent |
| Cross-session preference | controlled preference store | theme, density, saved view | mixing preferences with authorization or product truth |
| Experiment state | experiment platform | variant assignment, exposure event | changing behavior without observability or rollback |
Good architecture makes the state location obvious from the state's job.
Domain vocabulary before component vocabulary
For each important surface, write down domain nouns and verbs before designing components.
Example for a SaaS reporting dashboard:
| Domain concept | Meaning |
|---|---|
| Report | A saved definition of metrics, dimensions, filters, and permissions |
| Report run | A concrete execution of a report definition over a time range |
| Filter | A user-controlled constraint on report output |
| Segment | A reusable audience or business grouping |
| Export | A side-effecting operation that creates a downloadable artifact |
| Permission | A policy decision about who can view, edit, run, or export |
Now components can map to product reality instead of inventing their own language.
Ownership questions
Before implementation, answer:
- Which backend or BFF owns the canonical record?
- Which fields are safe for the browser to see?
- Which fields are editable by this user?
- Which changes are optimistic and which require confirmation?
- Which state must survive refresh, tab close, or offline use?
- Which state is shareable through URL?
- Which state is personal preference rather than product truth?
- Which state needs audit?
Data lifecycle
requested
-> loading
-> available
-> stale
-> refreshing
-> mutation pending
-> confirmed, rejected, conflicted, or rolled back
The UI should not collapse these into one vague "loading" or "error" state. Different lifecycle states require different copy, controls, telemetry, and recovery.
Cache and freshness baseline
Document freshness by user harm:
| Data | Freshness expectation | User harm if stale |
|---|---|---|
| Static marketing content | minutes to days | low, unless legal/compliance text |
| Dashboard analytics | seconds to hours depending on domain | medium; wrong decisions or confusion |
| Permissions | immediate or near-immediate | high; access leak or blocked work |
| Inventory/price | domain-specific, often strict | high; purchase or trust failure |
| Notifications | near-real-time if action-driving | medium to high |
| AI/RAG context | source freshness must be visible | high if generated output drives decisions |
Freshness is a product decision with technical consequences.
State anti-patterns
- Storing server data in a global client store because it is convenient.
- Putting shareable workflow state only in memory.
- Using URL state for secrets or sensitive filters.
- Duplicating derived state until it disagrees with source state.
- Treating optimistic UI as success before the server accepts the mutation.
- Letting each component invent its own empty, loading, and error semantics.
- Choosing a state library before defining state categories.
Review checklist
- Domain nouns and verbs are written in product language.
- Canonical owners are named for each data source.
- URL, server, client, local durable, derived, and preference state are separated.
- Freshness expectations are tied to user harm.
- Mutation states include pending, confirmed, rejected, conflicted, and rollback behavior.
- Sensitive data is not stored in URL, logs, or local storage.
- Empty/error/loading states are specific to the lifecycle state.
- Tests cover stale response ordering and mutation recovery where relevant.
Exercises
- Pick a complex route and classify every piece of state using the state placement model.
- Write a domain vocabulary table before sketching components.
- Define freshness expectations for five data types and rank user harm if stale.
- Replace a generic loading/error model with a full data lifecycle matrix.
Source lens
This foundation connects local distributed-systems material, database consistency concepts, browser storage guidance, and frontend architecture practice. It prepares you for Part III rendering/data architecture and Part V system design.