# Features — indawo_84

Evidence date: 2026-10-12. Revision: `main` `6ce3e8d` (2026-10-12, "days differences added").

The UI name is Indawo Online. The repository name is `indawo_84`.

`CHANGELOG.md` records PHP 8.4 fixes through 2026-02-11 only. Features changed after that date are taken from Git history and the current tree.

## Current features (`main`)

### Access and administration

| Feature | What it does | Evidence | Status |
|---|---|---|---|
| Login gate | `index.php` sends anonymous users to `login.php` and signed-in users to `home.php` | `index.php` | Implemented |
| Email, password, and shared PIN | Active, unlocked user in an active security group; password via `NemoPassword`; PIN from system settings | `login.php` | Implemented |
| Password expiry and reset | Expired passwords are rejected when the expiry check setting is `true`. Reset page exists | `login.php`, `resetPassword.php` | Implemented |
| TOTP MFA | Setup and verify pages. Issuer "Indawo Online". QR via Endroid. Remember-device rows in `tblUserMFARememberedDevices` | `two.factor.authentication.*.php`, `MFATables.sql`, `composer.json` | Implemented |
| Users | User maintenance | `user.php`, `includes/user.cls.php` | Implemented |
| User settings | Per-user settings screen | `user.settings.php` | Implemented |
| Security groups | Menu editor with view, new, save, delete, special | `security.group.php`, `includes/security.group.cls.php` | Implemented |
| Companies | Company records, including remote database and folder path used by sync and files | `company.php`, `includes/company.cls.php`, `setOWC()` | Implemented |
| Sales people | Sales-person maintenance | `sales.person.php`, `includes/sales.person.cls.php` | Implemented |
| Settings | System settings screen | `settings.php`, `includes/settings.cls.php` | Implemented |
| Usage log | Usage log screen and online usage report | `usage.log.php`, `onlineUsage.rpt.php` | Implemented |
| My tasks | Task list for the signed-in user | `my.tasks.php`, `includes/my.tasks.cls.php` | Implemented |
| Messages | Internal messages | `message.php`, `message.incl.php` | Implemented |
| Email | Email log, templates, online read, read receipt | `email.php`, `email.template.php`, `email.read.online.php`, `email.read.receipt.php` | Implemented |
| HTTP cron gate | Browser cron URLs require login and menu view, or ODBC basic auth | `.htaccess`, `http_cron_gate.php` | Implemented |
| Denied utility URLs | Apache deny for `.env`, `info.php`, ODBC connect scripts, sandbox, `_sync.php`, `_debug_*` | `.htaccess` | Implemented |

### Commercial and job operations

| Feature | What it does | Evidence | Status |
|---|---|---|---|
| Clients | Client list and edit. Realtime sync entity `Client` | `client.php`, `includes/client.cls.php` | Implemented |
| Contacts | Contact list and edit. Realtime sync entity `Contact` | `contact.php`, `includes/contact.cls.php` | Implemented |
| Contact log | Contact activity log | `contact.log.php`, `includes/contact.log.cls.php` | Implemented |
| Jobs (Foreman) | Job edit. Realtime sync entity `Foreman` | `job.php`, `includes/foreman.cls.php` | Implemented |
| Enquiries | Enquiry edit on the same Foreman model | `enquiry.php` | Implemented |
| Job types | Job type maintenance | `job.type.php`, `includes/job.type.cls.php` | Implemented |
| Job suggestions | Suggest field changes. Accept (status 1) writes `tblForeman`. Decline (status 2) does not. Approver stored | `job.suggestion.php`, `includes/job.suggestion.cls.php` | Implemented |
| Approver column | Approvals list column "Approved / Declined By" | `includes/foreman.cls.php` `getJobSuggestionList`, commit `223198b` | Implemented |
| Money impact | Current vs suggested labour, material, subcontractor, total cost, contract value, gross profit, GP%. Order budget verdict | `includes/job.money.impact.inc.php` | Implemented |
| Date differences | Planned vs actual start, finish, and duration, and suggested date changes. Missing dates include `0000-00-00` and `2000-01-01` | `includes/job.money.impact.inc.php` `jobDateNowHtml`, `jobDateAcceptedHtml`, commit `6ce3e8d` | Implemented |
| Pre-start agreement | Pre-start workflow. Inserts job suggestions at status 0 | `prestart.agreement.php`, `includes/prestart.agreement.cls.php` | Implemented |
| Budget adjustment | Budget adjustment workflow | `budget.adjustment.php`, `includes/budget.adjustment.cls.php` | Implemented |
| Orders | Purchase orders | `order.php`, `includes/order.cls.php` | Implemented |
| Order authorisation | Admin and production authorisation list, pending rows sorted first | `order.authorisation.php`, `includes/order.authorisation.cls.php` | Implemented |
| Raise invoice | Invoice request and PDF | `raiseInvoice.php`, `includes/raiseInvoice.cls.php`, `includes/invoicePDF.cls.php` | Implemented |
| Assets | Asset contacts and movements. Empty movement dates stored as NULL | `asset.contact.php`, `asset.movement.php`, commit `5534919` | Implemented |
| Search | Search page | `Search.php` | Implemented. What it searches is **Unknown** without a full read |
| Archived | Archived view | `archived.php` | Implemented. Scope **Unknown** |
| KPI | KPI screen | `kpi.php` | Implemented |

### Dashboards and reports

| Feature | What it does | Evidence | Status |
|---|---|---|---|
| Home | Landing page after login | `home.php` | Implemented |
| Sales-person dashboard | SP home and a large user dashboard class | `dashboard.sp.php`, `includes/dashboard.home.sp.cls.php`, `includes/dashboard.sp.cls.php`, `includes/dashboard.users.cls.php` | Implemented |
| Contract-manager dashboard | CM dashboard | `dashboard.cm.php`, `includes/dashboard.home.manager.cls.php` | Implemented |
| Cash under/over | Amount paid minus (labour + material) × 1.3 minus subcontractor excluded from the 1.3 factor. Shared by the cash-flow PDF and the SP dashboard | `cron.CashFlow.php`, `includes/dashboard.users.cls.php`, commit `41f6b52` | Implemented |
| Foreman reports | Budget vs actual, labour vs invoiced, prime ratios, overspent | `reportForeman.php`, `includes/reports/foreman/` | Implemented |
| QS incentive | QS incentive and fiscal summary | `reportQSIncentive.php`, `includes/reports/qsincentive/` | Implemented |
| Asset reports | Asset list report | `reportAssetManagement.php`, `includes/reports/assetmanagement/` | Implemented |
| Other reports | Referred-by, online usage, contact-log follow-up, enquiry follow-up | `includes/reports/other/` | Implemented |
| Charts | Highcharts assets | `charts/`, `plugins/Highcharts/` | Implemented library. Which pages bind it was not fully mapped |

### Sync, files, and operations

| Feature | What it does | Evidence | Status |
|---|---|---|---|
| Nightly lookup pull | Client type, sales person, job type, supplier | `Cron.daily.1.Lookups.php` | Implemented |
| Nightly client pull | Client, contact, customer | `Cron.daily.2.Clients.php` | Implemented |
| Nightly Foreman pull | Job headers, then financials, then costings and history | `Cron.daily.3.Foreman.php` through `Cron.daily.5.Foreman.php` | Implemented |
| Excel dumps | Per-company and combined Foreman dumps | `Cron.daily.6.DataDumps.php`, `cron.DataDumps.php` | Implemented |
| Manual full sync | On-demand chain plus dumps | `cron.daily.manuel.php` | Implemented |
| Cash-flow PDFs | Per-company PDFs. May doc: generated on Monday or the 23rd only | `cron.CashFlow.php`, `Cash Flow Report/` | Implemented. Tracked PDFs exist even though the folder is gitignored |
| Order-auth email | Emails pending authorisations | `cron.daily.orderauth.php` | Implemented |
| Monthly order cancel | Cancels old `New` orders for company 1 on the 15th | `cron.daily.ordercancel.php` | Implemented |
| Realtime sync queue | Logs push attempts and JSON snapshots. Ensures table columns | `includes/syssyncqueue_schema.inc.php`, `_sync.cls.php` | Implemented |
| Morning catch-up | Re-applies pending queue values after the SQL-to-MySQL pull, then pushes | `cron.morning.realtime-catchup.php`, `includes/realtime_morning_catchup.inc.php` | Implemented |
| Evening retry | Retries open failures from the last 7 days | `cron.evening.realtime-retry.php`, `includes/realtime_retry.inc.php` | Implemented |
| Realtime entity set | Client, Contact, Foreman, Foreman Job Start End Date History | `includes/realtime_entities.inc.php` | Implemented |
| `realTimeSync` guard | Local/QA can refuse normal-page pushes to production SQL Server | `env`, `system.php`, `_sync.cls.php` | Implemented |
| ODBC dashboard | Connectivity, cron map, test rows, queue, manual pull and retry | `ODBC_connections.php`, `README-odbc-dashboard.txt` | Implemented |
| Friday test cleanup | Deletes marked ODBC test rows | `cron.friday.odbc-test-cleanup.php`, `includes/odbc_test_cleanup.inc.php` | Implemented |
| Sync error email | Helper for batch sync errors | `includes/sync_error_email.inc.php` | Implemented |
| SharePoint file links | Rewrites job/enquiry file links. Three-year archive alert | `includes/foreman.cls.php` | Implemented |
| Local filesystem redirect | Localhost writes under `./indawo_filesystem/` instead of `/var/www/html/indawo_filesystem/` | `getFilesystemBase()` | Implemented |
| ODBC regression script | CLI checks for NULL ratings, zero dates, GROUP BY, toolbar buttons, SharePoint URLs | `tests/ett_odbc_regressions.php` | Implemented |
| Environment template | Commented `.env` keys for DB, SQL ODBC, and `realTimeSync` | `env`, `setup_composer.md` | Implemented |
| Sonar pipeline | SonarQube scan step | `bitbucket-pipelines.yml` | Implemented for branch pattern `{master}` only |

## Recently changed

| When | Change | Status |
|---|---|---|
| 2026-10-12 | Date-difference tables on job impact (`6ce3e8d`) and impact column layout/colours (`4099f45`) | Implemented |
| 2026-10-07 | Cash under/over no longer multiplies subcontractor actuals by 1.3 (`41f6b52`) | Implemented |
| 2026-10-01 | Authorisation money impact added, briefly undone, then included again (`9d28fe3`, `7342054`, `a16c9c5`) | Implemented on `main` |
| 2026-09-30 | Luvthis job numbers quoted in the Cron 3 percent insert (`cc78bb4`) | Implemented |
| 2026-09-21 | Suggestion list shows who approved or declined (`223198b`) | Implemented |
| 2026-09-06 to 2026-09-14 | Realtime queue re-apply skips CASE/JOIN mappings; cron HTTP gate; `.env` on the live site; SharePoint links | Implemented |
| 2026-02-03 to 2026-02-11 | PHP 8.4 null and quoting fixes across Nemo, login, sync, dashboards | Implemented. Recorded in `CHANGELOG.md` |

## Planned

| Item | Evidence | Status |
|---|---|---|
| Realtime queue, retry, and morning re-apply | June 2026 plan `docs/INDAWO-Realtime-Sync-Queue-Retry-Implementation-Plan.md` | The plan is written as section-by-section work waiting for human sign-off. The queue, retry cron, morning catch-up, and ODBC dashboard hooks are present on `main`. Which plan sections were signed off is **Unknown / Requires Confirmation** |
| Repeater incremental sync | `cron.daily.repeater.update.php` still prints that it is a temporary file. The May document recommends disabling it or implementing it | Planned only in the sense that the schedule slot exists. The body is not a sync. **Inferred** unfinished |
| `ONLY_FULL_GROUP_BY` restoration | `docs/ONLY-FULL-GROUP-BY-Cursor-Plan.md`, commit `bb1b2f0` | Plan document. Individual query fixes exist (`36aea37`, `0b7970e`). Whether the whole plan is done is **Unknown** |
| Changelog catch-up | `CHANGELOG.md` ends 2026-02-11 | Not a product feature. The log is behind `main` |

No other roadmap file was found.

## Deprecated, copied, or unused-looking files

These files are on `main`. "Unused" is **Inferred** from names and from the absence of references found during this pass. It was not proved by a full call graph.

| File | Note |
|---|---|
| `systemOld20260203.php`, `Zsystem.php` | Older system bootstrap kept beside `system.php` |
| `includes/cron.daily.php`, `cron.daily2.php`, `cron.daily.jobs.php`, `Zcron.daily.php` | May document lists the monolithic daily cron as not in the live crontab |
| `cron.daily.repeater.update.php` | Placeholder |
| `cron.CashFlow - B VAT.php`, `cron.CashFlow - B VAT Update.php` | VAT copies beside `cron.CashFlow.php` |
| `includes/order.cls - B VAT.php`, `includes/order.cls - B VAT Update.php`, and the same pattern for `foreman.cls`, `raiseInvoice.cls`, `prestart.agreement.cls`, `dashboard.users.cls` | Parallel copies. Which one production includes is the unsuffixed class unless a page says otherwise. Pages include the unsuffixed names that were seen |
| `includes/dashboard.users.cls.php_2025_03_25.php` | Dated copy |
| `includes/reports/assetmanagement/asset.list.rpt - Copy.php` | Copy |
| `project.functions.inc.php_2023_01_19`, `Cron.daily.6.DataDumps.php_2023_01_19` | Dated copies were in the broken checkout listing; confirm they are still blobs if a deploy script copies by wildcard |
| `order.php_20221215` | Dated copy present as an untracked path during the failed first checkout; not relied on |
| `email.test.php`, `info.php`, `zSandBox.php`, `odbc_connect.php` | Present and denied by Apache |
| Vendored `mpdf/` examples and Highcharts Java export server | Third-party trees committed with the app |

## Removed relative to older documents

| Older statement | Current `main` |
|---|---|
| May 2026 doc: no `sysSyncQueue`, no retry, realtime failure is not queued | Queue, morning catch-up, and evening retry exist |
| May 2026 doc: repeater does nothing | Still true |
| Folder links to `filesys.indawo.local` | Regression test expects SharePoint URLs and rejects that host |

## Requires confirmation

- Whether the VAT-suffixed class copies are still deployed by any host.
- Whether `development` or `staging` contain features that are not on `main`.
- Whether the ODBC feature branch `feature/odbc-connections-dashboard` (`3cbf504`) is already merged in substance or still has unique work. It was not checked out.
