Commit Graph

3 Commits

Author SHA1 Message Date
4a8bb97764 feat: BindRequestLogContext middleware + X-Request-Id round-trip
WS-7 PR-2 commit 3. RFC §3.13.

- app/Http/Middleware/BindRequestLogContext.php: tags every Laravel log
  line written during the request with request_id, organisation_id,
  user_id, and route name. Sets X-Request-Id on the response so the
  SPA can correlate to backend log lines via one click.
- Client-supplied X-Request-Id is honoured only if it parses as a ULID
  via Str::isUlid. Junk input (empty, non-ULID) is rejected and a
  fresh ULID is generated server-side.
- Registered as a global api-group middleware via the prepend list so
  it runs before authentication. Unauthenticated 4xx responses still
  carry the X-Request-Id header.
- Test count: 1523 to 1532. Larastan clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:28:50 +02:00
b1d5bcda76 feat: BindSentryContext middleware + queue job attempt tagging
WS-7 PR-2 commit 2.

- app/Http/Middleware/BindSentryContext.php: sets RFC §3.6 tags on the
  active Sentry scope (app, http.method, route_name, actor_type,
  user_id, organisation_id, event_id, impersonation). Multi-tenant
  invariant: throws RuntimeException in local/testing when an auth
  request to a tenant-scoped route lacks organisation_id; logs a
  warning in production so the user flow still completes.
- app/Listeners/Observability/TagJobAttemptOnSentry.php: tags
  queue.attempt on the scope from the JobProcessing event. Default
  stack-trace grouping preserved per §3.11.
- ActorType: VOLUNTEER case reserved for a future role split. Current
  resolver maps non-admin authenticated users to ORG_MEMBER.
- bootstrap/app.php: registers sentry.context alias. Applied inside
  auth:sanctum groups in routes/api.php so it runs after auth.
- AppServiceProvider::boot registers the queue listener.

Test count: 1507 to 1523. Larastan clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:13:55 +02:00
bdb89a2479 feat: sentry-laravel install + scrubber + ignored exceptions
WS-7 PR-2 commit 1. Wires sentry-laravel into the app behind a
config-only no-op when SENTRY_DSN_BACKEND is empty (RFC §3.3).

- composer require sentry/sentry-laravel ^4.15 (resolved 4.25.1)
- config/sentry.php: DSN env mapped to SENTRY_DSN_BACKEND, environment
  falls back to APP_ENV, traces/profiles forced to 0.0 (RFC §2
  amendment B), send_default_pii hard-pinned false, before_send to
  SentryEventScrubber, ignore_exceptions covers ValidationException /
  AuthenticationException / AuthorizationException.
- app/Services/Observability/SentryEventScrubber.php: recursive body /
  header / query-string scrubber + form_values wholesale replacement +
  HttpException sub-500 drop (status filter that ignore_exceptions
  cannot do class-only). Max-depth guard against malicious payloads.
- app/Enums/Observability/ActorType.php: enum + resolver for §3.6
  actor_type tag (consumed by BindSentryContext in commit 2).
- tests/Feature/Observability/PiiScrubbingTest.php: 20 cases.
- api/.env.example: SENTRY_DSN_BACKEND + SENTRY_RELEASE entries.

Larastan: clean. Test count: 1487 to 1507.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 08:55:50 +02:00