dorfteich/docs/architecture/adr/0023-read-access-audit-trail.md
Claude Opus 5 fd07f716f6
All checks were successful
CI / Lint, typecheck, test (pull_request) Successful in 4m42s
CI / Build container images (pull_request) Successful in 1m11s
CI / Auth e2e pack (pull_request) Successful in 7m47s
CI / Import/export fidelity gate (pull_request) Successful in 55s
CD / Build and push images (push) Successful in 18s
CD / Deploy to Test (push) Successful in 14s
CD / Smoke tests against Test (push) Successful in 1m16s
CD / Promote to Int (push) Successful in 11s
CI / Lint, typecheck, test (push) Successful in 4m50s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 7m38s
CI / Import/export fidelity gate (push) Successful in 56s
docs: VS-NfD readiness planning (ist-aufnahme, plan, ADRs 0019-0026, issue drafts)
Add docs/vs-nfd/: the analysis brief, the as-is assessment (42 findings,
all verified against the code), the prioritized action plan rev. 2 with
issue references written back to every checkbox, the two-stage issue/ADR
brief, and the full reviewed draft used to create the forge state.

Add eight proposed ADRs 0019-0026 covering the VS-NfD architecture
decisions: no security base functions (par. 52 VSA anchor), HKDF token
key separation, external authentication, page classification, read-access
audit trail (variant A), reproducible offline deployment, plugin trust
model, and backup target restriction.

Forge state created alongside this commit: 11 labels, milestones M24-M31,
issues #188-#236 (docs-only change, no code touched).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168Ph5uBmHm8X28CSVpbpnJ
2026-07-30 01:48:05 +02:00

3.3 KiB
Raw Permalink Blame History

ADR 0023: Read-access audit trail limited to classified content

  • Status: proposed
  • Date: 2026-07-29

Context

The existing audit trail (audit_log, issue #86) is deliberately scoped to "who changed access or configuration", and its own service comment states that content activity stays log-only. There is no record of reads.

For "operable in an approved environment", read logging is not a mandatory product feature — evidence collection can be a platform function. In practice platform logging cannot answer the question that matters: a proxy log knows URLs, not classifications, so it cannot say which classified page was read. Leistungsbeschreibungen tend to list this as a must.

Two variants were considered. Variant B logs all reads (1820 AT) and brings volume, latency and retention problems, plus the requirement that no event may be lost. Variant A logs reads of classified pages only (810 AT).

A live editing session is the volume hazard: Yjs sync means continuous traffic per open document.

Decision

Variant A: read events are recorded only for pages with classification = VS_NFD. Requires ADR 0022.

  1. All read channels are instrumented, or the feature is worthless: SPA page fetch, public API GET, attachment download, export, no-JS shell, collab WS join.
  2. A dedup window (session + page + channel within N minutes = one event) keeps Yjs sync from flooding the trail. The recorded event states that it represents a window, so the evidence is not overread.
  3. Its own table, with time partitioning and its own retention period — independent of audit_log, because volume, purpose and legal basis all differ.
  4. Failure is not silent. AuditService swallows write failures by design; for classified reads a lost event is a gap in evidence, so the behaviour is either hard failure or an explicitly documented degradation. Which one is decided in #222 and stated in the security documentation.
  5. Switchable, with a written purpose limitation. Off means nothing is written anywhere; a startup log line states the trail is off so a gap is never ambiguous.
  6. Variant B is rejected, and the rejection is recorded rather than left open: unbounded volume, the no-loss requirement, and a purpose limitation that is much harder to defend.

Consequences

  • The scope limit is the feature's strongest argument in the works-council discussion at the customer: only classified content is observed.
  • Reads of unclassified content are not evidenced. Deliberate, and it goes into the residual-risk list.
  • The collab WS join is the awkward channel: authorization there is token-only (signature plus pageId match) and the collab server has no permission context. Either the event carries what the token asserts, or the api emits it at token issuance. #222 decides and documents; the choice affects what the trail can prove about live sessions.
  • Retention and partition maintenance are operational obligations that must ship with the feature, not after it.
  • Classification at read time is stored with the event: a later reclassification must not rewrite history.

Implementing issues

#222 (instrumentation), #223 (dedup window), #224 (table, retention, partitioning), #225 (switch + purpose limitation). Depends on #204/#205.