Phase 0 — foundation fixes (architecture view)
This page describes how the four Phase 0 tasks fit together at the system level. For per-task technical detail see the technical finance docs. For staff-facing flow see the business finance doc.
What Phase 0 changes (and doesn't)
Phase 0 strengthens the existing GL layer without adding new pipeline stages. The pipeline before Phase 0 was:
Trigger → journal-entries.service.create() → GL + hash chain
After Phase 0 it is still that — but the GL now has the AAOIFI account skeleton it needs for Phases 1–3, can reverse entries cleanly, and is independently verified nightly.
Component map
Invariants Phase 0 introduces / preserves
- One shared hash function. Both the poster (
journal-entries.service.ts) and the verifier (hash-chain-verifier.service.ts) callcomputeJournalHash. Drift between poster and verifier is structurally impossible. - Reversal is the only allowed mutation.
_markAsReversedis the single private path that updates a posted entry, and it touches onlymetadata.reversedBy. All other mutations are forbidden. - Append-only ordering. Hash chain is over
(createdAt ASC, id ASC). Lines within an entry hash inid ASCorder. Any verifier or future migration that reorders breaks the chain. - Idempotent seeds. AAOIFI seed and per-fund auto-provision can be replayed safely. Idempotency is by 4-digit code (sub-groups) and by
namekey (per-fund custom accounts). - Audit assurance is server-authoritative. The audit UI no longer makes correctness claims from the client; it shows the result of a backend run.
Dependencies Phase 1 has on Phase 0
| Phase 1 block | Depends on |
|---|---|
| 1.A subledgers | AAOIFI control accounts (6101, 6102, 7001, 7002); per-fund control accounts (6001*) |
| 1.B posting/Shariah | SourceModule extension (so engine emits typed values); _markAsReversed stays the only mutation |
| 1.C NAV | Per-fund NAV adjustment accounts (6002*); FX gain/loss accounts (6301, 6302) |
| 1.D handlers | Reversal API (for cancelling a mispostied trade); all of the above |
Failure modes Phase 0 explicitly handles
- Missing parent group during AAOIFI seed → reported in
errors, seed continues - Per-fund account collision during fund creation → non-fatal; fund row remains valid, operator can re-run
- Legacy entries with
hashedAt: null→ surfaced under distinctlegacy_unhashed_timestampcategory, not flagged as tampering - Reverse of a reversal → 400; cycles are blocked
- Concurrent reverse of same original → second caller gets 409 because metadata update is in the same transaction
What's left for later phases to wire up
- A system-actor convention so the nightly verifier can post notifications via the existing notification module (currently it only logs at
errorlevel). - A scheduled rebaseline —
rebaselineHashChain()exists but is admin-only manual today; future ops may want a guarded automation. - An exhaustive
SourceModulehandler registry in Phase 1.B that compile-fails on missing handlers.