feat(audit): per-record change-history endpoint (PMS-182) #154
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/pms-182-ticket-edit-history"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Adds a per-record change-history endpoint so the SPA detail pages can show an entity's edit history to any tenant member (not just admins). Backend half of PMS-182 (tickets), reused by PMS-184 (tasks) and assets.
Endpoint
GET /api/v1/audit-log/entity/{entity_type}/{entity_id}/audit-log(admin-only) exposes.tickets,tasks,projects,assets. Any other type is a404, so the endpoint can never be pointed at billing/auth trails.audit_logrows filtered byentity_id. The audit middleware writesentity_id-less rows on every mutation; those are naturally excluded, so only the explicit before/after snapshots (e.g.update_ticket'saudit_write) surface.Response
Each
EntityHistoryEntrycarriesaction,user_id,timestamp, andchanged_fields: the set of columns that differ between the before/after JSON snapshots, with bookkeeping noise (updated_at,created_at,id,tenant_id,last_updated_by_id) removed and sorted. So a client can render "Updated (description, status)" without parsing raw JSON.Tests
ticket_history_records_description_edit: create a ticket, PUT a new description, then assert the history endpoint returns anupdateentry whosechanged_fieldscontainsdescription, and that a non-whitelisted entity type returns404.🤖 Generated with Claude Code
Add GET /api/v1/audit-log/entity/{entity_type}/{entity_id}: a tenant-scoped, non-admin per-record change history derived from the existing audit_log. Unlike the admin-only /audit-log, this lets any authenticated tenant member review the edit history of a record they can already see, but only for a whitelist of entity types (tickets, tasks, projects, assets) so it never exposes the trail for sensitive entities, and an unknown type is a 404. Each entry carries the action, actor id, timestamp, and the set of changed columns (computed by diffing the before/after JSON snapshots and dropping bookkeeping noise like updated_at), so a detail page can render "Updated (description, status) by X" without parsing raw JSON. update_ticket already writes the before/after audit row this reads; the middleware's entity_id-less rows are naturally excluded by the entity_id filter. Backs the ticket description history in PMS-182 and is reused by PMS-184 (tasks) and assets. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>