Close + archive — the 7-year SHA-256 vault
Final step of every engagement. The job locks read-only, the audit-evidence file is packaged into a SHA-256-verified ZIP, the archive is replicated off-site, and a retention timer kicks in for 7 years per ISA 230 + Oman OAAA.
What "close" actually does
For a full audit walkthrough of the closing acts (sign, issue, lock, archive) see Phase 13 of the audit manual. Here's the job-mechanics view:
Pre-flight checks
System verifies: status=completed, all tasks done|skipped, all workpapers EQCR-signed (audit only), audit report PDF present, issuance email sent. Failure = explicit blocker list shown.
Build archive ZIP
VaultBackupService::buildArchive($jobId)walks every related table, exports artefacts as PDF, packages the folder structure, computes SHA-256 per file, builds the ZIP atstorage/archives/{client-code}-{fy}-{job-id}.zip.Compute manifest
Per-file SHA-256 + size + path → written to
_manifest.jsoninside the ZIP. Top-level ZIP SHA-256 stored injobs.archive_sha256.Stamp retention
jobs.retention_until = report_date + 7 years(configurable perm16.retention_yearssetting). Auto-purge cron checks this column nightly.Off-site sync
Nightly cron
bin/cron-offsite-backup.shrclone-syncs new archives to the configured remote (B2 / S3 / Wasabi). Email alert on failure.Status flips to archived
Job is now read-only. All workpapers, AJEs, FS, notes, disclosures, comments — all uneditable. Audit-log captures the lock event.
Archive contents (TPL-AA Annual Audit example)
CL0042-FY2025-{JOB-ID}.zip · sha256: a3f8b2...e201
├── 01-Engagement/
│ ├── engagement-letter-signed.pdf
│ ├── independence-confirmation.pdf
│ └── client-acceptance-memo.pdf
├── 02-Trial-Balance/
│ ├── tb-original-uploaded.csv (sha256: ...)
│ ├── tb-adjusted.csv
│ └── ajes-register.pdf
├── 03-Workpapers/
│ ├── A-100-Planning.pdf
│ ├── B-100-Cash.pdf
│ ├── C-100-AR.pdf
│ ├── D-100-Inventory.pdf
│ ├── E-100-PPE.pdf
│ ├── F-100-Payables.pdf
│ ├── G-100-Revenue.pdf
│ ├── H-100-OpEx.pdf
│ ├── I-100-Equity.pdf
│ ├── J-100-Tax.pdf
│ ├── K-100-GoingConcern.pdf
│ ├── L-100-SubsequentEvents.pdf
│ └── _signoffs-matrix.csv
├── 04-FS-pack/
│ ├── SFP.pdf · SPL.pdf · SCF.pdf · SOCIE.pdf
│ ├── notes-1-to-24.pdf
│ └── disclosure-checklist.pdf
├── 05-Audit-Report/
│ └── Audit-Report-{ClientCode}-FY2025-SIGNED.pdf
├── 06-Completion/
│ ├── completion-summary.pdf
│ └── readiness-pdf.pdf
├── 07-Audit-Trail/
│ └── audit-log-{JOB-ID}.csv (every action timestamped)
└── _manifest.json (SHA-256 + size per file)
Non-audit template archives
Smaller jobs produce smaller archives — the framework is the same but only the relevant folders populate:
| Template | Archive folders | Approx size |
|---|---|---|
| TPL-AA Annual Audit | 01–07 + workpapers | 15–80 MB |
| TPL-RE Review | 01, 02, 04, 05, 07 | 5–20 MB |
| TPL-AUP Agreed Procedures | 01, 05, 07 | 2–10 MB |
| TPL-CIT Corp Tax Return | 01, 05 (computation), 07 | 1–5 MB |
| TPL-VAT Quarterly VAT | 05 (return PDF), 07 | 500 KB – 2 MB |
| TPL-BK Bookkeeping (monthly) | 05 (mgmt reports), 07 | 500 KB – 3 MB |
| TPL-PAY Payroll (monthly) | 05 (payslips, WPS SIF), 07 | 200 KB – 1 MB |
Restore from archive
Quarterly restore drill — pick a random archive, restore, verify, log.
Pull from off-site
rclone copy {remote}:archives/CL0042-FY2025-X.zip ./restore-test/Verify top-level SHA-256
sha256sum CL0042-FY2025-X.zip→ compare tojobs.archive_sha256for that job. Match required.Extract + verify manifest
unzip CL0042-FY2025-X.zip→ walk_manifest.json, recompute each file's SHA-256, compare. Report any mismatch.Open the audit report PDF
Confirm it's readable, the firm letterhead renders, partner signature visible.
Log the drill result
Drop a row in
backup_drillswith date + drill-runner + outcome. Some firms also email a brief to the partner.
Auto-purge after retention
The M16 retention cron (bin/cron-m16-retention.php) runs nightly and:
- Soft-flags any archive past
retention_untilwithlegal_hold=0for partner review - NEVER auto-purges — legal hold + partner approval required for physical delete
- Hard-purge happens only after partner approves + 30-day grace period elapses
- Audit-logs the purge action (last record of the file's existence)
On a closed engagement, click Job dashboard → archive download. Open the ZIP, walk the structure, recompute the SHA-256 of _manifest.json. Verify it matches the displayed value on the job dashboard. This is a 60-second integrity check you should run after every archive build.
If off-site backup goes silent, you're one disk-failure away from losing 7 years of evidence. Configure the cron so a failed sync pages someone within 24h. Audit firms have lost their licence to practice over evidence-file destruction. Backup is non-negotiable.
If an engagement is under regulatory inquiry, mark legal_hold=1 on the job. The retention cron will never flag it for purge — even after 7 years. Hold can be released only by super_admin with documented reason. Use this when OAAA, OTA, or CMA opens a case.
That's the lifecycle
From "client called" → "lead captured" → "job created" → "tasks ticked" → "files attached" → "status flipped to completed" → "invoice drafted + sent + paid" → "engagement archived in SHA-256 vault for 7 years". One template, ~430 rows, full audit trail. The next engagement starts fresh.
Now jump into a specific template walkthrough — TPL-AA Annual Audit is the deepest: