Stratify
Legal and compliance

Logging, Monitoring & Alerting Procedure

docs/compliance/isms/procedures/PRO-12-logging-monitoring-alerting.md

Source updated 03. Aug. 2026

Logging, Monitoring & Alerting Procedure

Documents what stratify actually captures today, where it's reviewed, and — honestly — that no alerting rule or on-call process exists anywhere in the repo. This procedure both documents the current state and proposes the minimum next step, marked clearly as proposed, not implemented.

1. What is captured today

  • Sentry — server-side only. apps/web/instrumentation.ts initializes Sentry for the Node

runtime with tracesSampleRate: 0.1. No client/browser Sentry init exists (no sentry.client.config.ts in the repo) — front-end JavaScript errors are not captured. This is a real visibility gap, not a deliberate scoping decision documented anywhere.

  • PostHogapps/web/lib/posthog/client.ts. EU region (eu.i.posthog.com), `autocapture:

false, events fired explicitly, identify() called only post-sign-up. This is a privacy-conscious configuration (matches dsgvo-data-flow.md` §9) but also means PostHog is not a general-purpose security telemetry source — it captures product events, not security-relevant activity.

  • Postgres/audit_log — every elevated write in the admin surface calls recordAudit(), and the

chain-hash mechanism (apps/web/lib/audit/chain.ts) makes the log tamper-evident. This is a log in the ISO 27001 sense (8.15) even though it is not routed anywhere for alerting.

  • CI logs.github/workflows/dos-ci.yml run history is retained by GitHub Actions and covers

lint, typecheck, test, secret-scan, and build outcomes for every PR.

2. Where this is reviewed today

Ad hoc. Toby checks the Sentry issues dashboard and the PostHog dashboard when something looks wrong (a user report, a deploy that feels risky) or occasionally out of habit — there is no defined cadence, no checklist, and no second person who reviews independently. This is stated as what it is: a real, current gap, not something covered by an unwritten process. There is no on-call process, rotation, or paging mechanism of any kind — appropriate for a single-engineer team in the sense that there is nobody to page, but that also means there is no guarantee an incident is noticed promptly outside of Toby actively looking or a user reporting it.

3. Confirmed absent: alerting rules

Checked directly: no alerting-rule configuration exists anywhere in the repository — no Sentry alert rules committed as config, no PostHog alert/insight-threshold definitions, no Postgres-level notification triggers, no external monitoring service wired to page anyone. If alert rules exist at all, they would have to live in a dashboard outside the repo (Sentry's or PostHog's own UI) — this procedure does not assume they do, since nothing in-repo confirms it either way, and that absence of evidence is itself the gap worth naming (register/facts.md, "Logging / monitoring").

4. Minimum starting procedure — proposed, not yet implemented

Two alerts are proposed as the first, minimum-viable alerting surface, chosen because they map directly onto stratify's two most compliance-critical structural controls:

  1. Repeated `audit_log_no_mutate()` trigger violations. This Postgres trigger

(supabase/migrations/0001_init.sql:124-154) raises an exception on any UPDATE/DELETE attempt against audit_log. A single violation could be a bug; repeated violations in a short window would indicate an attempted tamper against the compliance-critical audit trail — exactly the P0 scenario docs/runbooks/db-recovery.md §3.3 already has a response runbook for, but no detection trigger feeding into it. Proposed mechanism: a scheduled job that tails the Postgres error log on the Hetzner host for the trigger's raised exception message, and on more than N occurrences in a rolling window, sends a notification (email or a webhook to a channel Toby and Antonios both see). Not yet built.

  1. Erosion of the required CI check. The verify check in .github/workflows/dos-ci.yml is the

one structural gate protecting every merge to main (lint, typecheck, test, secret-scan, build). If branch protection is loosened or the check is removed as required, that gate silently stops protecting anything. Proposed mechanism: either a GitHub webhook on branch-protection-rule changes, or a periodic scripted check (gh api repos/.../branches/main/protection) comparing the live configuration against the expected one and alerting on drift. Not yet built.

Both are explicitly proposed next steps, not existing controls — do not represent either as implemented in register/controls.yaml or the Statement of Applicability until the mechanism actually runs and has been observed to fire correctly at least once.

5. Minimum recurring review, until real alerting exists

Until §4 is built, the interim mitigation is a named, dated weekly check rather than purely reactive dashboard glances: once a week, review the Sentry issues list and the PostHog dashboard for anything anomalous, and separately confirm (visually, in GitHub) that branch protection on main still requires the verify check. This does not close the gap in §3/§4, but it converts "nobody is looking unless something breaks visibly" into a minimum standing cadence.

6. Evidence this procedure produces

  • Once §4 is implemented: alert-fire records (timestamp, trigger, and the response taken).
  • Until then: a dated note each time the weekly check in §5 is performed, kept under

docs/compliance/isms/evidence/ — this is thin evidence, but it is honest evidence of a real cadence rather than an unverifiable claim of continuous monitoring.

7. Review

Reviewed annually and immediately upon standing up either proposed alert in §4, at which point this procedure should be rewritten to describe it as implemented rather than proposed.