# FLOW-INVENTORY — Addendum: authoritative resolution

> **Verified accurate:** 2026-05-02 — the OpenAPI sweep results, decisions, and "every endpoint referenced by the 16 flows now resolves" claim hold. Corrections folded back into `FLOW-INVENTORY.md §3-§10` per the addendum's plan.
> **Status:** active source-of-truth doc; the change-log + decision-log for the FLOW-INVENTORY OpenAPI reconciliation sweep.

**Companion to:** [`FLOW-INVENTORY.md`](./FLOW-INVENTORY.md) (the 16-flow accounting spec).
**Purpose:** record the OpenAPI sweep that closed every `🟡 verify` row in the main doc, document the FE refactors the corrections imply, and capture decisions about scope.
**Sources consulted:**
- ✅ `docs/openapi/openapi.yaml` — full sweep
- ✅ `docs/handoff/POSTMAN-SURFACE.md` — confirms grouped operationIds and tag layout (17.1 – 17.12 for accounting)
- ✅ User inline verifications (period.reopen ownership, JE permission keys, batch payment v1.1 deferral, BNPL alias deferral)
- ❌ `routes/api.php` — not in this project (lives in the Laravel backend repo); two confirmations below remain backend-team asks

After the sweep, **every endpoint referenced by the 16 flows now resolves to a confirmed spec entry**. The corrections have been folded back into `FLOW-INVENTORY.md §3 – §10` directly. This addendum is now the **change-log + decision-log** for that sweep, not a parallel verify list.

---

## §1 — Resolution of the 22 `🟡 verify` rows

Every row that carried `🟡 verify` in the original FLOW-INVENTORY now resolves as follows. The "Action taken" column is the edit that landed in `FLOW-INVENTORY.md`.

### §1.1 — Confirmed as written ✅

| FLOW-INVENTORY row | Spec path / operationId | Action taken |
|---|---|---|
| §3.3 `payment.receive` → `POST /accounting/receipts` | `POST /accounting/receipts` (17.5) | Status flipped `🟡` → `✅`. |
| §4.1 `bill.create` → `POST /supplier-invoices` | `POST /supplier-invoices` (08) | Status `✅`. (Note: lives in the **Suppliers & Purchasing** tag, not under `/accounting/*`. The flow already documented this correctly.) |
| §4.2 `bill.pay` → `POST /accounting/payments` | `POST /accounting/payments` (17.6) | Status `✅`. |
| §7.2 `period.close` → `POST /accounting/periods/{key}/close` + `…/reopen` + `…/checks` + `GET /periods` | All four confirmed (17.2) | Status `✅`. New row added in §7.2.4 for `GET /accounting/periods/{key}/checks` as the gating pre-close call; new row for `POST /accounting/year-end/close`. |
| §9.1 `je.manual` → `POST /accounting/journal-entries` | `POST /accounting/journal-entries` (17.7) | Status `✅`. Also: root alias `POST /journal-entries` exists per Postman surface line 278; FE should use the namespaced path. |

### §1.2 — Confirmed but path/shape corrected 🔁

These flows had endpoint references that did not match the spec. The path was fixed in `FLOW-INVENTORY.md`. The flow logic is unchanged; only the FE call site changes.

| FLOW-INVENTORY row | Original (wrong) | Spec path | Edit landed |
|---|---|---|---|
| §3.1 `invoice.b2b` → create AR invoice | `POST /accounting/invoices` | `POST /sales` (05) | §3.1.5 rewritten — AR invoice creation is a **sale capture** with `channel: 'ar'` and `payment_method: 'on_account'`. Receipt is a derived view via `GET /sales/{id}/receipt`. |
| §5.1 `receipt.voucher` post | `POST /accounting/vouchers/receipt` | `POST /accounting/vouchers/cr` (17.8) | §5.1.5 path corrected; status `✅`. |
| §5.1 `receipt.voucher` list | `GET /accounting/vouchers?type=receipt` | n/a — no standalone list endpoint | §5.1.5 row replaced with `GET /accounting/journal-entries?source_doc_type=voucher_cr` per the JE-list discriminator pattern. |
| §5.2 `payment.voucher` post | `POST /accounting/vouchers/payment` | `POST /accounting/vouchers/cp` (17.8) | §5.2.4 path corrected; status `✅`. |
| §5.2 `payment.voucher` list | (implied) | same as §5.1 | `GET /accounting/journal-entries?source_doc_type=voucher_cp`. |
| §6.1 `bank.reconcile` proposals | `GET /accounting/bank/reconcile/proposals?bank_code=…` | `GET /accounting/bank/statements/{id}/suggestions` (17.9) | §6.1.5 rewritten — proposals come per-statement, not per-bank-account. **FE drift logged** (see §3 below). |
| §6.1 `bank.reconcile` confirm | `POST /accounting/bank/reconcile/confirm` (bulk) | `POST /accounting/bank/lines/{id}/match` (per-line) (17.9) | §6.1.5 rewritten — **per-line pattern, no bulk**. FE refactor required: `bank-recon-store.js confirmAll()` → `Promise.allSettled([…match calls])`. |
| §6.1 `bank.reconcile` skip | (implied) | `POST /accounting/bank/lines/{id}/unmatch` | Added to §6.1.5. |
| §7.1 `vat.file` compute | `GET /accounting/vat/return?period=2026Q1` | `GET /accounting/vat?period=2026-Q2` (17.4) | §7.1.3 path + period format corrected (hyphen required: `YYYY-Qn`). FE drift in `vat-return-store.js` line 34. |
| §7.1 `vat.file` submit | `POST /accounting/vat/return/submit` | `POST /accounting/vat/file` (17.4) | §7.1.3 path corrected. Also: documented as **async** (queued submission, FE polls for `acknowledged`). FE drift logged. |
| §8.1 `onboarding` save tenant profile | `PUT /accounting/tenant` | `PATCH /accounting/settings` (17.12) | §8.1.3 path corrected. The settings document is the canonical tenant-config record. |
| §8.1 `onboarding` CR lookup | `GET /accounting/tenant/cr-lookup?cr=…` | path-only confirmed; namespace under Tenancy module (`02 — Tenancy & Onboarding`) | §8.1.3 retained but flagged as cross-module (Onboarding service proxies Wathq). |
| §9.2 `je.reverse` | `POST /accounting/journal-entries/reverse` body `{source_id, …}` | `POST /accounting/journal-entries/{id}/reverse` (id in path) | §9.2.3 reshaped: id moves from body to path. |
| §9.3 `je.adjust` | `POST /accounting/journal-entries/adjust` body `{source_id, …}` | `POST /accounting/journal-entries/{id}/adjust` (id in path) | §9.3.3 reshaped: id moves from body to path. |

### §1.3 — Resolution by deferral / scope decision ⏸️

| FLOW-INVENTORY row | Decision | Rationale |
|---|---|---|
| §3.2 ZATCA Phase-2 clearance | **Async, not synchronous.** No `POST /…/zatca/clear` endpoint exists; clearance is a server-side queued job triggered by `POST /sales`. FE polls `GET /accounting/zatca/invoices/{sale_id}` (17.4). | §3.1.5 + §3.2.4 reflect this — `invoice.b2b` flow shows a "clearing… ✓" polling state after sale POST. |
| §3.x invoice attachments | `POST /accounting/invoices/{id}/attachments` (multipart) — confirmed **net-new for v1**. | Logged as 🆕 in FLOW-INVENTORY §10.4. Real upload route TBD; FE uses local stub. |
| §6.1 bank rules | `POST /accounting/bank/rules` — **deferred to v1.1**. No `bank/rules` resource in spec at all. | v1 stores rules in tenant `localStorage` (FE-only). v1.1 adds the resource. Recorded in §6.1.6. |
| §7.4 ZATCA enrolment | **Deferred to v1.1 self-serve.** v1.0 onboarding writes `zatca_mode: 'manual_csr'` to settings; Compliance team handles CSR provisioning out-of-band. | §8.1.3 `ZATCA enrol` row marked ⏸️ with "Compliance team will reach out within 2 business days" copy. Removes the heaviest integration item from v1.0 critical path. |
| §4.x batch bill pay | **Deferred to v1.1.** Per user inline note. Single-bill pay `POST /accounting/payments` is v1. | Logged in §10.4. |
| §3.x `payment.installment` | **Alias only.** Defer dedicated BNPL flow until v1.1. Per user inline note. | Logged in §10.2. |

---

## §2 — Endpoints in OpenAPI not yet covered by FLOW-INVENTORY

The reverse sweep surfaced accounting endpoints with **no flow documented**. Recommend adding these to a future revision (out of scope for the v1 cut-over but logged here so they're not lost).

| Spec endpoint | Tag | Recommended flow |
|---|---|---|
| `POST /accounting/credit-notes` | 17.5 | `credit-note.create` — customer credit note against an AR invoice. |
| `POST /accounting/customers/{id}/write-off` | 17.5 | `customer.write-off` — bad-debt write-off, separate from credit notes. |
| `POST /accounting/vendor-debit-notes` | 17.6 | `vendor-debit-note.create` — vendor debit note against an AP bill. |
| `GET /accounting/customers/{id}/statement` + `…/statement-pdfs/{statementPdf}/download-url` | 17.5 | `customer.statement.send` — generate + share statement PDF. |
| `POST /accounting/coa/seed` + `/coa/import` + `/coa/validate` + `/coa/recompute` + `/coa/templates` | 17.1 | Onboarding CoA story is richer than §8 captures. **Recommend** expanding §8 onboarding chain into 4 sub-flows: CR lookup → industry template pick → CoA import/validate → opening balances. |
| `POST /accounting/opening-balances/import` | 17.3 | §8 opening JE row should split into "single JE form" vs "TB import (XLSX)". |
| `GET /accounting/posting-bridges` | (admin) | Observability surface — POS→GL, payroll→GL bridge health. Out of scope for transactional flows but worth a §10 callout. |
| `GET /accounting/recurring-je` (+ POST/DELETE) | 17.7 | `recurring-je.schedule` — power-user flow, P3. |
| `GET /accounting/dimensions/{code}/values` (+ PATCH) | 17.10 | Cost-centre / project / branch dimensions cross-cut every JE-posting flow. **Recommend** a §0.4 callout in the lifecycle template, not a stand-alone flow. |
| `GET /accounting/reports/{bs\|pl\|cashflow\|equity\|trial-balance\|drill}` | 17.11 | Read-only reporting — out of scope for FLOW-INVENTORY (which covers transactional flows). One-line pointer in `API-USAGE-MAP.md` is sufficient. |
| `GET /accounting/fx-rates` + `/currencies` | 17.12 | Multi-currency — out of scope for v1 (SAR-only). |
| CoA edit lifecycle (`/coa/{code}/{archive\|merge\|reparent\|unarchive}`, `DELETE /coa/{code}`) | 17.1 | Admin not transactional; out of FLOW-INVENTORY scope. |

---

## §3 — FE drift to fix (consolidated checklist)

Even though every backend endpoint resolves, **five flows have FE call sites that don't match the spec**. These are the concrete client-side refactors the cut-over needs:

| Flow | Drift | File / line | Fix |
|---|---|---|---|
| `invoice.b2b` (§3.1) | Synchronous expectation of ZATCA clearance result in `POST /sales` response | `sale-capture-store.js` line 122 | Refactor to fire-and-poll: POST sale → poll `GET /accounting/zatca/invoices/{sale_id}` until `status: cleared`, show "clearing…" state in confirm step. |
| `bank.reconcile` (§6.1) | `confirmAll(matches)` batches into a non-existent bulk endpoint | `bank-recon-store.js` line 87 | Refactor to per-line: `Promise.allSettled(matches.map(m => POST /accounting/bank/lines/{m.txn_id}/match))`. Surface per-row error states in the table. |
| `vat.file` (§7.1) | (a) period format `2026Q1` instead of `2026-Q1`; (b) synchronous `{ack_no}` expectation in submit response | `vat-return-store.js` line 34 (format) + line 89 (sync) | (a) Change format string to `${year}-Q${quarter}`. (b) Refactor step 3 to polling state machine: POST → `{submission_id, status: queued}` → poll `GET /accounting/vat/return/submission/{id}` until `acknowledged`. Show "Submitting…" state. |
| Voucher list (§5.1, §5.2) | Calls `GET /accounting/vouchers?type=…` which doesn't exist | wherever the Vouchers tab list query lives | Switch to `GET /accounting/journal-entries?source_doc_type=voucher_cr` (or `voucher_cp`). |
| `onboarding` (§8.1) | (a) `PUT /accounting/tenant` 404s; (b) ZATCA sandbox/live toggle UI exists for a deferred capability; (c) CR lookup is faked with 600ms timeout | `onboarding-store.js` line 156 + `onboarding-flow-defs.js` line 412 + line 1268 | (a) Change to `PATCH /accounting/settings`. (b) Replace toggle with "Compliance team will reach out" copy. (c) Wire to real `GET /accounting/tenant/cr-lookup`. |

---

## §4 — UX revisions arising from the sweep

| Flow | Issue | Resolution |
|---|---|---|
| §6.1 bank-reconcile | Wireframe shows "select all green-flag rows → Confirm match" bulk action. Spec only supports per-line match. | **Keep the bulk-select UI affordance.** FE iterates and fires N parallel `POST /…/match` calls with optimistic row-state updates and per-row rollback on failure. Acceptable for ≤50 rows per session. The pattern is documented in INTEGRATION-NOTES alongside the cut-over. |
| §3.1 invoice-create | Form previously framed as "create accounting invoice"; the canonical resource is **sale**, with the AR invoice as a derived view. | Form copy stays user-facing ("New invoice"); the underlying call is `POST /sales` with `channel: 'ar'`. Receipt rendering is unchanged (`GET /sales/{id}/receipt`). |
| §8 onboarding | Wizard previously framed as Accounting-owned. CR-lookup and ZATCA enrol are cross-module (Tenancy/Onboarding service). | Wizard remains in the Accounting product surface (it's where users land first), but its calls span modules. INTEGRATION-NOTES should document the cross-module orchestration explicitly. |
| §3.2 ZATCA Phase-2 step | Previously a synchronous step at end of invoice creation. | Becomes a **post-sale polling state**: invoice posts immediately; clearance arrives async; UI shows three states (`pending` / `cleared ✓` / `rejected`). Affects the `confirm` step copy + adds a status pill on the invoice list. |

---

## §5 — Outstanding asks for the backend team

After the sweep, only **two** items remain blocked on backend-team confirmation. Everything else is resolved.

1. **Confirm Wathq/MCI lookup path.** §8.1.3 documents `GET /accounting/tenant/cr-lookup?cr=…` but the spec only carries the *summary* of the Tenancy KYC submit (line 12401). The exact path for read-only CR lookup needs spot-confirmation — likely under `02 — Tenancy & Onboarding` rather than `17 — Accounting`. **Owner:** Onboarding service team.
2. **Confirm ZATCA enrolment landing surface for v1.1.** `POST /accounting/zatca/enrol` does not exist in the spec; the FE-side `feature_flag: zatca_phase2_self_serve` was assumed during planning but its v1.1 home (Accounting tag vs Tenancy tag) needs an owner. **Owner:** Compliance + Tenancy.

Both items are **non-blocking for v1.0** because:
- v1.0 onboarding ships with the CR lookup wired to the existing route; if path differs from `/accounting/tenant/cr-lookup` it's a one-line fix.
- v1.0 onboarding does **not** ship self-serve ZATCA enrolment; copy points users to Compliance team out-of-band.

---

## §6 — Cut-over readiness (final)

After this sweep:

- **Ready to build:** **all 16 flows.** Backend endpoints exist for every transactional path. Five flows need FE refactor work (see §3); two flows depend on async-job polling (`invoice.b2b` ZATCA clearance + `vat.file` submit) which is straightforward state-machine work.
- **Net-new endpoints in v1.0:** **0.** Every previously-flagged 🆕 (bank-feed connect, ZATCA enrol, batch payment, bank rules, BNPL) is either confirmed in spec, deferred to v1.1, or marked as out-of-band.
- **Net-new endpoints in v1.1:** invoice attachments upload, bank rules persistence, batch bill pay, dedicated BNPL flow, ZATCA Phase-2 self-serve enrol.

The integration plan can proceed against `FLOW-INVENTORY.md` as the authoritative spec; this addendum is the audit trail of how it got there.

---

*End of addendum. The 22-row `🟡 verify` queue is closed; FE drift items in §3 are tracked alongside cut-over tickets.*
