ADR-012: Domain Cache Sync Pattern
Status: Accepted
Date: 2026-03-09
Deciders: CepatEdge maintainers
Context
High-read domains need predictable API performance without excessive DB load. Generic cache invalidation after every mutation causes extra DB reads and stale list/detail divergence.
Decision
Adopt a domain-level cache sync pattern for read-heavy modules:
- Cache-first reads with explicit DB fallback on miss.
- Separate cache shapes for list and detail.
- Domain-local sync helpers that patch both list and detail caches after DB writes.
- No request-body to cache writes; patch payloads must come from persisted DB results.
- List cache schema versioning to support safe payload evolution.
Implementation Rules
- Keep cache update helpers close to the domain (e.g.
cache/<domain>/sync.ts). - Mutation flow is always: DB write -> build patch from DB result -> sync caches.
- Detail cache can be richer than list cache; list must only contain fields needed by list UI.
- Keep permissions/session-specific computed fields out of globally shared list cache.
- Introduce cache version bumps when list contract changes.
Concrete Examples
Users module
cache/user/sync.tsexposes helpers likecacheUserProfile,cacheUserAvatar,cacheUserSecurity./userslist cache stores only list-needed fields (lean shape)./users/:iddetail cache keeps richer profile/security/avatar data.
Maintenance module
- Maintenance cache now uses detail read-through (
getMaintenanceRequest) and full-list cache hydration on miss. - Mutations and attachment changes re-sync list/detail via maintenance cache helpers.
- List filtering/pagination reads from cache; DB is hit for writes and cache-miss hydration.
Consequences
Positive
- Lower repeated DB read load.
- Better list/detail consistency.
- Predictable extension pattern for new domains.
Negative
- More domain cache orchestration code.
- Requires strict discipline to wire all mutation points.
Follow-Up
- Use this ADR as the baseline for future read-heavy modules (analytics views, audit lists, logs).