Skip to content

Phase 21 — Engagement archive

Last updated: 2026-05-08

After the partner has marked an engagement delivered to client (Phase 20), they often want it out of the active workspace — clutter accumulates fast at 50+ engagements/year. Phase 21 adds archive/unarchive transitions and a list filter so the default view shows only what's still in flight.

Archive is a presentation concern, not data deletion. Findings, audit logs, deliverables, and S3 artifacts are all preserved; the engagement just doesn't surface in the default list. Admin can unarchive any time.

Endpoints

POST /auditforge/engagement/{id}/archive    # admin only; requires status=delivered
POST /auditforge/engagement/{id}/unarchive  # admin only; restores to delivered
GET  /auditforge/engagement?include_archived=true  # opt-in to see archived

archive

Admin role only. Engagement must be in delivered state (Phase 20). Returns 409 LOCKED on a non-delivered engagement; 200 with already_archived: true if already archived.

{
  "ok": true,
  "engagement_id": "eng-...",
  "status": "archived",
  "already_archived": false
}

unarchive

Admin role only. Transitions from archived back to delivered. The engagement is still frozen for finding mutations — unarchive doesn't unfreeze. To allow further edits, call /unfreeze separately.

{
  "ok": true,
  "engagement_id": "eng-...",
  "status": "delivered",
  "was_archived": true
}

List filter

The existing GET /auditforge/engagement now accepts include_archived=true (default false). Response includes the flag value back so the client can surface "showing archived" hints in the UI.

State machine

created → ... → findings_review → delivered → archived
                                       ↑           ↓
                                      ───── unarchive ─────
State List default Mutations
created → findings_review shown allowed
delivered shown blocked (frozen)
archived hidden blocked (frozen)

Unfreeze (Phase 20) and unarchive (Phase 21) are independent admin actions. Typical recovery flows:

  • Need to correct a delivered engagement: unfreeze → edit → re-deliver
  • Need to declutter: archive
  • Need to revisit an archived engagement: unarchive (still frozen — view-only)
  • Need to correct an archived engagement: unarchiveunfreeze → edit → re-deliver → re-archive

UX

  • Engagement list: a Include archived checkbox next to "+ New engagement" reveals archived engagements
  • Engagement detail header (when frozen): an extra Archive or Unarchive button next to Unfreeze

Why admin-only

Archive is reversible but consequential — a careless partner archiving the wrong engagement could confuse downstream reporting. Archive is rare enough (post-delivery housekeeping) that requiring admin authorization is low friction. Future polish: per-firm "auto-archive after 90 days delivered" admin setting.

Files

  • app/auditforge_endpoints.pyPOST /engagement/{id}/archive and /unarchive; include_archived query param on list
  • frontend/src/api/auditforge.tsarchiveEngagement, unarchiveEngagement, listEngagements(firmId, includeArchived)
  • frontend/src/components/EngagementList.tsx — Include-archived checkbox
  • frontend/src/components/EngagementDetail.tsx — Archive / Unarchive buttons
  • tests/test_auditforge_endpoints.py — 9 endpoint tests covering auth/role gating, state-machine invariants, list filter, idempotent paths

Audit trail

Each transition writes a structured warning log:

auditforge_engagement_archived | id=eng-abc by_user=admin-token
auditforge_engagement_unarchived | id=eng-abc by_user=u-xyz

Greppable in CloudWatch alongside the deliver/unfreeze events from Phase 20 for full chain-of-custody enumeration.