# Features — wca_dms (Admin Overdrive)

Evidence date: 2026-09-29.

Source: `git@bitbucket.org:overdrive/wca_dms.git`, `main` at `9f51c26` (2025-09-01).

Status labels: **Current** (code path exists and is wired), **Partial** (UI, route, or client exists but the backing class or caller does not), **Documented only**, **Not present**.

No feature was marked removed. Git history is five commits on 2025-09-01 and does not show a deletion of the missing domain controllers. Whether they were omitted at "Core checkout" is **Inferred**.

## Identity and shell

| Feature | Status | Evidence |
|---|---|---|
| Admin Overdrive branded shell (logo, title, mail footer) | Current | `app/Views/layouts/header.php`, `app/Views/common/login.php`, `app/Helpers/mail_helper.php` |
| AdminKit PRO 3 shell, Bootstrap 5, Feather, DataTables | Current | `public/assets/css/app.css`, `public/assets/css/bootstrap.min.css`, `public/assets/js/` |
| Database-driven sidebar | Current | `app/Views/layouts/sidebar.php`, `app/Helpers/menu_helper.php` |
| Dashboard with zero placeholders | Current | `app/Controllers/Home.php` sets session, credit, and chart values to 0 |
| Notification bell count | Current as a static `0` | `app/Views/layouts/header.php` |
| WCA name as a product expansion | Unknown | Repository and database name only |

Seeded menu (`app/Database/Seeds/UserMenu.php`): Dashboard (`home`), Users, Media Files (`media`), System Settings, Menu Management, CRUD Generator. Categories: General, Settings, Developers (`UserMenuCategory` seed).

## Access

| Feature | Status | Evidence |
|---|---|---|
| Email and password login | Current | `Welcome::index`, `password_verify` |
| Email 2FA code, skip when last success is under 1 day | Current | `UserModel::check2faEmailConfirmationDate`, `common/2fa-validation.php` |
| Logout recorded as history status 3 | Current | `Welcome::logout` |
| Forgot / reset password, minimum 8 characters | Current | `Welcome::sendResetPasswordLink`, `resetPassword` |
| Inactive account refusal | Current | `users.active == 0` checks in `Welcome` |
| IP block list check on login construction | Current | `Welcome` constructor, `BlockedUsersModel::getBlockedIP` |
| Failure lockout (5 in 5 minutes) | Current | `LoginHistoryModel::checkFailures` |
| Login history statuses 1, 2, 3, 4, 5, 6 | Current | `Welcome.php` (wrong password, success, logout, 2FA failure, bad reset token, reset requested) |
| Role menu permissions | Current | `Users` permission methods, `Authorization` filter |
| Roles Developer, Admin, Company Admin, Company User | Current as seed data | `UserRole` seeder |
| Company scoping for roles 1–3 | Current | `Welcome::setCompanyUsersAndAdminSessionVars` |
| Company User (role 4) scoping | Not present | No branch in that method |
| Public self-registration | Not present | `Welcome::register` empty |
| CSRF on forms | Not present | Filter alias exists; global is commented out |
| Row-level security | Documented only | `README.md` |

## Users and settings

| Feature | Status | Evidence |
|---|---|---|
| User list, create, update, delete, profile | Current methods | `app/Controllers/Users.php` |
| Role create and update | Current | `Users::createRole`, `updateRole` |
| System user active flag, role change, company assignment | Current | `app/Controllers/SystemUsers.php` against `users` and `company_users` |
| General settings CRUD | Current | `SystemSettings` `getGeneralSettings` through `changeGeneralSettingActive` |
| Cron action list, add, update, activate | Current | `SystemSettings` cron methods, table `cronjob_actions` |
| Email templates and template active flag | Current | `email_template`, `EmailTemplateModel` |
| Email logs from `sent_queue` | Current | `SystemSettings::getEmailLogs` |
| Email schedule stored as JSON `{"day","time"}` on settings name `email_schedule` | Current | `SystemSettings::updateEmailSchedule` |
| Public holiday add and active toggle | Current | `public_holidays` |
| Blocked list active toggle | Current | `blocked_users_list` |
| Fault types, transport methods, companies-to-process | Partial | Routes in `Routes.php`. Methods not on `SystemSettings`. Model reads `company_transport_methods` |
| Meeting / label user groups | Partial | Routes `labels/groups/*` to `LabelUserGroups`, class absent. Table `user_groups` is migrated. `getUser` concatenates `user_groups.meeting_groups_id` |

## Operations screens (EDI Overdrive)

`app/Views/edioverdrive/readme.txt`: "Put all EDI Overdrive views in here".

| Feature | Status | Evidence |
|---|---|---|
| Company list / form / vendor numbers | Partial | Views under `app/Views/edioverdrive/company/`. Routes `company/getVendorNumbers`, `addVendorNumber`, `changeVendorNumberActive`, `updateVendorNumber` target `Company`, which is absent |
| Products list and form | Partial | Views under `edioverdrive/products/`. Routes `products`, `products/getCompanyProducts`, `getProductsList`, `addProduct`, `updateProduct` target `Products`, absent |
| Orders list | Partial | Views under `edioverdrive/orders/`. Route `orders/getOrders` targets `Orders`, absent |
| Invoices | Partial | Views under `edioverdrive/invoices/`. `invoices/getInvoices` route is commented out |
| Fault finder (orders, invoices, products) | Partial | Views under `edioverdrive/faultFinder/`. Routes `faultfinder/*` target `FaultFinder`, absent. `CronjobsModel` queries `companies` for fault assignment |
| Store page | Partial | `Store::index` exists. `store-api` resource targets `StoreApiController`, absent. View `edioverdrive/store/store.php` |
| Label status tree | Partial | Routes `labels/status/*` target `LabelStatus`, absent |
| Label email templates | Partial | Routes `labels/email-templates/*` target `LabelEmailTemplates`, absent. Table `label_email_template` is migrated |
| XML fetch | Partial | Route `getXMLData` targets `GetXMLData`, absent |
| Pick n Pay SOAP order pull and confirm | Current as library code, no caller | `app/Controllers/Soap.php` |
| Shoprite REST order pull and confirm | Current as library code, no caller | `app/Controllers/Rest.php` |
| CSV map-and-save for products and stores | Partial | `app/Controllers/Csv.php`. `ProductsModel` and `CompanyStoresModel` absent |

## Reports

| Feature | Status | Evidence |
|---|---|---|
| Reports page with four tabs | Current shell | `Reports::index`, `app/Views/reports/reportsList.php` |
| BI tab limited to roles 1 and 2 | Current in the view | `reportsList.php` |
| Uninvoiced orders, unmatched invoices, sales charts, BI charts | Partial | Tab markup and DataTables `ajax` URLs. No matching routes or controller methods. Commented route for `reports/uninvoicedOrders` |

Chart view files under `app/Views/reports/ReportCharts/`: total products, orders per month, order value per month, invoices per month, invoice value per month, daily order totals, daily order value, daily invoice totals, daily invoice value, summary.

## Mail, files, and tracking

| Feature | Status | Evidence |
|---|---|---|
| HTML mail with Admin Overdrive wrapper | Current | `app/Helpers/mail_helper.php` |
| Sent-queue insert | Current | `Email::updateSentQue` (method name spelling) writes `sent_queue` |
| Cron send of due queued mail | Current | `CronJobs::sendScheduledEmails` |
| Open pixel | Partial | `EmailPixelTracking::index` returns a PNG. `EmailPixelTrackingModel` absent |
| Media file screens | Partial | Views `mediaFile/`. Table `media_file` migrated. No `Media` controller and no `media` route were found. Authorization would still require a menu row whose URL is `media` |
| Generic upload | Partial | `POST /upload` targets `Upload::uploadFiles`. That method is not defined. `Upload` only has `index`. `GET /upload` is commented out. The class imports missing `CompanyModel` |
| Uploaded-file model | Current class | `UploadedFileModel` uses table `uploaded_file`, which has a seed and no migration found |

## Monitoring and developer tools

| Feature | Status | Evidence |
|---|---|---|
| Monitoring page and log queries | Current | `ServerMonitoring`, table `server_monitoring_log` (no migration found) |
| Alert thresholds stored in `settings` | Current | `ServerMonitoring::updateAlertThresholds` |
| Spark command `monitor:system` | Current | `app/Commands/MonitorSystemUsage.php`. Infinite loop, Linux `top`, default CPU threshold 5 and memory 50 ("hardcoded for now") |
| Cron health mail when a resource exceeds 55 log rows in 5 minutes | Current | `CronJobs::checkServerLogs` |
| Menu management | Current | `Developers/MenuManagement.php` |
| CRUD generator | Current | `Developers/CRUDGenerator.php` |
| DB table viewer and Adminer-style pages | Partial | `DbTableDataView`, `DbAdmin`, views `projects/adminer.php`. No routes found for them. Auto-route is off, so they are not reachable by URL unless a route is added outside the file that was read |
| Site health | Partial | `SiteHealth` and `SiteHealthModel` (`site_health`). No route found |
| Test project runner | Partial | `Test` and `TestLog` controllers, tables `test` and `test_log` in the model, no migrations, no routes found |
| SonarQube badges view | Partial | `app/Views/modules/sonarCubeBadges.php`. Pipeline scans `main` |
| ChatGPT page | Current | `ChatGPT`, helper calls OpenAI completions |
| Slack notify helper | Current | `slack_helper.php`. `GET slack` is public and calls `sendMessage` with an empty default message |
| Organisations REST resource | Partial | Route and `OrganisationModel` plus migration. Controller class absent |
| JWT simulation API | Not routed | `ApiSimulation` extends `ResourceController` and uses `JwtLibrary` with default secret `secret` |
| Salesforce connect | Not present | Empty helper |
| SMS via Africa's Talking | Not present | Helper body commented out |
| AWS, PDF, spreadsheet features | Documented only | Composer packages, no call sites |

## Planned or commented behaviour

| Item | Evidence | Label |
|---|---|---|
| Do not offer registration | Comment in `Welcome::register` | **Implemented** by leaving the method empty |
| Change cron end hour from 17:00 to 23:00 | Comment in `CronJobs::index` attributed to Wessels | **Implemented** as `hour >= 23` |
| Make lockout limit 5 | Comment "TO-DO: Make this 5" | Already 5. **Implemented** |
| Fix server-alert contact after testing | Comment "TO-DO: Fix this after testing", contact id 2, name Wessels | **Implemented** as that fixed recipient |
| 10-day 2FA example | Comment in `UserModel` | **Not** the code. Code uses 1 day |
| CRUD automation scripts | `README.md` heading with an empty bullet | **Unknown** |
| Jira project SI and Confluence space AO | Links in `README.md` | **Documented** external trackers. Contents not read |

## Recently changed

All five commits are dated 2025-09-01. The last change is SonarQube `sonar-project.properties`. The previous commit subject is "Cleanup dashboard". No release notes file exists, so the dashboard cleanup contents were not diffed line by line for this document.

## Tests as a feature

`tests/` contains CodeIgniter example session and database tests plus `tests/unit/HealthTest.php`. `tests/README.md` is the framework testing guide. `composer.json` script `test` runs PHPUnit. The pipeline does not run PHPUnit. Product behaviour is not covered by an application test suite in this tree.
