6.1 KiB
Audit Log Manager — Implementation notes (review & debug)
This document describes the Audit Log Manager delivered in this repo: database schema, backend recording, admin API, frontend layout, and how to verify end-to-end (Postgres, API, MinIO).
1. Database
- Migration:
be0/migrations/008_audit_events.sql- Creates PostgreSQL enum
audit_actionand tableaudit_events(append-only by convention). - Indexes: actor+time, entity+time, action+time, GIN on
metadata.
- Creates PostgreSQL enum
Apply (example against local Docker Postgres — adjust connection):
psql "$INITIATIVE_DATABASE_URL" -f be0/migrations/008_audit_events.sql
(INITIATIVE_DATABASE_URL is typically postgresql://… for psql; the app uses SQLAlchemy async URL like postgresql+asyncpg://….)
Docker Compose mounts 008_audit_events.sql into docker-entrypoint-initdb.d for new databases only. Existing initiative_pg_data volumes still need the psql -f …/008_audit_events.sql step once.
2. Backend model & helpers
| Piece | Path |
|---|---|
| ORM model | be0/src/initiative_db/models.py — AuditEvent |
| Helpers | be0/src/audit.py — record_audit, persist_audit_standalone, resolve_actor_fields |
await record_audit(session, …)— insert via a SAVEPOINT: ifaudit_eventsis missing (migration not applied), logs a warning and does not roll back the parent transaction (so login/register still succeed).await persist_audit_standalone(…)— own session +commit; same missing-table handling without raising.
3. Where events are written
| Area | Actions / entity_type | Notes |
|---|---|---|
| Auth | register → create / user |
Same transaction as user + roles |
| Auth | OK login → login / auth |
|
| Auth | Bad login → login_failed / auth |
Standalone insert after failed credentials |
| Auth | Valid Bearer logout → logout / auth |
Standalone; skipped if JWT does not decode |
| Auth | Profile patch → update / user |
Before/after: fullName, phone |
| Auth | Password change → update / user |
Snapshots `{ password: "[redacted |
| Drafts autosave | update / application_draft |
When owner_id is known (authenticated saves) |
| MinIO evidence | create/update/delete / application_evidence |
After DB + object write/delete in main.py |
| Staff evidence review | update / application_evidence_review |
Admin adjudication (application_admin_results.py):
create/application_admin_resultupdate/ …upsert→createorupdatedepending on prior rowdelete— requiresactor_user_id;delete_admin_result(..., actor_user_id=…)called frommain.py
Legacy table audit_log (draft telemetry) remains unchanged.
4. Admin HTTP API
- JWT decode for admin routes (
decode_bearer_token,decode_access_token_user_id) lives inbe0/src/auth_jwt.pyso audit routes do not pull in Argon2 at import time. - Router:
be0/src/admin_audit_routes.py, mounted inmain.pyas/api/v1/admin. GET /api/v1/admin/audit— list (admin JWT only).- Default window: now − 7 days → now if
from/toomitted. - Query params:
from,to,actor_user_id,actor_email(exact, lowercased)entity_type,entity_id,action(comma-separated),request_id,page,page_size(≤ 100),sort(occurred_at:asc|desc).
- Default window: now − 7 days → now if
GET /api/v1/admin/audit/{id}— full row incl.before/afterJSON.
Non-admin receives 403.
5. Frontend
| Layer | Path |
|---|---|
| Shared types + API client | fe0/src/audit/ |
| Admin UI | fe0/src/admin/audit/ — AuditLogManagerPage, filters, table, detail Sheet |
| Applicant-side copy (reuse) | fe0/src/applicant/audit/actionLabels.ts — Vietnamese labels for actions |
| Nav | fe0/src/components/admin/DashboardSidebar.tsx (+ duplicate DashboardSidebar.tsx) — « Nhật ký Audit » → /dashboard/admin/audit |
| Routes | fe0/src/App.tsx — admin/audit before admin nested under dashboard |
Detail panel loads /api/v1/admin/audit/{id} and runs microdiff on the client only (see audit/jsonMicrodiffLines.ts), per architecture doc.
Dependency: microdiff (added to fe0/package.json).
6. Debugging checklist
- 500 on
/auth/loginafter adding audit — Postgres log / SQLAlchemy showedrelation "audit_events" does not exist: apply migration008. Until then,record_auditskips the insert and auth still works. ECONNREFUSEDfromfe0to:4402— API not listening yet (be0still on NLTK pip, or old entrypoint failed onollama: command not found). Rebuildbe0; entrypoint now skips Ollama when the binary is absent. Wait forUvicorn running on http://0.0.0.0:4402before logging in.- Table missing / Admin audit 503 — run migration
008_audit_events.sql. - Empty list but events expected — check
from/to; default is last 7 days on the API. - 403 on
/api/v1/admin/audit— JWT must includeadmininroles(same as other admin APIs). - Failed-login rows missing — must use
persist_audit_standalonepath; if Postgres URL wrong, standalone insert is skipped (is_postgres_enabled()). - MinIO uploads without audit rows — evidence handler must reach
upsert_evidence_artifactafter successfuls3.upload; failures before that do not audit. - Comment typo broke build once —
formatAuditTime.tsJSDoc used invalid**/”sequence; stick to*/closing block comments.
7. Suggested verification flow
- Apply migration → restart API.
- Register / login → see
create/loginrows (filteraction=login,create). - Save applicant draft tab →
application_draft. - Upload evidence with MinIO configured →
application_evidencewithmetadata.minioBucket. - Open
/dashboard/admin/auditas admin → pagination + row click opens JSON + microdiff.
8. References
- Spec:
assets/docs/audit-log-implementation.md - Product plan:
docs/audit-log-manager-plan.md