Build an Angular permit operations queue for a city reviewer. The first page contains 47 cases and a total of 47,000 authorized summaries. Search and status are writable source signals; visible cases and counts are computed from the same source snapshot. A row receives a required case input and emits an approval intent, while the parent owns the mutation, pending state, and rollback. Stable case IDs must keep a private note attached to its case when sorting changes. Switching rapidly between cases 47 and 81 may finish requests in reverse order; only the active case may appear. The initial server HTML and browser render must agree on authorized data before a browser-only saved display preference applies.
Project: Angular permit operations queue
Build contract
- Keep one writable case snapshot and derive the visible list, count, and status summary with computed signals.
- Use required inputs and typed outputs for row contracts; track rows by stable case ID and keep server mutations in the owner.
- Bind detail requests to selected identity, cancel obsolete reads, and validate response identity before display.
- Isolate server requests, transfer only authorized boot data, and defer browser storage until after initial render.
Implementation checkpoint
function mayShowPermitDetail(requestGeneration, activeGeneration, responseCaseId, selectedCaseId) {
return requestGeneration === activeGeneration && responseCaseId === selectedCaseId;
}
console.log(mayShowPermitDetail(47, 81, 47, 81));
// Output: falseCost and boundaries
A changed query may scan n authorized cases and allocate up to O(n) visible references. A computed signal avoids recomputation while its dependencies stay unchanged; it does not turn a 47,000-case filter into constant-time work. Preserve an O(page size) render boundary and ask the server for paged search when filtering all cases on every keystroke becomes expensive. Stable row identity retains editor state, which also means private drafts need explicit expiry and logout cleanup. Canceling an obsolete read saves some client work, but the server may already have processed it. Generation and identity checks still guard publication. Server-side rendering spends bytes and CPU per request; transfer only data already authorized for that viewer and never share mutable reviewer state across requests.
Failure drill
Load the same authorized snapshot on server and client, then apply a saved page-size preference only after hydration. Reverse the completion order of detail requests for cases 47 and 81; case 47 must not overwrite case 81. Insert a new case before a row whose editor contains a private note, then sort in both directions. The note must remain with its case ID. Force an approval failure after the child emits its intent and verify that the parent restores the previous server-backed status. Render two reviewers concurrently on one server worker and compare their boot payloads: a case from one reviewer must never enter the other response.
Acceptance checks
- Visible cases, count, and status summary always describe the same source snapshot and filters.
- Rapid selection changes cannot publish stale detail or leak detail from another selected case.
- Sort, insertion, and rejected approval preserve case-owned notes and authoritative status.
- Concurrent server renders keep viewer data separate, and the first browser render matches authorized HTML.
Common Mistakes
- Copying computed output into another writable signal.
- Using a row position as the tracking key.
- Assuming cancellation alone prevents an obsolete response from rendering.
- Serializing private detail into a shared server cache.
Related lessons
Angular Signals and Delivery Boundaries; Angular Signal Sources, Computed Views, and Effect Scope; Angular Component Input, Output, and Row Identity; Angular HttpClient Streams and Stale Detail Requests; Angular SSR Hydration and Private Transfer State.
