Skip to content

Add structured request logging and submission provenance#52

Merged
koinsaari merged 3 commits intomainfrom
feature/request-logging-provenance
May 2, 2026
Merged

Add structured request logging and submission provenance#52
koinsaari merged 3 commits intomainfrom
feature/request-logging-provenance

Conversation

@koinsaari
Copy link
Copy Markdown
Contributor

Summary

Two independent features implementing observability and accountability for writes.

Structured request logging (#15)

  • New RequestLogger HTTP middleware wraps the entire handler chain
  • Every request logs: method, path, status, latency_ms, ip, request_id, api_key_id
  • UUIDv4 request IDs generated server-side, returned as X-Request-ID header
  • Log level adapts to status: Info (2xx/3xx), Warn (4xx), Error (5xx)
  • API key DB ID (not the raw key or hash) is injected into the log line by the auth layer via a mutable context carrier — no extra DB lookup needed
  • Fixes integration test wait strategy: wait.ForSQL was polling Docker API per retry and hitting context deadline; replaced with ForAll(ForLog, ForListeningPort)

Submission provenance + write audit log (#11)

  • submitted_by (UUID FK to api_keys, internal-only, never in JSON) and submitted_at (timestamp, exposed read-only in responses) on both Place and AccessibilityProfile
  • Auto-populated from the authenticated API key on every write — never client-submitted
  • New write_logs table: append-only row per create/update with table name, record ID, API key ID, and action; indexed on record_id and api_key_id for investigations
  • Audit failures are warn-logged but never propagate — they cannot block writes
  • Migration 000005 adds the new columns and write_logs table
  • OpenAPI spec updated with submitted_at as readOnly on both schemas

Closes #15
Closes #11

@koinsaari koinsaari force-pushed the feature/request-logging-provenance branch from f7b400f to d9b7238 Compare May 2, 2026 16:39
koinsaari added 2 commits May 2, 2026 19:53
- Add RequestLogger HTTP middleware: logs method, path, status,
  latency_ms, ip, request_id, api_key_id on every request
- Generate UUIDv4 request IDs, expose as X-Request-ID response header
- Add mutable logFields carrier in context so auth layer can enrich
  the log line with the API key ID after the fact
- Add APIKeyID context helpers (WithAPIKeyID, APIKeyIDFromCtx)
- Enrich request context in authenticate() with resolved API key ID;
  sets both the log carrier and the provenance context key in one pass
- Fix integration test wait strategy: replace wait.ForSQL (which polls
  Docker API per-attempt and times out) with ForAll(ForLog, ForListeningPort)
- Add submitted_by (UUID, internal-only) and submitted_at (exposed
  in responses) to Place and AccessibilityProfile models
- submitted_by is auto-populated from the authenticated API key ID;
  never client-submitted, never serialised to JSON
- Add migration 000005: submitted_by/submitted_at columns on both
  tables plus the write_logs audit table
- Add internal/audit package: append-only write_logs entries on every
  create/update; failures are warn-logged but never block the write
- Wire RequestLogger into the outer handler in main.go
- Update OpenAPI spec: submitted_at as readOnly date-time on Place
  and AccessibilityProfile response schemas
@koinsaari koinsaari force-pushed the feature/request-logging-provenance branch from d9b7238 to 8ea2ded Compare May 2, 2026 16:54
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by Claude review — no must-fix issues found.

claude-code-action does not support workflow_run events — it requires
pull_request context (github.event.pull_request.number) to interact
with PRs. Switch back to pull_request trigger with track_progress
enabled, which is the officially supported configuration.

Remove the auto-approve step since GITHUB_TOKEN cannot approve PRs
from workflows it triggered.
@claude
Copy link
Copy Markdown

claude Bot commented May 2, 2026

Review Summary

No must-fix issues found. The PR looks good to merge.

Both features (structured request logging and submission provenance) are correctly implemented:

  • Provenance fields are server-controlled: submitted_by is tagged json:"-" (never deserialized from client input) and submitted_at is always overwritten server-side before persistence — client-supplied values are ignored even if submitted.
  • Mutable log context carrier is correct: The logFields pointer stored by RequestLogger is shared across derived contexts, so SetLogAPIKeyID called from the auth layer is visible to the logger after ServeHTTP returns. The mutex is properly scoped.
  • Audit non-blocking by design: audit.Log is called after successful DB writes and failures are warn-logged only — consistent with the stated design intent.
  • Context enrichment in auth.go: *req = *req.WithContext(enriched) correctly propagates the API key ID for downstream handler access via APIKeyIDFromCtx, while SetLogAPIKeyID separately populates the log carrier through the shared pointer.
  • No FK constraints on provenance columns: Intentionally omitted to preserve audit history when API keys are deleted — correct for this use case.
  • ForLog(...).WithOccurrence(2) wait strategy: Valid for the official PostgreSQL Docker image, which logs this message twice (once on init, once after the internal restart). Resolves the previous context-deadline issue.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by Claude review — no must-fix issues found.

@koinsaari koinsaari merged commit 28174e7 into main May 2, 2026
7 of 8 checks passed
@koinsaari koinsaari deleted the feature/request-logging-provenance branch May 2, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add structured request logging middleware Add submission provenance to writes

1 participant