875d61d858287ef8b9b9cbc6fc886dd8067d2ede
CI / scan (pull_request) Successful in 4m45s
CI / commits (pull_request) Successful in 4m46s
CI / check (pull_request) Successful in 5m12s
CI / a11y (pull_request) Successful in 4m19s
Docs site / build (pull_request) Successful in 5m38s
CI / perf (pull_request) Successful in 9m8s
PR 1 of the tabs + full-result charts chantier. New BFF endpoint
that powers the upcoming "Charts" tab on portal-admin's /audit page
with aggregations computed over the FULL filtered set rather than
the paginated slice that currently feeds the charts.
New route: GET /api/admin/audit/stats
* Same query DTO shape as /audit (AdminAuditStatsQueryDto)
minus pagination — stats endpoint always aggregates the whole
filtered set.
* Returns three projections:
- dailyVolume: [{day: 'YYYY-MM-DD', count}]
- outcomeBreakdown: [{outcome, count}]
- eventTypeByDay: [{day, eventType, count}]
+ total (sum of dailyVolume.count) for the donut centre label.
* Time bound: respects filters strictly (per chantier brief). No
filter → aggregates across the full audit retention (365 days
per ADR-0013). The Redis cache below absorbs repeated heavy
queries.
New service: AuditStatsReader
* Same role-locking posture as AuditReader — every query inside
a transaction that opens with SET LOCAL ROLE audit_reader.
SELECT-only on audit.events even if the BFF connection is
otherwise privileged.
* Parameterised SQL only. Filter values flow through positional
parameters, never concatenated into the SQL string.
* Three GROUP BY queries scoped by the same WHERE clause as the
list endpoint's buildWhere (kept structurally in sync by
convention, not extracted yet because the two readers'
pagination shapes differ).
Redis cache: 5-min TTL per filters-hash
* Cache key = `audit:stats:` + sha256(canonical-JSON of filters)
truncated to 16 hex chars. Sorted-keys canonicalisation so the
same filters in different argument orders map to the same
key.
* Cache writes are best-effort — Redis-write failure does not
fail the response. The DB read already happened.
* Spec covers: cache-hit path skips DB, cache-key stability across
key ordering, write happens with EX 300, write failure tolerance.
Audit event: admin.audit.stats.query
* New typed AuditWriter method (mirrors adminAuditQuery but
captures `total` instead of `resultCount` — stats responses
don't paginate, the value carries more "size of scan" signal).
* Emitted on every stats call per ADR-0020's read-deterrence
posture. Distinct event_type from admin.audit.query so an
auditor can spot "scanned aggregations" vs "paged through
rows" — different observation signals.
ADR-0013 amended (light): new "Reader endpoints" subsection
documents the two-endpoint reader surface + Redis cache caveat.
The events table grows four rows it was previously missing
(admin.access_denied, admin.audit.query, admin.audit.stats.query,
admin.users.query).
Verification:
* 414 portal-bff specs pass (was 401; +13: 8 service-level + 5
controller-level).
* `pnpm nx lint test build --projects=portal-bff` — green.
PR 2 (SPA) lands next: Tabs UX (Table / Charts) + replaces the
client-side per-page computeds with consumption of this endpoint.
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%