Repository navigation
ux(settings): expose updated_at + audit log for service overrides and configs #8
Description
Summary
account_service_overrides carries created_at and updated_at columns (from migration 000011_cloud_accounts.up.sql:78), and the same is true for cloud_accounts, service_configs, and most other config-bearing tables. No UI surfaces these timestamps, and there's no broader audit trail capturing who made which change, when, and what they changed it from.
For users in compliance-aware environments (SOC 2, ISO 27001, internal change management), this absence is a real gap: every settings change is anonymous and undated from the user's perspective. The data is there for the most recent edit; older edits are overwritten.
Two layers of work
This issue is a placeholder — actual implementation is non-trivial and the priority depends on customer demand. Two stages, in dependency order:
Stage 1: Surface existing timestamps (cheap)
In the override-row table (loadOverridesPanel in settings.ts), add a small "Last updated: 2026-04-27 12:34 UTC" line below the row's other fields, sourced from updated_at on AccountServiceOverride. The data already comes back over the wire — internal/api/handler_accounts.go:listAccountServiceOverrides returns the full row.
Same treatment for service config rows in Settings → Purchasing (their last-touched timestamps would help users debug "why did my settings change?").
Stage 2: Real audit log (substantial)
Add a config_audit_events table that records (actor_user_id, action, target_table, target_id, before_jsonb, after_jsonb, occurred_at) rows for every CREATE / UPDATE / DELETE on service_configs, account_service_overrides, cloud_accounts, purchase_plans, etc. Hook the writes via DB triggers or via the API handlers (the latter is more controllable; the former is more complete because direct-DB edits get captured).
Plumb a "View history" UI per row that opens a modal listing the events, with the ability to view diffs.
Why now
This is the kind of gap that's invisible until a customer specifically asks for it, then it's blocking. Stage 1 is cheap and unblocks the most common request ("when was this last changed?"). Stage 2 should be deferred until a paying customer asks for SOC 2-grade audit.
Acceptance criteria
Stage 1 (this issue's V1)
- Override rows show
Last updated: <timestamp>(or similar). - Service config rows in Settings → Purchasing show the same.
- Tests in
settings-accounts.test.tsandsettings.test.tsassert the timestamp is rendered when the API returns it.
Stage 2 (follow-up issue under this umbrella)
- New audit table + migration.
- Per-row history modal.
- API endpoint to fetch events for a target.
- Filtering / search.
Out of scope
- Capturing API-key-based changes (vs UI-session-based) — needs a clear actor-identity model.
- Retention policy for audit events.
- Audit events for deletes that include the deleted row's full state in
before_jsonb.
Activity
IAmJSD commentedon Oct 24, 2026
Claiming: working on this
feat(frontend): show when each account service override was last upda…
Merge remote-tracking branch 'origin/main' into ui/issue-613
feat(config): expose created_at/updated_at on service config rows (#1562
IAmJSD commentedon Oct 28, 2026
Status update (2026-10-28): Stage 1 backend merged in #1562: service config rows now return read-only
created_at/updated_at, and the save returns the stamps it wrote.Left: showing the stamp on Purchasing service-config rows (UI owner). Stage 2 (audit log endpoint and history UI) waits on a customer ask, as the issue says.