Build a Vue permit review queue whose source snapshot contains 47,000 records. A reviewer searches, opens a case detail, writes a private note, and requests approval. Keep the case snapshot and search phrase as authoritative inputs; visible rows and count must be derived together. Switching from case 47 to 81 while a detail request is pending must invalidate the old request even when a test transport ignores abort. The case card proposes an approval through an event; the parent owns pending state, operation identity, server response, and rollback. Sorting or inserting a row must never move a note to another case. The server-rendered first view must be isolated per request and agree with the first browser render before a saved preference applies.
Project: Vue permit review queue
Build contract
- Derive filtered rows and count from a single snapshot; replace large shallow data immutably if shallow tracking is chosen.
- Watch only selected identity fields, register cleanup immediately, and reject stale or mismatched response payloads.
- Give rows stable case ID keys, emit approval commands, and keep private drafts owned by case ID.
- Create request-scoped server state and reuse its permitted snapshot for the first browser render.
Implementation checkpoint
function mayPublishPermitDetail(requestGeneration, activeGeneration, responseCaseId, selectedCaseId) {
return requestGeneration === activeGeneration && responseCaseId === selectedCaseId;
}
console.log(mayPublishPermitDetail(47, 81, 47, 81));
// Output: falseCost and boundaries
Filtering a snapshot is O(n) for n cases and may allocate an O(n) result array. Computed caching prevents unnecessary reruns when dependencies stay stable but cannot make each changed phrase free. Shallow tracking avoids nested proxy work, provided updates replace data instead of mutating a hidden field. A watcher can abort obsolete requests, yet the server may already have done work and an abort-ignoring transport still requires a generation guard. Saved drafts and pending operations consume memory proportional to active cases; define cleanup at submission, logout, and expiry. Per-request server state costs initialization time but prevents data crossing reviewer sessions. Serialized boot data uses response bytes and must exclude records the viewer is not allowed to see.
Failure drill
Type a phrase while a new snapshot arrives and check that count and rows agree. Mutate a nested object under shallow storage as a negative test, then repair the update by replacing the case and snapshot. Select case 47, then 81; return 81 first and 47 last, with abort ignored. Only case 81 may appear. Reject an approval from the server after a card emits its request; no other component should retain an optimistic status. Insert case 29 ahead of a drafted case and reverse sorting. Run two simultaneous server renders for different reviewers on one worker, then hydrate one browser with a different time zone and saved filter. Check private data isolation and initial markup agreement.
Acceptance checks
- Rows and count correspond to the same snapshot and phrase after every update.
- No stale detail, late response, or rejected approval appears as current data.
- Drafts stay with their case IDs through sort, insert, switch, and logout.
- Two server requests cannot share selected case state, and hydration begins from matching permitted data.
Common Mistakes
- Keeping filtered rows and count as separately writable state.
- Assuming request abort alone prevents a stale response from publishing.
- Sharing user-specific refs across server requests or mutating a child prop.
Related lessons
Vue Reactivity and Component Boundaries; Vue Source State, Computed Views, and Large Snapshots; Vue Watch Cleanup and Stale Request Ownership; Vue Props, Emits, and Keyed Editor Ownership; Vue Server Rendering and Hydration Stability.
