If You Remember One Thing
In a system design interview, your data model is the contract for everything else: rendering strategy, UI states, caching, and reliability. If your entities, ownership boundaries, and invalidation rules are explicit, your frontend system design answer sounds senior and survives follow-up questions.
In the RADIO framework, Data model is where scope and architecture become concrete contracts.
What Data Model Must Produce
| Artifact | Minimum interview output | Why it matters |
|---|---|---|
| Entity map | Core entities, IDs, and relations | Prevents hand-wavy domain modeling |
| State ownership table | Server truth vs client UI state vs URL state | Avoids sync bugs and duplicate sources of truth |
| UI states matrix | idle/loading/success/empty/error/stale/partial | Shows production-ready frontend thinking |
| Cache policy | Query keys, TTLs, and invalidation triggers | Makes stale behavior predictable |
| Mutation flow | Optimistic update, rollback, and conflict handling | Tests write-path maturity |
Inputs You Must Carry from Requirements and Architecture
Data model quality is a dependency chain. Good system design interview preparation means carrying constraints forward, not resetting at each step.
| Input | Data-model decision | What to say out loud |
|---|---|---|
| Primary user flow | Model entities around top task first | "I am modeling the highest-value user path before edge entities." |
| Route rendering split | Separate SSR-safe payloads from CSR-interactive state | "I am designing data contracts to support both SSR payload and CSR updates." |
| Scale and latency targets | Define pagination shape, cache key granularity, and TTL | "I will tune key and TTL design to hit p95 latency targets." |
| Reliability requirements | Add stale and partial states in contracts | "I will include stale and partial response semantics in the model." |
| Security constraints | Model field visibility by role/scope | "I am separating public and privileged fields at contract level." |
Entity Model and API Contracts
Entity sketch template
Suggestion {
id: string
label: string
type: 'user' | 'repo' | 'doc'
score?: number
updatedAt: string
}
SearchResponse {
query: string
items: Suggestion[]
nextCursor?: string
stale: boolean
partial: boolean
}Modeling rules you should state
- Every entity has stable ID and update timestamp/version.
- Keep payloads route-focused; avoid over-fetching fields not rendered.
- Represent optional capability as explicit fields, not implicit null behavior.
- Include metadata needed for UI state decisions (for example,
stale,partial).
State Ownership Model
| State class | Owner | Examples | Common pitfall |
|---|---|---|---|
| Server truth | API + server-state cache | Entities, permissions, availability | Copying into multiple client stores |
| Client view state | Component/local store | Popover open, selected row, input draft | Persisting ephemeral state globally |
| URL state | Router/query params | Query, filters, sort, page cursor | State not shareable/bookmarkable |
UI States Matrix (Critical for Frontend)
| State | Trigger | What user sees | Telemetry signal |
|---|---|---|---|
| idle | No request yet | Prompt or default content | Initial load event |
| loading | Request in-flight | Skeleton/spinner with accessible announcement | Request start latency timer |
| success | Data received | Primary content rendered | Success rate and completion |
| empty | Valid response, zero items | Empty-state guidance + next action | Zero-result rate |
| error | Failure/timeout/unauthorized | Error message + retry path | Error rate by endpoint/route |
| stale | Cached data older than freshness policy | Stale badge while background refresh runs | Stale duration distribution |
| partial | One dependency failed in aggregate response | Partial data + degraded notice | Partial-response ratio |
Query Keys, Caching TTLs, and Invalidation
Cache policy example
| Query key pattern | TTL | Invalidate when | Notes |
|---|---|---|---|
['search', query, filters, sort] | 15-30s | Query/filter/sort changes, relevant mutation | Short TTL for high interaction flows |
['entity', id] | 60-120s | Entity update/delete, permission change | Stable detail reads with targeted invalidation |
['list', segment, cursor] | 30-90s | New create event affecting ordering | Cursor-aware invalidation avoids full reset |
What interviewers want to hear
- You define key shape before saying "we will cache."
- You combine time-based and event-based invalidation.
- You explicitly describe stale behavior and background refresh.
Pagination, Sorting, Filtering, and URL Sync
| Concern | Decision | Pitfall to avoid |
|---|---|---|
| Pagination | Prefer cursor pagination for mutable lists | Offset drift on frequently updated feeds |
| Sorting | Include sort token in query key and URL | Cache collisions across sort modes |
| Filtering | Normalize filter order in keys and URLs | Duplicate queries due to parameter order |
| URL sync | Keep shareable state in query params | State lost on refresh/back/forward |
Mutation Flows and Optimistic Updates
- Capture previous cache snapshot for affected keys.
- Apply optimistic patch locally for immediate UI feedback.
- Send mutation request with idempotency token where possible.
- On success, reconcile server response and clear temp markers.
- On failure, rollback snapshot and show actionable error state.
Script cue: "I will optimize read-your-writes UX with optimistic updates, but keep rollback explicit to avoid silent divergence."
Consistency and Sync Strategy
| Consistency level | Where to use | Frontend implication |
|---|---|---|
| Strong | Payments, inventory, permission-critical operations | Block speculative UI; wait for confirmed server state |
| Eventual | Feeds, analytics counters, recommendations | Allow stale view with explicit refresh semantics |
| Read-your-writes UX | User-triggered actions where instant feedback matters | Use optimistic patch + rollback guardrail |
Failure Modes and Recovery
| Failure mode | User-visible behavior | Data-model guardrail |
|---|---|---|
| Timeout under load | Show stale cache + retry affordance | Model stale flag + lastUpdated timestamp |
| Partial backend response | Render available sections with degraded notice | Model partial response metadata per segment |
| Mutation conflict | Conflict prompt with server-authoritative view | Version token and conflict status in contract |
| Permission drift | Disable restricted actions and refresh view | Role/scope fields as part of entity payload |
Security and Privacy Boundaries
- Classify fields: public, authenticated, privileged.
- Never leak privileged fields into broad list endpoints if detail view needs auth checks.
- Avoid caching sensitive payloads in long-lived shared layers.
- Design contracts so client cannot infer restricted data from error shape.
Observability and Data Quality Signals
| Signal | Metric | Alert direction |
|---|---|---|
| Freshness | Stale-state dwell time by route | Alert when stale duration exceeds SLO window |
| Correctness | Client/server mismatch rate after mutation | Alert on rollback spikes |
| Resilience | Partial-response ratio and timeout rate | Alert on sudden trend breaks |
| User impact | Primary task completion rate | Alert on significant drop after release |
What to Say Out Loud (Data Model Script Cues)
- "I will define entities and ownership boundaries before discussing libraries."
- "I am separating server truth, UI state, and URL state to avoid sync confusion."
- "I will model all critical UI states: idle, loading, success, empty, error, stale, and partial."
- "I am defining query keys first so caching and invalidation stay predictable."
- "Trade-off here: shorter TTL improves freshness but increases backend load."
- "I will use optimistic updates only where rollback is safe and explicit."
- "For this flow, eventual consistency is acceptable; strong consistency is reserved for critical writes."
- "I am keeping shareable filters and pagination in URL state for deep links."
- "I will instrument stale time, mutation rollback rate, and partial responses to validate this model."
- "With data contracts locked, I can now move to interface behavior confidently."
Data Model Timebox for Interviews
45-minute interview
| Time range | What to do | Output artifact |
|---|---|---|
| 0:00-2:00 | Sketch top entities and relations | Entity map |
| 2:00-4:00 | Define state ownership boundaries | Ownership table |
| 4:00-6:00 | Set query keys, TTL, invalidation | Cache policy card |
| 6:00-8:00 | Cover UI states + mutation failure handling | UI states matrix + rollback notes |
60-minute interview
| Time range | What to do | Output artifact |
|---|---|---|
| 0:00-3:00 | Entity model with field-level contracts | Entity and contract sheet |
| 3:00-6:00 | State ownership and URL sync rules | Ownership and URL table |
| 6:00-9:00 | Caching and invalidation by use case | TTL and invalidation matrix |
| 9:00-12:00 | Mutation conflict, consistency, observability recap | Hardening checklist |
Quick Drill: Typeahead Data Model in 7 Minutes
| Minute | What to produce |
|---|---|
| 0-1 | Entity sketch: Suggestion, SearchResponse, ErrorPayload |
| 1-2 | State ownership split: server results, UI highlight index, URL query |
| 2-3 | UI states matrix including empty/error/stale/partial |
| 3-4 | Query key pattern and TTL decisions |
| 4-5 | Invalidation triggers for query change and mutation |
| 5-6 | Optimistic update and rollback notes for save/recent actions |
| 6-7 | Telemetry: latency, error, stale ratio, zero-result rate |
Before You Move to Interface
- Entities and relationships are explicit and bounded.
- Server truth, UI state, and URL state are clearly separated.
- All critical UI states are modeled, not implied.
- Cache keys, TTLs, and invalidation triggers are concrete.
- Mutation rollback and conflict handling are defined.
- Security, privacy, and observability considerations are included.