# Features — bitool_backend

Evidence date: 2026-10-19.

Source: `git@bitbucket.org:overdrive/bitool_backend.git`, `master` at `09437373` (2026-09-11).

Status words:

- **Current** — routed and called by a controller on this commit.
- **Completed** — present and not marked as temporary in code. This branch has no release notes that say "done".
- **Planned** — commented route, README TODO, or comment that names work still to do.
- **In development** — not established. No open-branch evidence was collected beyond `master`.
- **Recently changed** — subject of a commit in the deepened history after the 2025-12-17 `qa` merge.
- **Removed or leftover** — code or docs that no longer match the routed app.

`bi_tool_backend_phase6/features.md` describes branch `phase6`. Do not read those features as present on this `master` tip.

## Current features

### Login and session

- WebBoon login and JWT issue. `POST loginAuth`. `app/Controllers/LoginController.php`, `app/Models/UserLoginModel.php`.
- Sliding session stored in `userjwt`. `app/Filters/AuthFilter.php`.
- Per-email idle override. `app/Libraries/SessionLoginExpiry.php`.
- IP lockout after failed logins. `UserLoginModel::LOGIN_ATTEMPT_MAX`.
- One hardcoded username substitutes a fixed producer list. `loginAuth`.

### Export statistics

- Public filter list. `GET getFilters`. `app/Models/FilterDataModel.php`.
- Authenticated filter list with price ranges, grouped countries, and producer names. `GET auth/getFilters`, `GET auth/getCountryGroup`. `app/Models/AuthFilterDataModel.php`.
- Charts: top countries, chart data, cultivar chart, year-over-year, total litres, exports, total-litres detail. `app/Controllers/ChartDataApi.php`, `app/Models/ChartDataModel.php`.
- Five public tables under `POST tables/*`. `app/Controllers/TableDataApi.php`.
- The same five tables under `POST auth/tables/*`, with producer columns when a producer is requested. `app/Controllers/AuthTableDataApi.php`.
- RSA exports report with litre and currency totals and a two-period trend. `POST auth/reports/getRSAExportsReport`. `app/Models/TableDataReportModel.php`.
- Price-range query and saved filter history. `app/Controllers/priceRangeController.php`, `app/Models/PriceRangeModel.php`.

### Vineyard status

Routed in `app/Config/Routes.php`, implemented in `app/Controllers/VineyardStatus.php` and `app/Models/VineyardStatusModel.php`.

- Filter values: year (`INFOBLOCKS.INFOYRREPORT`), region (`regions.VOLLEBESKRYWING`), cultivar, age, and white/red.
- Report catalogue from `Reports` where `Type = 'VineyardStatus'`.
- Reports: total hectares, hectares, age distribution, status, ranking, uprootings, new plantings, net change, irrigation, trellising.
- Empty-cell normalisation. `app/Traits/NormalizesEmptyReportValues.php`.
- Test route `GET vineyardStatus/testReports/{name}/{count}`.

### Grape production

- Filters and report catalogue (`Reports.Type = 'GrapeProduction'`).
- Total production and production per region and cultivar. `app/Models/GrapeProductionModel.php`.
- Test route `GET grapeProduction/testReports/{name}/{count}`.

### Operator data sync

- HTML dashboard. `GET auth/dashboard`. `ImportData::dashboard`.
- Monthly export rebuild from `mapperdata_imported` into `mapper_data` and the export tables. `GET auth/runDataSync`.
- Vineyard status sync and grape production sync, with backup and restore methods. `runDataSync_VineyardStatus`, `runDataSync_GrapeProduction`.
- Spreadsheet check form on the dashboard (`FullYear`, `FullMonths`, `FullMonthsCountry`). `GET auth/excel_import_check`.
- Pending industry import and dry run. `GET sys/ExportPendingIndustryCodes`.
- Missing-industry email on login, once per user and code set. `UserLoginModel::sendMissingIndustryCodesEmailOnce`.
- `GET sys/ExportDataTo__Data_export_dev_industry` and `GET sys/createIndustryImport`.

### Platform

- Global CORS, including preflight on routes that do not exist. `app/Filters/Cors.php`.
- CodeIgniter welcome page at `GET /`.
- Deploy script with token and IP gate. `public/deploy.php`.
- SonarQube project key and a Bitbucket pipeline step on `master`. `sonar-project.properties`, `bitbucket-pipelines.yml`.
- PHPUnit bootstrap and one health test. `phpunit.xml.dist`, `tests/unit/HealthTest.php`.

## Completed

Treated as completed because they are on `master` and are called by routed code: login, export charts, export tables, RSA report, price ranges, vineyard reports, grape reports, and the three sync entry points.

No version number or changelog in the repository marks a release. `composer.json` has no version field.

## Planned

| Item | Evidence | Notes |
|---|---|---|
| Jira board SI | `README.md` Development TODOS | URL only. Board contents were not read |
| Confluence space AO | `README.md` | URL only |
| `auth/setPriceRanges` | Commented route | Method `priceRangeController::setPriceRanges` still exists |
| Older full-table export GETs | Commented routes for `ExportDataTo__data_export_dev`, `_qa`, and `_price_ranges` | Methods remain on `ImportData` and are called internally by `regenerateDataTables` |
| Web-server or auth restriction on sync GETs | Comment in `Routes.php` | The comment says to add it before exposing the routes. The routes are still registered without `authFilter` |
| Sultana-specific vineyard calls | `setFilters($sultana)` | No route passes `$sultana = true` |

**In development:** Unknown. This inspection did not list open pull requests on `bitool_backend`.

## Recently changed

From the deepened history after `2ee3833` (merge `qa`, the task-creation snapshot). Subjects are commit messages, not a product changelog.

| Commit | Subject | Feature affected |
|---|---|---|
| `0020cdd` | init for vineyardstatus | Vineyard status API |
| `733e36b`, `face26f`, `9eed9d6`, `01d4bb5` | net change fixes | `VineyardStatusModel::netChange` |
| `0db5f99`, `be9f71e`, `e5da194` | trellising and grape production | Trellising report and grape data |
| `6d03721`, `d928d55` | ranking fixes | Ranking report |
| `a925347` | region filter response to remove null | Region filter |
| `9f927a2` | fixing blank issues | Empty report cells. Matches `NormalizesEmptyReportValues` |
| `debec62` | hotfix Ettiene | The special-case login. **Inferred** from the message plus the `EttieneOverdrive` branch in `loginAuth` |
| `8018f6f` | Stop tracking vendor | `vendor/` no longer in Git |
| `dd3e408` | Vuln and sec fixes and ensuring pages work | Security. The commit message does not list the fixes |
| `5fb8861` | Stop industry ETL on login; pending sync, notify, monthly catch-up | Login no longer builds industry rows. Pending sync and email were added |
| `0943737` | Merged PR #5 `bugfix/industry_specific_import` | Current tip |

## Removed, unused, or contradicted

| Item | What the repo shows |
|---|---|
| Industry import during login | Removed by the behaviour in `5fb8861`. `loginAuth` comments say industry import is manual. The email remains |
| `vendor/` in Git | Stopped at `8018f6f`. `composer.json` still requires the packages |
| FTP deploy pipeline | Header comment in `bitbucket-pipelines.yml`. The only step is SonarQube |
| Registration, authorization menus, "auto create controller and view" | `README.md` Features. No routes. Helpers `menu_helper.php` and `useraccess_helper.php` are not autoloaded |
| `ChatGPT`, `DbAdmin`, `ApiSimulation` | Classes under `app/Controllers/`. Not named in `Routes.php`. Auto-routing is off |
| Views `developers/dbAdmin` and `projects/chatgpt` | Referenced by those controllers. Not present under `app/Views/` |
| `app/Helpers/chatgpt_helper.php`, `africastalking_helper.php`, `mail_helper.php` | Not autoloaded. `mail_helper` is separate from the CodeIgniter email service used for the industry notice |
| AWS SDK, mPDF, PhpSpreadsheet, OpenAI client | In `composer.json` and `README.md`. No `use` under `app/` |
| `public/config.php` Marketing Cloud WSDL settings | File exists. No PHP reference to `appsignature` or that file was found outside the file itself |
| `app/Libraries/JwtLibrary.php` | Custom HMAC helper. Login uses `Firebase\JWT\JWT` instead. `ApiSimulation` constructs `JwtLibrary` and is not routed |
| `AppSessionModel`, `UploadedFileModel` | Session and upload CRUD. No routed controller on this branch uses them except unrouted `ApiSimulation` |
| `app/Middleware/CORS.php` | Duplicate of the filter idea. `Filters.php` registers `App\Filters\Cors`, not this middleware class |
| `Filters_old.php`, `Kint_old.php` | Old copies beside the live config |
| Global `authFilter` | Commented in `Filters.php` |
| CSRF, toolbar, honeypot | Aliases commented out |

## Source map

| Feature | Primary files |
|---|---|
| Routes | `app/Config/Routes.php` |
| Login | `app/Controllers/LoginController.php`, `app/Models/UserLoginModel.php` |
| Auth filter | `app/Filters/AuthFilter.php` |
| Charts | `app/Controllers/ChartDataApi.php`, `app/Models/ChartDataModel.php` |
| Tables | `app/Controllers/TableDataApi.php`, `app/Controllers/AuthTableDataApi.php`, `app/Models/TableDataModel.php` |
| RSA report | `app/Models/TableDataReportModel.php` |
| Filters | `app/Models/FilterDataModel.php`, `app/Models/AuthFilterDataModel.php`, `app/Models/FilterModel.php` |
| Price ranges | `app/Controllers/priceRangeController.php`, `app/Models/PriceRangeModel.php` |
| Vineyard | `app/Controllers/VineyardStatus.php`, `app/Models/VineyardStatusModel.php` |
| Grape | `app/Controllers/GrapeProduction.php`, `app/Models/GrapeProductionModel.php` |
| Sync | `app/Controllers/ImportData.php` |
| CORS | `app/Filters/Cors.php`, `app/Config/Filters.php` |
