Skip to content

ux(settings): expose updated_at + audit log for service overrides and configs #8

Open

Description

@cristim

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.ts and settings.test.ts assert 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

  1. IAmJSD commented on Oct 24, 2026

    @IAmJSD
    Collaborator

    Claiming: working on this

  2. self-assigned this
    on Oct 24, 2026
  3. IAmJSD commented on Oct 28, 2026

    @IAmJSD
    Collaborator

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions