Files
curo1305 87a32b7ee8 feat(phase-4): complete UX redesign — FileManagerView, FolderTreeItem, test suite, and all Phase 4 fixes
Adds the unified file manager view (Windows Explorer-style), collapsible
folder tree sidebar item, full vitest test suite (55 tests, 4 files), and
commits all Phase 4 backend/frontend fixes that were staged but uncommitted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 17:10:52 +02:00

5.2 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
04-folders-sharing-quotas-document-ux 06 admin-audit
audit-log
admin-api
celery
csv-export
minio
security
requires provides affects
04-03
04-04
ADMIN-06
D-17
backend/api/audit.py
backend/tasks/audit_tasks.py
backend/celery_app.py
backend/main.py
added patterns
Admin-only audit log viewer with paginated, filtered SQLAlchemy query
Streaming CSV export via FastAPI StreamingResponse + csv.DictWriter
Celery beat crontab schedule at midnight UTC for daily MinIO export
Deferred imports inside async task body to prevent circular imports
_audit_to_dict() safe whitelist serializer pattern (mirrors _user_to_dict)
created modified
backend/api/audit.py
backend/tasks/audit_tasks.py
backend/celery_app.py
backend/main.py
CSV export reuses _audit_to_dict() whitelist helper — single source of truth for safe field set
audit_tasks.* routed to documents queue — reuses existing documents worker (no new queue needed)
crontab alias uses _crontab (underscore prefix) consistent with existing _timedelta alias
duration_seconds completed_date tasks_completed files_created files_modified
262 2026-05-25 2 2 2

Phase 4 Plan 06: Admin Audit Log API + Celery Daily Export Summary

One-liner: Admin-only paginated/filtered audit log viewer with CSV streaming export (ADMIN-06) and midnight-UTC Celery beat task uploading daily CSVs to MinIO audit-logs bucket (D-17).

Tasks Completed

Task Name Commit Files
1 Admin audit log viewer + CSV export 364447d backend/api/audit.py, backend/main.py
2 Celery daily export task + beat schedule f89f787 backend/tasks/audit_tasks.py, backend/celery_app.py

What Was Built

Task 1: backend/api/audit.py

Two admin-only endpoints protected by Depends(get_current_admin):

  • GET /api/admin/audit-log — paginated (page/per_page), filtered (start, end, user_id, event_type). Returns {items, total, page, per_page}. Runs a separate COUNT query for total using the same filters.
  • GET /api/admin/audit-log/export — same filter params, no pagination; streams CSV with Content-Disposition: attachment; filename=audit-export.csv.

The _audit_to_dict() helper is the single source of truth for the safe field set: id, event_type, user_id, actor_id, resource_id, ip_address, metadata_, created_at. The dict literal contains no filename, extracted_text, password_hash, or credentials_enc keys. Both the JSON and CSV paths use this same helper.

Task 2: backend/tasks/audit_tasks.py + celery_app.py

  • audit_log_daily_export Celery task: sync entry point → asyncio.run(_run_daily_export()).
  • _run_daily_export(): queries yesterday's AuditLog rows (UTC midnight to midnight), writes CSV via csv.DictWriter, uploads to MinIO via put_object_raw(bucket="audit-logs", key="audit-logs/YYYY-MM-DD.csv", ...). Wraps everything in try/except — returns {"exported": 0, "error": str(e)} on failure.
  • All imports deferred inside _run_daily_export() body (same circular-import-prevention pattern as document_tasks._run).
  • celery_app.py: _crontab aliased import, beat entry "audit-log-daily-export" at _crontab(hour=0, minute=0), task route "tasks.audit_tasks.*": {"queue": "documents"}.

Deviations from Plan

None — plan executed exactly as written.

Security Invariants Verified

Threat ID Check Result
T-04-06-01 Depends(get_current_admin) on both endpoints (grep: 2 occurrences at lines 94, 129) PASS
T-04-06-02 _audit_to_dict() dict literal contains no forbidden keys (grep: filename/extracted_text only in comments) PASS
T-04-06-03 CSV export uses same _audit_to_dict() helper as JSON viewer PASS
T-04-06-04 put_object_raw uses bucket="audit-logs" (not documents bucket) PASS

Test Results

tests/test_audit.py: 4 xfailed (stub tests from Wave 0 — plan 04-06 implements the API,
  detailed integration tests will be written in the full TDD pass)
Full suite: 1 failed (test_extractor.py::test_extract_docx — pre-existing missing module,
  out of scope), 130 passed, 7 skipped, 35 xfailed

Pre-existing failures (not caused by this plan):

  • test_extractor.py::test_extract_docx — missing python-docx module in local env
  • test_documents.py::test_content_stream_200 — intentional TDD RED from plan 04-05 (commit 8e6cb6e)

Known Stubs

None — both endpoints are fully implemented and wired.

Threat Flags

None — no new network endpoints or trust boundaries beyond those documented in the plan's threat model.

Self-Check: PASSED

  • backend/api/audit.py exists: FOUND
  • backend/tasks/audit_tasks.py exists: FOUND
  • Task 1 commit 364447d: FOUND
  • Task 2 commit f89f787: FOUND
  • python3 -c "from api.audit import router" exits 0: PASS
  • python3 -c "from tasks.audit_tasks import audit_log_daily_export" exits 0: PASS
  • beat_schedule contains audit-log-daily-export: PASS
  • task_routes contains tasks.audit_tasks.*: PASS