# Features — crimemapping-webportal

Evidence date: 2026-10-18. Source: `master` at `f8a20d4` (2024-02-05). Provenance is **Implemented** unless a row says otherwise.

Menu URLs below are the first URI segment. `Authorization` only allows a segment that exists in `user_menu.url` and is granted in `user_access`. The seed inserts Dashboard (`home`), Users (`users`), Menu Management, and CRUD Generator for role id 1. Crime, organisation, location, incident, export, and activity menus are not in the seed. They must be inserted through Menu Management or directly in the database before the screens can be opened. That menu data is **Unknown** for any live database.

## Current

| Feature | What the user gets | Where |
|---|---|---|
| Staff login and logout | Email and password, session in MySQL, logout destroys the session | `Welcome.php`, `common/login.php` |
| Registration page | Public form that tries to create a user as role id 1 | `Welcome::register`, `common/register.php` |
| Empty dashboard | Signed-in landing page with no widgets | `Home.php`, `common/home.php` |
| Forbidden page | Shown when the menu exists but the role has no grant | `common/forbidden.php` |
| User administration | List, create, update, hard delete. Role id 4 is limited to their organisation and may only create role id 2 | `Users.php`, `settings/userList.php` |
| Profile | Name-related fields, password, phone check, note (max length 200 on the textarea) | `Users::displayProfile`, `settings/profile.php` |
| Roles and menu grants | CRUD on `user_role`. Ticks for menu category, menu, and submenu | `UserRoles.php`, `settings/userRoleList.php`, `settings/userAccessList.php` |
| Organisations | CRUD, soft delete, parent/child links, suburb attach and detach | `Organisations.php`, `common/organisationList.php` |
| Locations catalogue | CRUD on municipal-code rows, list capped at 10,000, ordered by `mp_name` | `Locations.php`, `settings/locationList.php` |
| Incident types | CRUD, soft delete, ordered by `name_group` when that column exists | `IncidentType.php`, `settings/incidentTypeList.php` |
| Crime log | Modal create and update, incident badges, child crimes, image lookup, hard delete of the crime and its incident and image rows | `CrimeLog.php`, `common/crimeLogList.php` |
| Crime map | Month-scoped Google Map, incident and attempted filters, marker clustering | `CrimeMap.php`, `common/crimeMap.php`, `public/assets/js/crimeMap.js` |
| GIS map page | Shell that loads OpenLayers and `main.js` from `sungis10.stb.sun.ac.za` | `CrimeMapGis.php`, `common/crimeMapGis.php` |
| Crime log export | Read-only table with notes, address, coordinates, and DataTables copy/CSV/Excel/PDF/print | `CrimeLogExport.php`, `common/crimeLogListExport.php` |
| Activity log | Manual rows: user, IP, type, description | `ActivityLog.php`, `settings/activityLogList.php` |
| Menu management | Create menu category, menu, and submenu, including file generation for a new page | `Developers/MenuManagement.php` |
| CRUD generator | Prints controller, model, and view stubs from a chosen table | `Developers/CRUDGenerator.php` |
| API user create | `POST apiusers` by cellphone, no bearer token | `apiUsers::create` |
| API login, current user, logout | Cellphone plus password, JWT stored on `users.token` | `apiUsers::login`, `getUser`, `logout` |
| API crime create | Token, incidents, JPEG/PNG upload resized to 400px wide | `apiCrimes::create` |
| API crime read | Token. Show returns the row plus incident types. The image helper queries incident types again | `apiCrimes::show`, `ApiCrimeModel::getCrimeImages` |
| API incident read | Token. List and show on `apiincidents` | `ApiIncidents.php` |
| API organisation list | No token. All rows, newest id first | `ApiOrganisations::index` |
| API organisation write | Token required for show, create, update, delete | `ApiOrganisations.php` |
| GIS authenticate | Vendor name plus key checked as a user password | `Apigis::authenticate` |
| GIS towns, user location, town crimes | Group by town, suburbs for an email, paged point features | `Apigis.php`, `ApiGisModel.php` |
| SonarQube on master | Pipeline step before FTP | `bitbucket-pipelines.yml`, `sonar-project.properties` |
| FTP deploy of master | `git ftp push` after the scan | `bitbucket-pipelines.yml` |

## Completed

"Completed" here means present on `master` and introduced by a named commit in the fetched history, not a closed ticket.

| When | Commit | Feature |
|---|---|---|
| 2023-06-23 | `92785fd` | Export page |
| 2023-07-13 | `bbe9f75`, `f2714d3` | Geo API and renamed geo calls |
| 2023-07-20 | `7c2f075` | Linking child crimes |
| 2023-07-24 | `3b92c10` | GIS map page ("theo map") |
| 2023-07-25 | `64847b2` | Delete restrictions and export update |
| 2023-12-01 | `afab9d0` | Further GIS API call |
| 2023-12-06 | `7e3d7b9` | Map-click geocoding turned off |
| 2024-02-05 | `004b521` | Suburbs on the organisation location list |
| 2024-02-05 | `38b40a9` | Attempted flag on crime-log incidents |
| 2024-02-05 | `0427601` | Incident ordering |
| 2024-02-05 | `f8a20d4` | Notes column on the export |

Organisation location work cited as `CRIM-49` is in `66b33b4` and `5ac7be8`. The date of those two commits was not copied into this note; they sit inside the fetched 52-commit window (2023-04-04 through 2024-02-05).

## Planned

Nothing in the repository describes a future release. These stubs exist and do nothing:

| Item | Evidence | Status |
|---|---|---|
| API forgot password | `apiUsers::ForgotPassword` empty body | **Planned** only in the sense that the method was declared. No behaviour |
| API change password | `apiUsers::ChangePassword` empty body | Same |
| API crime update and delete | Commented methods on `apiCrimes` | Not available |
| API login with email | Commented second `login` on `apiUsers` | Not available |
| Suburb-based GIS queries | Commented SQL in `ApiGisModel` | Replaced by town grouping. The comment says suburb links are incomplete |
| Jira `SI` board and Confluence `AO` | URLs in `README.md` | Contents **Unknown** |

## In development

No branch other than `master` was checked out. The tip is dated 2024-02-05. There is no in-progress feature marked in the tree.

## Recently changed

Relative to the tip, the last day of work (2024-02-05) changed incident ordering, the attempted flag, organisation suburbs, and the export notes column. The export screen is the newest user-visible change.

## Deprecated or removed

| Item | Evidence |
|---|---|
| Reverse geocoding on the crime-log map click | Calls in `crimeLogList.php` are inside comments. `getFormattedAddressFromCoordinates` is defined and not called. Commit `7e3d7b9` |
| `git ftp init` | Commented in `bitbucket-pipelines.yml`. Push remains |
| Soft delete of a crime | Commented `active = 0` update in `CrimeLogModel::deleteCrimeLog`. The live path is a hard delete |
| AWS, mPDF, PhpSpreadsheet | Required by Composer. No `app/` PHP reference. **Inferred** leftover from the Admin Overdrive starter |

## Not features

- The activity log does not record sign-in or crime edits by itself.
- The dashboard does not summarise crimes.
- `tests/` does not exercise crime, map, or API behaviour. It is the framework example suite (`HealthTest`, `ExampleSessionTest`, `ExampleDatabaseTest`).
