299e66fde5316f94de5cf8791a0d2e111456b393
PR 2 of the tabs + full-result-charts chantier — closes the loop on the BFF endpoint shipped in #173. Two changes: 1. Wraps the audit page content in two tabs — `Table` (default) and `Charts`. WAI-ARIA pattern: `role="tablist"` on the container, `role="tab"` on each button, roving tabindex (the active tab reachable via Tab, inactive ones via arrow keys). The Charts panel hides until the user switches to it. 2. Charts now consume the BFF stats endpoint (full filtered set, Redis-cached 5 min) instead of the per-page aggregations the previous PR shipped. The three client-side computeds (`dailyVolume`, `outcomeBreakdown`, `dailyByEventType`, `totalOnPage`) are replaced by: * `stats: signal<AdminAuditStats | null>` — filled by the `GET /api/admin/audit/stats` call. * `statsLoading` + `statsError` — own loading / error state, distinct from the table's so a failed stats call doesn't mask the table view. * `fetchStats()` — strips pagination from the filter shape, calls the new `AuditEventsService.stats()` method. Lazy fetch policy: * Default tab Table → no stats call on first render. Saves a DB round-trip when the admin only wanted to scan rows. * Switch to Charts → fetch stats if not already loaded. * Filter change (Apply / Reset / actor pivot) → invalidate stats (set to null). If Charts tab is currently active, re-fetch immediately. Otherwise wait for the user to open it. * Pagination (next / previous) → does NOT invalidate stats. The underlying filtered set is unchanged, so re-opening Charts after paginating is free. The Charts panel's note now reads "Aggregations are computed across the full filtered set (server-side), not just the events on the current page. Results are cached for 5 minutes per filter combination." — honest disclosure of the new scope + cache. Audit chunk: 84.5 KB gzip (essentially unchanged from #172's 84 KB; the tab markup + stats branch add ~50 LOC of plumbing offset by removal of the per-page aggregation computeds). audit.scss ticks up to 7.5 KB which exceeds the 6 KB warning threshold but stays under the 8 KB error threshold — acceptable for a single- PR add of the tab styling. Verification: * 62 portal-admin specs pass (was 57; +5 net: 7 new tabs / stats tests, 3 old per-page chart tests dropped, 1 prior test reframed). * `pnpm nx run-many -t lint test build --projects=portal-shell, portal-admin,shared-charts,portal-bff` — green.
Documentation index
This is the entry point to all project documentation. It is maintained automatically: any addition, rename, or removal of a .md file under docs/ must be reflected here in the same change.
Conventions
- Documentation is written in English.
- One topic per file. Group related files into a folder when there are three or more.
- Cross-reference with relative links so they keep working in GitHub, IDEs, and exported sites.
- For architectural decisions, do not add them here — they belong in decisions/ as MADR 4.0.0 ADRs.
Sections
Daily development
- development.md — repo layout, prerequisites, initial setup, daily commands, observability dev-loop (Jaeger UI, log ↔ trace correlation), dependency updates (Renovate), conventional commit cycle. Day-to-day reference for working on the project.
Architecture
- architecture.md — cross-cutting Mermaid diagrams: C4 system context, C4 containers, Nx module boundaries, CI/CD pipeline. Single-decision diagrams (auth sequence, ERD, etc.) live inline in their ADR.
Onboarding & environment
Setup guides for new contributors:
- setup/01-wsl-terminal-setup.md — modern WSL terminal (Zsh + Powerlevel10k + CLI tools)
- setup/02-dev-web-stack.md — Node via nvm, pnpm via corepack, Docker
- setup/03-angular-nx-monorepo.md — Angular + Nx monorepo bootstrap
Operations & runbooks
Empty — to be populated when we deploy.
Security, performance, accessibility
Empty — placeholders to be filled with rationale docs alongside their corresponding ADRs.
Description
Languages
TypeScript
85.3%
JavaScript
5.4%
SCSS
4.3%
HTML
3.9%
Shell
0.8%
Other
0.3%