# Nowills SQC ERP — Full System Audit
**Date:** 7 Sep 2026 · **Auditor:** Arena Agent (automated code + data audit)
**Verdict:** The ERP is *analytically complete* (31/31 dashboards live) and *transactionally deep*
(78 CRUD entities + 23 document workflows). Remaining work is: (A) making the dashboard
actionable, (B) a short list of missing backend features, (C) hardening.

---

## 1. Verified inventory — what already exists ✅

| Layer | Count | Detail |
|---|---|---|
| Dashboard modules (Command Centre) | 31/31 | All live on `/api/v1/*`, 12 KPIs each, charts + drill-down tables |
| Eloquent models | 100 | Full quarry→construction→finance domain |
| Generic CRUD entities (`app/Support/CrudRegistry.php`) | 78 | Masters, logs, diaries, budgets, HSE, assets, sequences, audit logs |
| Dedicated document controllers | 23 | PO/SO/PI/SI/GRN/journal/payroll/IPC/claims/payments/WO/weighbridge… |
| Posting/transition actions | 20+ | post, approve, convert, pay, reconcile, reverse, close, cancel, send… |
| Approval engine | 8 flows | PR, PO, leave, advance, expense, quotation, subcon claim, client IPC (+ decide endpoint + queue UI) |
| Reports (`ReportController`, 9 groups) | 43 | Production, sales, purchase, inventory, fleet, projects, HR, finance/tax, HSE — **CSV export works** (`?export=csv`) |
| Print templates (HTML) | 10 | Quotation, SO, delivery, SI, LPO, GRN, journal, payment, weighbridge, WO |
| RBAC | 13 roles / 63 perms / 5 users | Module-level `*.view/create/edit/delete/approve/post` permissions |
| Ghana localisation | ✅ | VAT 15%, NHIL/GETFund/COVID levies, WHT 3%/7.5%, PAYE bands, SSNIT 5.5/13.5, EPA + mining-licence tracking |
| Backup | ✅ manual | One-click mysqldump download (`settings.backup`) |
| Audit trail | ✅ | 2,213 events; `audit-logs` browser in classic UI |

**Classic UI** (`/dashboard` + Blade pages) covers data entry; **Command Centre** (`/command`)
covers analytics. Auth is session-based; all routes sit behind `auth`.

---

## 2. Gap list — features remaining to be developed 🛠️

### Track A — Make the dashboard actionable (biggest UX gap)
The Command Centre JS contains **only 2 write calls** (login/logout). Everything else is read-only.

| # | Feature | Why | Size |
|---|---|---|---|
| A1 ✅ | **Inline Approve/Reject in `#/wflow`** *(shipped 7 Sep 2026 — dialog + POST + cache-bust, 403-safe)* | Queue exists, `approvals.decide` endpoint exists — just needs buttons + remarks modal | S |
| A2 ✅ | **"+ New" quick-create per module** *(shipped 7 Sep 2026 — quick toolbar on all 31 modules; generic schema modal gives real inline create for 21 CRUD entities + deep links for document flows)* | At minimum deep-link to classic create pages; ideally modal forms | M |
| A3 ✅ | **KPI & row drill-through** *(shipped 7 Sep 2026 — 375/384 KPIs link to workspaces via central map; record modals carry Open-record + workspace links; 9 now-linked tables)* | Click a card/table row → filtered classic list (e.g. Overdue Bills → PI list) | M |
| A4 ✅ | **Actionable AI recommendations** *(shipped 7 Sep 2026 — 7 deep links to source docs)* | `#/ai` P1–P3 actions should link to the underlying document | S |
| A5 | **Notifications bell + My Tasks inbox** | ✅ SHIPPED: live "My Tasks" panel atop the B2 inbox — approvals I can decide (deep-linked to source docs) + overdue GRA filings + equipment docs expiring ≤30d, all perm-gated; verified (5 tasks: 3 approvals + 1 overdue + 1 expiry) | M |
| A6 | **Global search** (docs, customers, suppliers, equipment…) | ✅ SHIPPED: Ctrl/⌘+K palette in classic shell (debounced, grouped, arrow/enter/esc nav) + `/search` over 10 entities (customers, suppliers, equipment, employees, projects, products, invoices, LPOs, quotations, journals), each perm-gated; verified ("consar"→customer, "yaw"→employees for admin but customers-only for accountant) | M |
| A7 ✅ | **Per-table CSV export buttons** *(already present in toolbar — verified on all tables 7 Sep 2026)* | Client-side CSV helper exists in JS — wire it to every dashboard table | S |
| A8 ✅ | Remove dead legacy link `/phase1#/companies` *(shipped 7 Sep 2026 — now points to `/settings/company`)* | Found in CC JS; goes nowhere | XS |

### Track B — Missing backend features

| # | Feature | Current state | Size |
|---|---|---|---|
| B1 | **PDF generation** (invoices, LPOs, payslips, statements, IPC certs) | ✅ SHIPPED: dompdf ^3.1 + `PdfService`; `?pdf=1` on all 10 print routes + payslip + `?export=pdf` on all 46 reports; 📄 buttons on show pages & report pages; doc numbers verified inside all PDFs; HTML print regression-clean | M |
| B2 ✅ | **Email + in-app notifications** *(shipped 7 Sep 2026 — ApprovalRequested/Decided + RiskDigest, mail+database, queued, bell + inbox UI)* | `mail.php` configured but **zero** `Mail::`/Notification usage; no `app/Notifications` | M |
| B3 ✅ | **Scheduler + queued jobs** *(shipped 7 Sep 2026 — digest 06:30 daily, backup Sun 02:00, failed-job prune; DB queue)* | `routes/console.php` is stock Laravel (only `inspire`); no Jobs/Events | M |
| B4 ✅ | **Period close / year-end lock** *(shipped 7 Sep 2026 — FiscalService guard at GL choke points, close/reopen UI, 🔒 pill)* | `fiscal_years.is_closed` flag exists but **nothing sets it**; posted periods editable forever | S–M |
| B5 | **Fixed-asset depreciation run** | ✅ SHIPPED: `DepreciationService` (straight-line, NBV-floor-capped) + `/depreciation-runs` (preview, one-click run, history); posts balanced JV Dr5260/Cr1510, unique per period, FY-close-guarded; verified live (JV-26-00049 GH₵8,923.60 = NBV drop; re-run blocked) | M |
| B6 | **Bank statement CSV import** | ✅ SHIPPED: 2-step wizard `/bank-transactions/import` (flexible CSV parser: Dr/Cr or Amount cols, 7 date fmts) + auto-match (same amount+direction, ±3 days) with match/new/skip per row, duplicate flagging; verified live (1 matched, 2 created, balance Δ exact) | M |
| B7 | **Tax filing tracker** | ✅ SHIPPED: `tax_filings` (7 GRA/SSNIT types, unique type+period, due/liability/paid/credit_cf/GRA receipt) + CRUD with draft→filed→paid transitions (auto-stamps filing date/by), outstanding + overdue computed columns; verified live incl. overdue flag; test rows cleaned | S |
| B8 | **Central document library (EDMS)** | ✅ SHIPPED: `DocumentLibraryController` + `/docs-library` (browse/search by name·owner·kind, 20MB upload with dual content+extension validation, byte-verified download, version-level delete); versions-by-filename with v-badges + history; `docs.view/create/delete` perms seeded & RBAC-verified (403s); sidebar link + CC docs QUICK bar (4 btns, jsdom-clean); library roundtrip-tested, back to 0 rows | M |
| B9 | **Drilling operations entry** | ✅ SHIPPED: `drill_logs` (pattern/burden/spacing/diameter/holes/depth, auto `total_meters` = holes×depth, DRL-numbers, planned→in-progress→completed) + CRUD + sidebar + CC QUICK inline-create + `#/drill` API (Meters Drilled/Drill Holes cards w/ drill-through + d_drill register w/ Open-record links); verified live (DRL-26-00001, 36 holes × 12.5m = 450m in API) | S–M |
| B10 | **Budget virements** | ✅ SHIPPED: `budget_virements` (VR-numbers) + dedicated form (budget→lines w/ available balances) + `VirementService` (same-budget, avail-funds, closed-budget guards) + full approval flow (`budget_virement` type, finance approvers, transfer posts on approve w/ locked re-check); verified live incl. reject + over-funds/same-line blocks; demo data restored | S |
| B11 ✅ | **Scheduled (automatic) backups** *(shipped 7 Sep 2026 — `erp:backup --keep=14`, weekly Sun 02:00)* | Manual download works; no nightly schedule, no retention, no off-site | S (needs B3) |
| B12 | Weighbridge scale hardware integration | Manual weights + `close` endpoint; serial/indicator link is a site-deployment item | L (site) |

### Track C — Hardening & quality

| # | Feature | Current state | Size |
|---|---|---|---|
| C1 | **Server-side API authorization** | ✅ SHIPPED: `$this->need('<mod>.view')` enforced in all 31 CC API endpoints, mirroring `CommandController::MODULE_PERMS` (shell already server-scopes menus; ROL preview disabled via `canPreview:false`); tightened docs/reports to their real perms (UX-neutral, all roles hold them); 403s return JSON → CC degrades to SAMPLE fallback. Verified: accountant gets hr/quarry 403 + finance/docs/reports 200; admin 200 on all 32 endpoints | M |
| C2 | **Feature test coverage** | ✅ SHIPPED (starter — extend per feature): 19 passing on sqlite :memory: — 4 `BankImportParser` unit + 3 `DepreciationService` + 3 `VirementService` + 7 `CurrencyService`/FX + ExampleTest; suite fully green | M (ongoing) |
| C3 | **Login history / sessions / password policy** | ✅ SHIPPED: `login_histories` (success+failed w/ IP + client, user-linked) + `/users/{id}/logins` UI with 30-day fail count + password policy (min 8, mixed-case, numbers, symbols) on admin create/edit + self-service profile; verified (fail+success recorded, weak rejected, strong accepted, demo creds restored) | S |
| C4 ✅ | **Multi-currency** *(shipped 7 Sep 2026 — `Currency` + `CurrencyRateHistory` + `CurrencyService`; FX on quotes/orders/DN/invoices/receipts/LPOs/GRNs/bills/payments/banks/credit-notes; GL posts in GHS; auto 4950/5650 FX gain/loss on settlement; currency-aware prints/reports/dashboards; 7 FX tests; live-verified USD sales + purchase cycles then reversed)* | — | L |
| C5 | Token API for mobile (weighbridge/dispatch app) | Session web UI only — optional future | L |
| C6 | Audit-log archiving/purge policy | ✅ SHIPPED: `erp:audit-purge --days=365` (chunked, min-30-day guard, --dry-run; covers audit_logs + login_histories), scheduled monthly; verified (2+1 old rows purged, 2,213 recent kept) | XS |

*Sizes: XS <1h · S = hours · M = 1–3 days · L = 1–2 weeks (single dev).*

---

## 3. Production ops notes (for B2/B3/B4)
- **Cron:** `* * * * * cd /path/to/nowills-sqc-erp && php artisan schedule:run >> /dev/null 2>&1`
- **Queue worker (supervisor):** `php artisan queue:work --sleep=3 --tries=3` (database driver — no Redis needed)
- **Mail:** set `MAIL_MAILER=smtp` + host/credentials in `.env` (currently `log` — mails land in `storage/logs/laravel.log`)
- **Links in mail** use `APP_URL` — set the public URL (currently `http://localhost:8000`)
- **Backups** land in `storage/app/private/backups/` (14 kept); copy off-site for DR
- **FY close** blocks GL + bank postings only; operational logs (weighbridge, diaries) stay editable by design

## 3. Recommended build order

1. **A1 + A4 + A7** (approvals inline, actionable AI, CSV buttons) — same-day wins, no schema change.
2. **B2 + B3 + B4** (notifications, scheduler, period close) — the control backbone.
3. **A2 + A3** (quick-create, drill-through) — unifies the two UIs.
4. **B1 + B8** (PDFs, document library) — external-facing polish.
5. **B5 + B6 + B7 + B10** (depreciation, bank import, tax tracker, virements) — finance depth.
6. **Track C** hardening alongside.

---
*Generated from live code inspection: routes, 53 controllers, 100 models, CrudRegistry (78 keys),
ReportController (43 reports), CC JS bundle, composer manifest, and seeded data.*
