# Front-End File Consolidation Guide

> **Verified accurate:** 2026-05-02 — the 46→17 consolidation rules and merge plan are unchanged. **One note:** the prototype has since added 8 batch-namespace files + per-batch screen splits (see MODULE-MAP §1), so the "46 split-mission files" baseline this guide opens with is now ~60. The merge groupings still apply; just expect to be folding more files than originally listed.
> **Status:** active refactor playbook; runs on demand.

**Audience:** developer doing the merges manually  
**Goal:** reduce 46 split-mission files (54,523 lines) to ~17 single-mission files so backend developers see **one screen domain = one file = one Postman folder**.

This is a **non-destructive refactor**. Behaviour does not change. Only file boundaries change.

---

## The rules

1. **Never delete the source files** until everything is verified working. Move them to `archive/pre-consolidation/` instead.
2. **Bump the cache-buster query string** (`?v=N`) on every changed `<script>` tag in `index.html`.
3. **Verify after each pass** by reloading the prototype and clicking through the affected screens. Console must stay clean.
4. **Some files are too big to merge.** Files marked `🟥 KEEP SEPARATE` below stay as-is — merging would push them past 5,000 lines.
5. **Mission-merge candidates** are marked `🟢 MERGE` — these belong together by backend domain.

---

## How to merge a group (template)

For each group below:

1. **Create** the target file (e.g. `accounting-settings.compiled.js`).
2. At the top, add the **header block** shown for that group.
3. **Concatenate** the source files in the order listed, **inside one outer IIFE** if the originals had IIFEs:
   ```js
   (function(){
     // ─── §1 source-file-1 contents (without its outer IIFE) ───
     // ─── §2 source-file-2 contents (without its outer IIFE) ───
     // ...
   })();
   ```
   If two source files declare the same `const Icon = window.Icon` etc. — keep only the first; remove duplicates from later sections.
4. **Add section dividers** between concatenated parts:
   ```js
   // ════════════════════════════════════════════════════════════════
   // §2  TAX RATES   ←  was: accounting-settings-part2.compiled.js
   // ════════════════════════════════════════════════════════════════
   ```
5. **Update `index.html`**: replace the N source `<script>` tags with one `<script>` for the merged file. Bump `?v=N+1`.
6. **Move sources** to `archive/pre-consolidation/<module>/`.
7. **Reload + verify** in the prototype.

---

## Pass 1 — Accounting (low risk, ~3 hours)

### 1.1 — Settings (4 files → 1) 🟢 MERGE

**Target:** `front/accounting/accounting-settings.compiled.js`

**Sources (in order):**

| Order | Source | Lines | Section |
|---|---|---:|---|
| §1 | `accounting-settings.compiled.js`           |   516 | Hub shell + sub-tab registry |
| §2 | `accounting-settings-part2.compiled.js`     |   812 | Chart of Accounts editor + Tax rates + Numbering |
| §3 | `accounting-settings-part3.compiled.js`     | 1,685 | Cadence · day-zero · fixed-assets |
| §4 | `accounting-settings-integration.js`        |   291 | Integrations |

**Total:** 3,304 lines.

**Header to paste at top:**

```js
// ════════════════════════════════════════════════════════════════
// SAAED BOOKS · SETTINGS  (one mission, one file)
// 
// Backend mapping:
//   GET    /api/v1/companies/{id}/accounting-settings
//   PATCH  /api/v1/companies/{id}/accounting-settings
//   GET    /api/v1/accounting/coa
//   PATCH  /api/v1/accounting/coa/{code}
//   GET    /api/v1/accounting/tax-rates
//   GET    /api/v1/accounting/numbering-sequences
//   GET    /api/v1/accounting/integrations
//
// Sections (search to jump):
//   §1  HUB & SUB-TAB REGISTRY              (line ~30)
//   §2  CHART OF ACCOUNTS / TAX / NUMBERING (line ~550)
//   §3  CADENCE / DAY-ZERO / FIXED ASSETS   (line ~1370)
//   §4  INTEGRATIONS                        (line ~3055)
// ════════════════════════════════════════════════════════════════
```

---

### 1.2 — Data fixtures (3 files → 1) 🟢 MERGE

**Target:** `front/accounting/accounting-data.js`

| Order | Source | Lines | Section |
|---|---|---:|---|
| §1 | `accounting-data.js`        | 677 | Static fixtures (COA, JEs, invoices, vendors, periods) |
| §2 | `accounting-data-extra.js`  | 328 | Recurring JEs · pre-close checks |
| §3 | `accounting-data-live.js`   | 233 | Live shim (AcctData ↔ AcctStore reactivity) |

**Total:** 1,238 lines.

**Header:**

```js
// ════════════════════════════════════════════════════════════════
// SAAED BOOKS · DATA  (mock fixtures + live shim)
// 
// Backend mapping (when MOCK_MODE=false this layer goes away):
//   §1 fixtures → seeders + factories in DalseenSeeder
//   §2 extras   → Recurring JE table, period_checks() RPC
//   §3 live     → no backend; merges AcctStore writes into AcctData reads
//
// Sections:
//   §1  STATIC FIXTURES         (line ~1)
//   §2  RECURRING / CHECKS      (line ~680)
//   §3  LIVE SHIM               (line ~1010)
// ════════════════════════════════════════════════════════════════
```

---

### 1.3 — Flow definitions (5 files → 1) 🟢 MERGE

**Target:** `front/accounting/accounting-flow-defs.compiled.js`

| Order | Source | Lines | Section |
|---|---|---:|---|
| §1 | `accounting-flow-defs-sales.compiled.js`        | 607 | Quick / Standard / ZATCA invoice; receive payment |
| §2 | `accounting-flow-defs-spend.compiled.js`        | 367 | Bills · Pay vendor · Refunds |
| §3 | `accounting-flow-defs-admin.compiled.js`        | 403 | Period close · Recurring · Adjust |
| §4 | `accounting-flow-defs-manual-je.compiled.js`    | 316 | Manual journal entry composer |
| §5 | `accounting-flow-defs-invoice-b2b.compiled.js`  | 808 | Unified B2B composer (overrides §1) |

**Total:** 2,501 lines.

**Header:**

```js
// ════════════════════════════════════════════════════════════════
// SAAED BOOKS · FLOW DEFINITIONS
//
// Each flow ID maps to a Postman folder under /api/v1/accounting/*
//
//   §1  invoice.quick / invoice.standard / payment.receive  → POST /api/v1/accounting/invoices
//   §2  bill.record / bill.pay / refund.issue               → POST /api/v1/accounting/bills
//   §3  period.close / recurring.schedule / je.adjust       → POST /api/v1/accounting/periods/{id}/close
//   §4  je.manual                                            → POST /api/v1/accounting/journal-entries
//   §5  invoice.b2b (overrides §1)                           → POST /api/v1/accounting/invoices (with line items)
// ════════════════════════════════════════════════════════════════
```

---

### Pass 1 wrap-up

**HTML script-tag changes** — open `index.html`, find these lines, replace with the consolidated tags:

```html
<!-- BEFORE: 12 tags -->
<script src="front/accounting/accounting-data.js?v=1"></script>
<script src="front/accounting/accounting-data-extra.js?v=1"></script>
<script src="front/accounting/accounting-data-live.js?v=1"></script>
<script src="front/accounting/accounting-settings.compiled.js?v=1"></script>
<script src="front/accounting/accounting-settings-part2.compiled.js?v=1"></script>
<script src="front/accounting/accounting-settings-part3.compiled.js?v=1"></script>
<script src="front/accounting/accounting-settings-integration.js?v=1"></script>
<script src="front/accounting/accounting-flow-defs-sales.compiled.js?v=1"></script>
<script src="front/accounting/accounting-flow-defs-spend.compiled.js?v=1"></script>
<script src="front/accounting/accounting-flow-defs-admin.compiled.js?v=1"></script>
<script src="front/accounting/accounting-flow-defs-manual-je.compiled.js?v=1"></script>
<script src="front/accounting/accounting-flow-defs-invoice-b2b.compiled.js?v=1"></script>

<!-- AFTER: 3 tags -->
<script src="front/accounting/accounting-data.js?v=2"></script>
<script src="front/accounting/accounting-settings.compiled.js?v=3"></script>
<script src="front/accounting/accounting-flow-defs.compiled.js?v=1"></script>
```

**Smoke test (Pass 1):**

1. Open Business OS → SAAED Books.
2. Click each sub-tab: Home, Sell, Collect, Spend, Pay, Banking, Journal, GL, Recurring, Chart of Accounts, Opening, Periods, VAT · ZATCA, Reports, Settings.
3. Click **+** to open a flow → Quick invoice → Standard invoice → Bill → Manual JE.
4. Open Settings → COA, Tax, Numbering, Approvals, Cadence, Fixed Assets, Integrations.
5. Console must stay clean.

---

## Pass 2 — Owner / Platform (medium risk, ~2 hours)

### 2.1 — Owner console (5 files → 2) 🟡 PARTIAL MERGE

`owner-submodules.compiled.js` is already **5,751 lines** — too big to merge with siblings without becoming unmaintainable. **Keep it separate.**

**Target A:** `front/owner/owner-shell.compiled.js` (merge shell + home + flows + data)

| Order | Source | Lines |
|---|---|---:|
| §1 | `owner-console.compiled.js`           | 66 |
| §2 | `owner-home.compiled.js`              | 2,264 |
| §3 | `owner-flows-goals-legal.compiled.js` | 930 |
| §4 | `owner-data.js`                       | 564 |

**Total:** 3,824 lines.

**Target B:** `front/owner/owner-submodules.compiled.js` 🟥 **KEEP SEPARATE — already 5,751 lines.**
Just add a header pointing at the sub-modules it contains.

**Header for A:**

```js
// ════════════════════════════════════════════════════════════════
// OWNER CONSOLE · shell + home + flows + data
//
// Backend mapping:
//   GET  /api/v1/me/setup-progress         → home progress card
//   GET  /api/v1/me/goals                  → §3 goals
//   GET  /api/v1/companies/{id}/legal      → §3 legal
//
// Sections:
//   §1  CONSOLE SHELL              (line ~1)
//   §2  HOME (KPIs, signals, CTA)  (line ~70)
//   §3  GOALS · LEGAL              (line ~2335)
//   §4  DATA FIXTURES              (line ~3265)
// ════════════════════════════════════════════════════════════════
```

---

### 2.2 — Platform admin (5 files → 2) 🟡 PARTIAL MERGE

`platform-screens.compiled.js` (3,315) + `platform-health.compiled.js` (2,190) + `dalseen-commercial-screens.compiled.js` (2,003) are each **substantial** — keep separate but rename for clarity.

**Recommended split:**

| Final file | Sources | Total |
|---|---|---:|
| `platform-shell.compiled.js`         | `platform.compiled.js` + `platform-admin.compiled.js`  | 1,866 |
| `platform-screens.compiled.js`       | (keep as-is, rename if you like)                       | 3,315 |
| `platform-health.compiled.js`        | (keep as-is)                                           | 2,190 |
| `platform-commercial.compiled.js`    | rename `dalseen-commercial-screens.compiled.js`        | 2,003 |

So the only **merge** here is `platform.compiled.js` + `platform-admin.compiled.js` → `platform-shell.compiled.js`.

---

## Pass 3 — HR (high impact, ~6 hours)

**This is the biggest win.** 23 files → 5 files, organized by backend domain.

### 3.1 — `hr-people.compiled.js` 🟢 MERGE (5 files)

People-record domain: directory, hires, contracts, employee self-service.

| Order | Source | Lines |
|---|---|---:|
| §1 | `hr-shell.compiled.js`             | 552 |
| §2 | `hr-staff.compiled.js`             | 577 |
| §3 | `hr-staff-2.compiled.js`           | 272 |
| §4 | `hr-staff-3.compiled.js`           | 474 |
| §5 | `hr-directory-flow.compiled.js`    | 1,228 |

**Total:** 3,103 lines. **Backend folders:** `/hr/employees`, `/hr/contracts`, `/hr/onboarding`.

---

### 3.2 — `hr-recruit-grow.compiled.js` 🟢 MERGE (4 files)

Recruiting + perf + learning + helpdesk.

| Order | Source | Lines |
|---|---|---:|
| §1 | `hr-ats.compiled.js`         | 541 |
| §2 | `hr-perf.compiled.js`        | 599 |
| §3 | `hr-learning.compiled.js`    | 313 |
| §4 | `hr-helpdesk.compiled.js`    | 578 |

**Total:** 2,031 lines. **Backend folders:** `/hr/ats`, `/hr/performance`, `/hr/learning`, `/hr/tickets`.

---

### 3.3 — `hr-payroll.compiled.js` 🟢 MERGE (4 files)

Money flowing **to** employees.

| Order | Source | Lines |
|---|---|---:|
| §1 | `hr-payroll-v2.compiled.js`   | 383 |
| §2 | `hr-expenses.compiled.js`     | 533 |
| §3 | `hr-loans.compiled.js`        | 502 |
| §4 | `hr-contracts.compiled.js`    | 651 |

**Total:** 2,069 lines. **Backend folders:** `/hr/payroll`, `/hr/expenses`, `/hr/loans`, `/hr/contracts`.

---

### 3.4 — `hr-time.compiled.js` 🟢 MERGE (3 files)

Attendance / leave / roster.

| Order | Source | Lines |
|---|---|---:|
| §1 | `hr-leave-v2.compiled.js`     | 447 |
| §2 | `hr-roster-v2.compiled.js`    | 355 |
| §3 | `biometric-shift.compiled.js` | (in `front/common/`) |

Move `biometric-shift.compiled.js` from `front/common/` to `front/owner/` first.

**Total:** ~1,400 lines. **Backend folders:** `/hr/leave`, `/hr/shifts`, `/hr/biometric-events`.

---

### 3.5 — `hr-org-policies.compiled.js` 🟢 MERGE (4 files)

Org chart + roles + assets + flows.

| Order | Source | Lines |
|---|---|---:|
| §1 | `hr-org.compiled.js`              | 584 |
| §2 | `hr-roles-policies.compiled.js`   | 608 |
| §3 | `hr-assets.compiled.js`           | 372 |
| §4 | `hr-flows.compiled.js`            | 367 |
| §5 | `hr-extended.compiled.js`         | 557 |

**Total:** 2,488 lines. **Backend folders:** `/hr/org-units`, `/hr/roles`, `/hr/policies`, `/hr/assets`.

---

### 3.6 — `hr-data.js` 🟢 RENAME (1 file)

`hr-data-extended.js` → `hr-data.js` (drop the `-extended` suffix; no merge needed).

---

### Pass 3 wrap-up — HR `<script>` block

**Before:** 23 tags in `index.html`  
**After:** 6 tags — the 5 merged files plus `hr-data.js`.

---

## Pass 4 — Retail (high risk, ~8 hours)

### 4.1 — Retail flows (9 files → 3) 🟡 PARTIAL MERGE

`retail-checkout.compiled.js` (2,427) and `retail-inventory-flows.compiled.js` (3,300) are too big to merge with siblings.

**Recommended split:**

| Final file | Sources | Lines |
|---|---|---:|
| `retail-flow-pos.compiled.js`        | `retail-flow` + `retail-cfd` + `retail-receipts` + `retail-receipt-share` | 3,381 |
| `retail-flow-checkout.compiled.js`   | (keep `retail-checkout` as-is)                                            | 2,427 |
| `retail-flow-stock.compiled.js`      | `retail-inventory-flows` + `retail-transfers` + `retail-returns-flow`     | 5,351 — KEEP `retail-inventory-flows` SEPARATE; merge only the smaller two into `retail-flow-stock.compiled.js` (2,051) |
| `retail-flow-misc.compiled.js`       | `retail-complete` + `retail-ext` + `retail-expiry-wastage` + `retail-growth-ops` | varies |

So actually:

| Final file | Sources | Total |
|---|---|---:|
| `retail-flow-pos.compiled.js`        | retail-flow + retail-cfd + retail-receipts | ~3,381 |
| `retail-flow-checkout.compiled.js`   | retail-checkout (rename only)              | 2,427 |
| `retail-flow-stock.compiled.js`      | retail-inventory-flows (rename only)       | 3,300 |
| `retail-flow-extras.compiled.js`     | retail-transfers + retail-returns-flow + retail-complete + retail-ext | 3,883 |

**Backend mapping:**
- `retail-flow-pos` → `/api/v1/pos/sales`, `/pos/shifts`, `/pos/receipts`
- `retail-flow-checkout` → `/api/v1/pos/checkout`
- `retail-flow-stock` → `/api/v1/inventory/movements`, `/inventory/counts`, `/inventory/adjustments`
- `retail-flow-extras` → `/api/v1/inventory/transfers`, `/pos/returns`

---

### 4.2 — Inventory + Add Product (6 files → 2) 🟢 MERGE

| Final file | Sources | Lines |
|---|---|---:|
| `inventory.jsx`     | `inventory-hub` + `inventory-tabs-a` + `inventory-tabs-b` | 2,220 |
| `add-product.jsx`   | `add-product-v2` + `add-product-v2-fields` + `add-product-v2-preview` | 963 |

**Backend mapping:**
- `inventory.jsx` → `/api/v1/catalog/products` (search/list/edit), `/inventory/levels`
- `add-product.jsx` → `/api/v1/catalog/products` (POST), `/catalog/categories`, `/catalog/uoms`

---

### 4.3 — Ops hub (9 files → 2) 🟡 PARTIAL MERGE

`ops-bundle.jsx` is **4,664 lines** — keep separate.

| Final file | Sources | Lines |
|---|---|---:|
| `ops-hub.jsx`      | `ops-hub` + `ops-hub-v2` + `ops-hooks` + 5× `ops-tab-*` | 5,626 — split if needed |
| `ops-bundle.jsx`   | (keep as-is)                                            | 4,664 |

If 5,626 is too big, split as:
- `ops-hub-shell.jsx` = `ops-hub` + `ops-hub-v2` + `ops-hooks` (1,528)
- `ops-hub-tabs.jsx` = 5× `ops-tab-*` (4,098)

---

### 4.4 — POS flow (3 files → 1) 🟢 MERGE

| Final file | Sources | Lines |
|---|---|---:|
| `pos-flow.compiled.js` | `pos-flow-data.js` + `pos-flow-mocks.compiled.js` + `pos-flow-ui.compiled.js` | 3,252 |

**Backend mapping:** `/api/v1/pos/*` end-to-end.

---

### 4.5 — Zero-friction onboarding (8 files → 2) 🟢 MERGE

| Final file | Sources | Lines |
|---|---|---:|
| `zf-flow.jsx`         | `zf-flow` + `zf-flow-scenes` + `zf-flow-wrap` + `zero-friction-hooks` | 2,293 |
| `zf-screens.compiled.js` | `zf-ui-core` + `zf-screen-main` + `zf-screen-tabs1` + `zf-screen-tabs2` | 2,935 |

**Backend mapping:** `/api/v1/signup`, `/setup/kyc`, `/me/setup-progress`, `/companies/{id}`, `/branches`.

---

## Final tally

| Pass | Before | After | Reduction |
|---|---:|---:|---:|
| 1 — Accounting           | 12 files | 3 files  | −9 |
| 2 — Owner / Platform     | 10 files | 6 files  | −4 |
| 3 — HR                   | 23 files | 6 files  | −17 |
| 4 — Retail               | 36 files | 12 files | −24 |
| **TOTAL**                | **81**   | **27**   | **−54** |

Backend developers will see a `front/` directory where every file maps to a clear backend domain — no more "which `hr-staff*` do I read for the employee endpoint?".

---

## Verification checklist (run after each pass)

- [ ] Open `index.html` in browser
- [ ] Console clean (no errors / no `Cannot read properties of undefined`)
- [ ] All sidebar tabs reachable (Owner, Retail, Pay, Dine, SAAED Books)
- [ ] Sub-tabs render: ≥3 random sub-tabs per module
- [ ] One write-flow works end-to-end (e.g. open Quick Invoice → fill → submit)
- [ ] One read-flow works (e.g. open Journal → click JE → see detail)

If anything breaks, the source files are in `archive/pre-consolidation/` — restore the original `<script>` tag temporarily.

---

## Don't merge (intentionally separate, by design)

These look like split missions but are actually **infrastructure** — keep them.

| File | Why keep separate |
|---|---|
| `front/common/api.js`               | Future API client — will replace mocks |
| `front/common/api-seeds.js`         | Mock data for `api.js` |
| `front/common/auth.compiled.js`     | Auth + permissions — orthogonal to features |
| `front/common/shell.compiled.js`    | Top nav / shell — touches every module |
| `front/common/icons.compiled.js`    | Icon lookup — pure registry |
| `front/common/tokens.js`            | Design tokens — pure constants |
| `front/accounting/pos-gl-bridge.js` | Event listener; isolated by source |
| `front/accounting/stock-gl-bridge.js` | Event listener; isolated by source |
| `front/accounting/acct-invoice-helpers.js` | Tiny helper module |

---

## Questions for the developer doing this

If anything is unclear, ask before merging:

1. Does the source file have its own IIFE? (Most do — strip the inner `(function(){...})();` and keep only one outer wrapper.)
2. Does the source file write to `window.X`? Keep that line — other files depend on it.
3. Does it depend on `React.useState` etc. via destructuring? Hoist that to the top of the merged IIFE once.
4. Does the file have a `// ─── §N ───` divider already? Use that as the section name.

---
---

# 📘 Appendix A — Worked Example (do this one first)

This is **Pass 1.2 fully worked out** so you see the exact pattern. Once you've done this one, every other merge in the guide follows the same shape.

## The 3 source files (real, in this repo)

```
front/accounting/accounting-data.js          (677 lines, defines window.AcctData)
front/accounting/accounting-data-extra.js    (328 lines, extends window.AcctData)
front/accounting/accounting-data-live.js     (233 lines, monkey-patches window.AcctData)
```

**Why this order matters:** the live shim reads `window.AcctData` and *replaces* its functions with reactive versions. If you paste the live shim before the fixtures, `window.AcctData` doesn't exist yet → crash. **Always: fixtures → extras → live shim.** The guide tables list source files in dependency order; respect it.

## What each source file currently looks like (truncated)

**File 1 — `accounting-data.js`:**
```js
// ═════════════════════════════════════════════════════════════════════════
// SAAED BOOKS — Accounting fixtures + state
// ═════════════════════════════════════════════════════════════════════════
(function(){
  // ... 670 lines of code ...
  window.AcctData = AD;
  window.AcctHooks = HOOKS;
  window.AcctTweaks = { /* ... */ };
})();
```

**File 2 — `accounting-data-extra.js`:**
```js
// ═════════════════════════════════════════════════════════════════════════
// SAAED BOOKS · Extra seed data — Periods, Opening Balances, Recurring JEs
// ═════════════════════════════════════════════════════════════════════════
(function () {
  if (!window.AcctData) {
    console.warn('[acct-data-extra] AcctData missing; load order issue');
    return;
  }
  const PERIODS_2026 = [ /* ... */ ];
  // ... 320 lines ...
  window.AcctData.vatPeriods = ...;
  window.AcctData.openingBalances = ...;
  window.AcctData.recurringJEs = ...;
})();
```

**File 3 — `accounting-data-live.js`:**
```js
// ═════════════════════════════════════════════════════════════════════════
// SAAED BOOKS · Live view shim
// ═════════════════════════════════════════════════════════════════════════
(function(){
  'use strict';
  if (!window.AcctData)  { console.warn('[AcctDataLive] AcctData missing, skipping');  return; }
  if (!window.AcctStore) { console.warn('[AcctDataLive] AcctStore missing, skipping'); return; }
  const AD = window.AcctData;
  const AS = window.AcctStore;
  // ... 220 lines that overwrite AD.invoices(), AD.kpis(), etc. ...
})();
```

## What the merged file looks like

**Target — `front/accounting/accounting-data.js` (overwrite):**

```js
// ════════════════════════════════════════════════════════════════
// SAAED BOOKS · DATA  (mock fixtures + live shim)
// 
// Backend mapping (when MOCK_MODE=false this layer goes away):
//   §1 fixtures → seeders + factories in DalseenSeeder
//   §2 extras   → Recurring JE table, period_checks() RPC
//   §3 live     → no backend; merges AcctStore writes into AcctData reads
//
// Sections:
//   §1  STATIC FIXTURES         (line ~30)
//   §2  RECURRING / CHECKS      (line ~700)
//   §3  LIVE SHIM               (line ~1030)
// ════════════════════════════════════════════════════════════════

(function(){
  'use strict';

  // ════════════════════════════════════════════════════════════════
  // §1  STATIC FIXTURES   ← was: accounting-data.js
  // ════════════════════════════════════════════════════════════════

  // [PASTE everything that was BETWEEN the outer (function(){ and })(); 
  //  of the original accounting-data.js — DO NOT include those wrappers]

  // §1 ends with: window.AcctData = AD; window.AcctHooks = HOOKS; window.AcctTweaks = ...

  // ════════════════════════════════════════════════════════════════
  // §2  RECURRING / CHECKS   ← was: accounting-data-extra.js
  // ════════════════════════════════════════════════════════════════

  // The original had:
  //   if (!window.AcctData) { console.warn(...); return; }
  // ⚠️ DELETE that guard — we're now in the same IIFE that just defined it.
  //    Keeping the `return` would skip §3.

  // [PASTE the rest of the inner contents of accounting-data-extra.js]

  // ════════════════════════════════════════════════════════════════
  // §3  LIVE SHIM   ← was: accounting-data-live.js
  // ════════════════════════════════════════════════════════════════

  // The original had:
  //   if (!window.AcctData)  { console.warn(...); return; }
  //   if (!window.AcctStore) { console.warn(...); return; }
  // ⚠️ DELETE the AcctData guard (we just defined it above).
  // ⚠️ KEEP the AcctStore guard — AcctStore is in a different file
  //    that may load later. Convert the `return` to an `if/else`:

  if (window.AcctStore) {
    // [PASTE the rest of the inner contents of accounting-data-live.js]
  } else {
    console.warn('[AcctDataLive] AcctStore missing, skipping live shim');
  }

})();
```

## The exact rules you applied

1. **Outer IIFE wrapper:** kept ONE — `(function(){ ... })();` around everything.
2. **Inner IIFE wrappers:** stripped — each source's own `(function(){` and `})();` removed.
3. **`'use strict';`:** kept once at the top of the outer IIFE.
4. **Cross-file guards (`if (!window.AcctData) return;`):** removed — they were defending against load-order issues that no longer exist now that everything is in one file.
5. **External dependency guards (`if (!window.AcctStore) return;`):** kept, but converted from `return` (which would abort our whole IIFE) to `if/else` (which only skips that section).
6. **Section dividers:** added between each pasted block, naming the original source file.

## HTML script tags before/after

**Before:**
```html
<script src="front/accounting/accounting-data.js?v=1"></script>
<script src="front/accounting/accounting-data-extra.js?v=1"></script>
<script src="front/accounting/accounting-data-live.js?v=1"></script>
```

**After:**
```html
<script src="front/accounting/accounting-data.js?v=2"></script>
```

Two lines deleted, one cache-buster bumped from `v=1` to `v=2`.

## Smoke test for this specific merge

1. Reload `index.html`.
2. Open browser console. **Required logs:**
   - `[AcctDataLive] live shim installed · AcctData now reflects AcctStore`
   - **No** errors, no `Cannot read properties of undefined`.
3. Click **SAAED Books** in top nav.
4. Click **Periods** sub-tab → see "Fiscal year 2026" with 12 month chips. (← exercises §2)
5. Click **Opening** sub-tab → see "Trial balance brought forward · 1 Jan". (← exercises §2)
6. Click **Recurring** sub-tab → see 3 recurring entries. (← exercises §2)
7. Click **Sell** sub-tab → click **+** → fill Quick Invoice → Submit. (← exercises §3 reactivity)
8. Click **Journal** sub-tab → confirm new JE appears at top. (← exercises §3)

If all 8 pass, **Pass 1.2 is done**. Move to Pass 1.1.

---

# 📕 Appendix B — Common Pitfalls

These are the 6 things that actually break in practice. Read once before your first merge.

## Pitfall 1 — Duplicate `const` declarations

**Symptom:** `Uncaught SyntaxError: Identifier 'Icon' has already been declared`

**Cause:** Many compiled files start with `const Icon = window.Icon;` or `const { useState, useMemo } = React;`. When you paste two such files into one IIFE, you have two `const Icon` in the same scope.

**Fix:** Hoist these to the top of the outer IIFE, declare them ONCE:

```js
(function(){
  'use strict';
  const Icon = window.Icon;
  const { createElement: h, useState, useMemo, useEffect, useReducer, useRef } = React;

  // §1 — paste source 1 here, but DELETE its own `const Icon = ...` and `const { useState ... } = React`

  // §2 — paste source 2 here, but DELETE its own `const Icon = ...` and `const { useState ... } = React`

})();
```

## Pitfall 2 — Style-object name collision

**Symptom:** Layout looks slightly wrong on one tab — buttons mis-coloured, padding off — but no console error.

**Cause:** Two files both declared `const styles = { ... }` at module scope. After merge, the second `styles` overwrites the first.

**Fix:** Find every `const styles = ` in your sources. Rename each to be section-specific BEFORE merging:
- `const settingsHubStyles = { ... }`
- `const settingsCoaStyles = { ... }`

Then update every `styles.x` reference inside that section to the new name.

## Pitfall 3 — JSX vs JS file extensions

**Symptom:** `Uncaught SyntaxError: Unexpected token '<'`

**Cause:** A `.compiled.js` file holds plain JS using `React.createElement(...)` calls. A `.jsx` file holds JSX (`<div>...</div>`) and **must** be loaded with `<script type="text/babel">`. If you merge a JSX file into a `.compiled.js` file, Babel doesn't run on it.

**Fix:** Match extensions. Merge JSX with JSX (target `.jsx`, loaded as `<script type="text/babel">`). Merge plain JS with plain JS (target `.compiled.js`, loaded as plain `<script>`). Don't mix.

## Pitfall 4 — `return` statements that abort the wrong scope

**Symptom:** Later sections of the merged file silently don't run. No error, just missing UI.

**Cause:** Source files used `if (!window.X) return;` as an early-exit guard for their own IIFE. Inside the merged IIFE, that `return` now aborts ALL remaining sections.

**Fix:** Convert each guard from `return` to `if (window.X) { ... }` wrapping that section. See the worked example §3 above.

## Pitfall 5 — Missing `window.X` exposures after merge

**Symptom:** Some other file later calls `window.AcctTweaks.get()` and crashes with `undefined`.

**Cause:** When stripping the inner IIFE, you accidentally deleted the `window.AcctTweaks = { ... }` line that was at the bottom.

**Fix:** Before pasting, search each source file for every `window.X = ...` line. Confirm each one survives into the merged file. After merging, run this in the console to verify all globals are restored:

```js
['AcctData','AcctHooks','AcctTweaks','AcctStore','AcctView','AcctJE','AcctFlow']
  .map(k => k + ': ' + (typeof window[k]))
```

All should be `'object'` or `'function'`. None should be `'undefined'`.

## Pitfall 6 — Cache-buster forgotten

**Symptom:** You merged the file, but the browser still shows the old behaviour or throws errors referencing files you already deleted.

**Cause:** Browser cached the old `?v=1` and didn't re-fetch.

**Fix:** Always bump `?v=N` to `?v=N+1` on every changed `<script>` tag, even if the filename is the same. Hard-refresh (Cmd-Shift-R / Ctrl-F5) once after changes.

---

# 📗 Appendix C — Per-Pass Verification Scripts

Concrete click-paths. Run after each pass.

## Pass 1 verification — Accounting (12 → 3 files)

Paste this in the browser console after reload:

```js
// 1. Globals exist
const globals = ['AcctData','AcctHooks','AcctTweaks','AcctStore','AcctView','AcctJE','AcctFlow','AcctTabJournal','AcctTabGL','AcctTabPeriods','AcctTabOpening','AcctTabRecurring','AcctTabVAT'];
const missing = globals.filter(k => typeof window[k] === 'undefined');
console.log(missing.length === 0 ? '✅ all globals present' : '❌ missing: ' + missing.join(', '));

// 2. Fixtures count
console.log('JEs:', window.AcctData.journalEntries.length, '· COA:', window.AcctData.coa.length, '· Periods:', window.AcctData.vatPeriods?.length);
```

Then click through manually:

1. **SAAED Books** in top nav
2. Click each sub-tab in order: **Home → Sell → Collect → Spend → Pay → Banking → Journal → GL → Recurring → Chart of Accounts → Opening → Periods → VAT · ZATCA → Reports → Settings**
3. On each tab, confirm the page renders without "—" or empty placeholders where data should be.
4. **Settings** sub-page: click each side-nav item: Company, Tax, Numbering, Approvals, Cadence, Day-zero, Fixed Assets, Integrations
5. **Open a flow:** click **+** button → "Quick Invoice" → fill name + 100 SAR → Submit → toast appears → Journal tab shows new JE at top.
6. **Open another flow:** **+** → "Manual JE" → add 2 lines (Dr 100 / Cr 100) → Submit.

**Pass criteria:** all clicks render, console clean, both flows complete.

## Pass 2 verification — Owner / Platform

```js
const globals = ['OwnerHome','OwnerSubmodules','OwnerData','PlatformAdmin','PlatformScreens','PlatformHealth'];
const missing = globals.filter(k => typeof window[k] === 'undefined');
console.log(missing.length === 0 ? '✅ globals OK' : '❌ missing: ' + missing.join(', '));
```

Click-path:

1. **Owner Console** in top nav → Home renders with KPIs
2. Click **HR & Staff** badge → opens HR shell
3. **My Plan**, **Invoices**, **Support** tabs all render
4. Open **Command Center** (top nav) → see platform admin
5. Click any tenant row → tenant detail page opens

## Pass 3 verification — HR

```js
const hrGlobals = ['HRShell','HRStaff','HRDirectory','HRPayroll','HRLeave','HRRoster','HRPerf','HRLearning','HROrg','HRRoles','HRAssets','HRFlows'];
const missing = hrGlobals.filter(k => typeof window[k] === 'undefined');
console.log(missing.length === 0 ? '✅ HR globals OK' : '❌ missing: ' + missing.join(', '));
```

Click-path:

1. **HR & Staff** badge in top nav
2. Click each side-nav item: **Directory, ATS, Contracts, Payroll, Expenses, Loans, Leave, Roster, Performance, Learning, Helpdesk, Org Chart, Roles, Assets**
3. On Directory: click any employee row → detail panel opens with Personal / Employment / Documents tabs
4. On Payroll: open the latest period → see line items
5. On Leave: file a new request via **+** → submit

## Pass 4 verification — Retail

```js
const retailGlobals = ['Retail','RetailFlow','RetailCheckout','RetailInventory','RetailOps','POSFlow','ZFFlow','InventoryHub','AddProduct'];
const missing = retailGlobals.filter(k => typeof window[k] === 'undefined');
console.log(missing.length === 0 ? '✅ Retail globals OK' : '❌ missing: ' + missing.join(', '));
```

Click-path:

1. **POS · Sell** badge → POS opens fullscreen
2. Add 2 items → checkout → pay cash → receipt shows
3. **Products & Inventory** badge → grid of products renders
4. Click **+ Add Product** → wizard opens (3 steps)
5. **Ops Hub** → click each tab: Tasks, Shifts, Approvals, Audit, Branches

---

# 📙 Appendix D — Rollback Procedure

If a smoke test fails, recover in this order:

## Step 1 — Identify what broke

Check the browser console. The error tells you which file:

| Error | Cause | Fix |
|---|---|---|
| `Cannot read properties of undefined (reading 'X')` on load | One of the source files' globals didn't get exposed | Search merged file for `window.X = ` — make sure the assignment survived |
| `Identifier 'X' has already been declared` | Pitfall 1 | Hoist the duplicate `const` to the top of the outer IIFE |
| `Unexpected token '<'` | Pitfall 3 | Wrong file extension / script tag type |
| Layout broken but no error | Pitfall 2 | Search for `const styles = ` collisions |
| One section silently missing | Pitfall 4 | Find the `return` you forgot to convert |

## Step 2 — Revert one file at a time

If you can't immediately spot the cause:

1. Open the archived sources from `archive/pre-consolidation/<module>/`
2. In `index.html`, comment out the merged `<script>` line
3. Re-add the original `<script>` lines one at a time (with `?v=99` to bust cache)
4. Reload after each — when console goes clean, you've isolated which source is in conflict
5. Compare that source's bottom (its `window.X = ...` exposures) against your merged file

## Step 3 — Last resort

Restore everything for that pass from `archive/pre-consolidation/`:

```bash
# pseudo-shell — adjust to your tooling
mv archive/pre-consolidation/accounting/* front/accounting/
# revert the HTML script-tag block in index.html to the BEFORE state from the guide
```

Then post the console error in our chat and I'll pinpoint it before you retry.

---

# 📒 Appendix E — Mental Model (read this first)

Why does this consolidation work?

**Every "compiled" file in this repo is a script that runs in browser global scope and exposes things on `window`.** There's no module system, no `import`, no bundler. Files are concatenated by the browser via `<script>` tags in `index.html`.

That means **merging two files is mechanically equivalent to changing the order of `<script>` tags AND deleting the boundaries between them.** Nothing that worked before stops working — as long as:

- Globals (`window.X = ...`) still get exposed
- Local scopes (the `(function(){ ... })()` IIFEs) still isolate variables that shouldn't leak
- Load order between merged groups is preserved

This is also why **a backend developer reading the merged file sees the truth more clearly than reading 23 files:** they get the actual execution order in one scroll, with section headers naming each Postman folder.

**The mental shift:** stop thinking "these files do different things." Start thinking "these files are one thing arbitrarily split during development. We're un-splitting them."
