Files
SluijsensandClaude Opus 5 357d395629 Designs the security headers and observability units
Records the functional design for the two remaining application units,
before any of their code exists.

Security headers have to come from the application, because relying on
nginx or IIS configuration is exactly what this deployment model rules
out. Strict applies to /admin, /api/v1 and /health; a relaxed policy
applies to the public website, which this repository does not author.

The strict policy needs style-src 'unsafe-inline'. That is not a
shortcut: Radix positions dropdowns and dialogs with inline style
attributes recalculated per click and scroll position, and CSP nonces
apply only to style elements, never to style attributes. No nonce- or
hash-based variant leaves the admin UI working. The exception is bounded
to styles — script-src stays closed, which is where XSS actually lives.

The website's policy is enforcing rather than absent, so every
HTML-serving path carries a CSP and no exception has to be recorded. It
still blocks external script origins, so it remains a real boundary.

HSTS is skipped in development: browsers remember it per host and
localhost is shared with unrelated projects. Every other header applies
locally, so a CSP violation surfaces while developing.

For observability, browser error reports tunnel through the API rather
than going to Sentry directly. Ad blockers block Sentry domains, which
loses errors precisely for the users most likely to have browser
oddities. The tunnel forwards only to the host derived from the
configured DSN — a caller-supplied destination would turn an anonymous
endpoint into a request-forgery primitive.

Two consequences of the chosen options are recorded rather than left
implicit:

Enabling SendDefaultPii attaches request headers, and this application
carries two standing credentials in them. Besides the refreshToken
cookie, X-Master-Api-Key would have been sent to a third party on every
error raised during a master/slave call. The scrub list removes the
whole Cookie header, Authorization, X-Master-Api-Key and the request
body.

Console logging at Information plus structured logging to Sentry would,
taken literally, mean one Sentry event per request — exhausting the free
plan within hours and burying real errors in request noise. The
thresholds are split: console keeps Information, Sentry takes warnings
and above as events with Information as breadcrumbs, so every event
arrives carrying the trail that led to it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHoJpxYXzHACSQguHrC5fw
2026-07-28 00:01:04 +02:00

2.5 KiB

Functional Design Plan — U4 Observability Integration

Unit: U4 Observability Integration Round: R2 (with U3 Security Headers & CSP) Requirements: FR-13, FR-14, FR-15, FR-16, FR-19 Components: C-08, C-09, C-14, C-15, U4 portion of C-16

Scope boundary: this stage designs behaviour — what is reported, when, and what happens when a service is absent or unreachable. The pattern decisions (structured-log shape, correlation-ID mechanism per OPEN-01, alert-rule design) belong to this unit's NFR Design, which follows.


Step 1: Analyze unit context

  • Read the U4 definition from unit-of-work.md
  • Read FR-13 through FR-16 and FR-19 from requirements.md
  • Read the reference project's Sentry and Umami implementation for the frontend
  • Note the coupling to U3: the origins this unit introduces must be permitted by U3's CSP

Step 2: Design backend error and log reporting

  • Define behaviour when no Sentry DSN is configured
  • Define behaviour when Sentry is configured but unreachable
  • Define what is sent and what is deliberately withheld — see Question 2
  • Define the production log level — see Question 3
  • Define environment and release tagging

Step 3: Design security event emission

  • Define which events are emitted for alerting — see Question 4
  • Define what context each event carries, and what it must never carry
  • Confirm no event carries a password, token or PII

Step 4: Design frontend observability

  • Define Sentry initialisation and the absent-DSN path
  • Define the transport route to Sentry — see Question 1
  • Define Umami inclusion behaviour and its absent-configuration path — see Question 5
  • Define behaviour in local development

Step 5: Design the same-origin API base URL

  • Define resolution when VITE_API_BASE_URL is absent or empty
  • Define resolution when an explicit absolute URL is supplied
  • Define validation behaviour for a malformed value
  • Confirm the local master and slave development setups keep working

Step 6: Define business rules

  • Enumerate reporting rules
  • Enumerate degradation rules
  • Enumerate configuration-resolution rules
  • Identify error and edge-case scenarios

Step 7: Generate artifacts

  • Generate business-logic-model.md
  • Generate business-rules.md
  • Generate domain-entities.md
  • Generate frontend-components.md
  • Validate all diagrams against the Mermaid standards
  • Verify Security Baseline compliance for this unit's design