# Features — permits.mypass.zone

Evidence date: 2026-10-07. Source: `master` at `16d1793` (2022-07-01).

Status words mean:

- **Active in the PIN flow** — reachable after the shared PIN sets event `45` and the browser lands on `/walkins`.
- **Present, disconnected** — code and screens exist, but they require `Zend_Auth` identity or are skipped by a redirect.
- **Unused in this app** — files exist and no reachable controller calls them.
- **Removed / inactive** — left in the tree commented out or not referenced.

## Current features

### F-01 — PIN login and logout

Active in the PIN flow.

`/login` posts a password field labelled as a PIN. A match stores `EVENT.EID = 45` and redirects to `/`, which redirects to `/walkins`. Any other value shows "Bad entered credentials". If an event id is already in the session, `/login` skips the form. `/login/logout` destroys the session.

Evidence: `application/modules/default/controllers/LoginController.php` (`indexAction`, `logoutAction`), `IndexController::init`, `views/scripts/login/index.phtml`.

### F-02 — Company picker

Active in the PIN flow.

`/walkins` lists companies linked to the session event. The heading is "SELECT YOUR COMPANY". A search box calls `/walkins/search` and replaces the cards.

Evidence: `WalkinsController::indexAction`, `searchAction`, `views/scripts/walkins/index.phtml`, `search.phtml`, `Model_CompanyEvents::getListByEvents`.

### F-03 — Company passkey and new-permit form

Active in the PIN flow.

"New Permit" asks for a PIN in a modal and compares it with the company's `passkey`. `/walkins/new/id/{CEID}/ref/{passkey}` reloads the company only when both match, then shows load type, service type, reference, date, time in, time out, job description, vehicle, trailer, driver, and occupants.

Dates offered are the event's active load-in or load-out dates that are today or later.

Evidence: `WalkinsController::newAction`, `views/scripts/walkins/new.phtml`.

### F-04 — Create permit and email

Active in the PIN flow, with a break at the email step.

The form posts to `/permits/addpermit/cid/{CID}`. The action inserts `Accreditation_Permits` at status `2`, sets `PermitNr` to `PM` plus a zero-padded id, and attempts a confirmation email. The email step reads `$this->identity`, which this controller never sets.

Evidence: `PermitsController::addpermitAction`, `Model_AccreditationPermits`.

### F-05 — FAQ

Active in the PIN flow (the event session is required).

`/permits/questions` prints the venue FAQ: entry rules, one permit per vehicle per day, health and safety file, delivery versus work, load-in versus load-out, printed copy, staff identification, and a single company administrator.

Evidence: `PermitsController::questionsAction`, `Questions()`.

### F-06 — Permit profile

Active in the PIN flow for `profileAction`.

`/permits/profile/key/{PID}` loads the permit from `Permits_view` with no company filter, splits occupants and driver, and sets `LOCKED` from the 13:00-previous-day rule. A missing permit redirects to `/`.

Evidence: `PermitsController::profileAction`, `views/scripts/permits/profile.phtml`.

## Present, disconnected from the PIN login

### F-07 — Operations dashboard

`IndexController::indexAction` and `getdataAction` load gates, zones, the accreditation row, and permits from `Permits_view` for a date and load type. `index/index.phtml` shows counts, status badges, zone weight against bay capacity, and a 10:30 lock on the previous day.

`init` redirects to `/walkins` as soon as `EID` is set, so this screen does not render after login.

Evidence: `IndexController`, `views/scripts/index/index.phtml`.

### F-08 — Permit PDF

`IndexController::getpermitpdfAction` fetches HTML from `https://www.footprintapp.net/pdf/getpermit/id/{id}` and streams an A4 landscape PDF through dompdf. It writes under `AC_PATH`, which is not defined in this repository. The action sits behind the same redirect as the dashboard.

### F-09 — Supplier registration

`/register` collects company and administrator details, including B-BBEE level and company type. `/register/newcompany` inserts the member, the company, and a `Company_Events` row for event `44`, then emails `supplier.sarugby.online` to confirm the address. `/register/validateemail/id/{key}` on this host can confirm the key if the link is opened here.

The login form does not sign the new user in.

Evidence: `RegisterController`, `views/scripts/register/index.phtml`.

### F-10 — Forgot and reset password

`/login/forgot` and `/login/reset/user/{key}` update `Company_Members.password` as `md5` and email the user. The wired login form does not ask for that password.

Evidence: `LoginController::forgotAction`, `resetAction`, `views/scripts/login/forgot.phtml`, `reset.phtml`.

### F-11 — Email and password login

`LoginNow` authenticates against `CompaniesLogin`. `login/auth.phtml` is an email and password form. No action renders that view or calls `LoginNow`.

### F-12 — Company profile and staff

`CompanyController` and `UsersController` require `Zend_Auth`. They edit `Companies_Profile`, upload a company image, and insert or update `Company_Members`, including a generated password when `AllowLogin` is set. Staff role labels are a fixed list.

The PIN login never creates the identity, so these screens redirect to `/login/` and then bounce back to `/walkins` once the PIN session exists.

### F-13 — Save, duplicate, and cancel a permit

`savepermitAction`, `duplicatepermitAction`, and `cancelAction` update `Accreditation_Permits`. All three read `$this->identity`. Cancel sets status `5`. Duplicate sets status `2` and clears approval fields.

### F-14 — Open the desk for an arbitrary event

`/login/external?eid={id}` stores that id and redirects to `/walkins` with no PIN.

Evidence: `LoginController::externalAction`.

### F-15 — Remote company image upload

`LoginController::uploadremotecompanyAction` writes a base64 image to `public/archives/companies/{cid}_image.jpg` and stores the file name on `Companies_Profile`. It does not check a session. `companypicAction` returns the stored image, or a built-in placeholder, as `image/gif`.

## Unused or stub features in this tree

These files load under the Zend autoloader. No action in the PIN flow calls them.

| Item | Evidence |
|---|---|
| Rugby models: fixtures, scores, squads, tournaments, positions, profiles, unions, match reports, commentary, news, ethnicity | `application/models/Fixture.php`, `Squad.php`, `Tournament.php`, `Profile.php`, `GirProfile.php`, `MatchReport.php`, `NewsArticles.php`, and the "Copy of Fixture.php" duplicate |
| Food, allergens, nutrition, menu venues | `Allergens.php`, `Nutritions.php`, `FoodSessionItems.php`, `MenuVenues.php`, `TournamentFoodSession.php` |
| `BBEETypes` model | `BBEETypes.php` (`B_BBEE_Types`). Registration uses `Accre_Company_Types` instead |
| `AuthonController` | Empty `index`, `test`, and `newcompany` actions |
| `OrganisationController` | Empty `profile` and `test` |
| `OrgController` | Class name is `Company_OrgController`, not `OrgController`, so the default module will not dispatch `/org` to it |
| `EventsController` | Class name is `Companies_EventsController`. `indexAction` prints events from `AccreditationList::getEvents(2)` and expects a redirect to `/companies/login/` |
| `UsersController::UserImage` | Returns a hardcoded placeholder image and is not called |
| `IndexController::testAction` | Prints one member row for a hardcoded identity number |
| `PermitsController::emailtestAction` | Sends a test message to a hardcoded personal mailbox |
| Layouts named in `application.ini` (`admin`, `union`, `referee`, `gir`, `accreditations`) | No matching layout files. On disk: `default.phtml`, `layout.phtml` |
| `library/PG` plugins other than `LayoutPicker` | PDF, upload, email, and match-report helpers. `LayoutPicker` is the only plugin registered, and it sets the layout name to the module name `default` |
| WordPress directories | `public/wp-content`, `public/wp-includes`. The application entry point is `public/index.php` |
| Bundled match-report PDFs | `public/archives/matchreports/`. Not referenced by the permit controllers |

`scripts/stop_server` is not listed in `appspec.yml`. The assignment `isExistApp = \`pgrep httpd\`` is not valid bash (spaces around `=`).

## Planned features

None are listed in the repository.

Email and FAQ text describe future or out-of-band steps: administrator approval of a permit, a 48-hour company review, printing at an operations centre, and health-and-safety file approval. Those are **Documented** and not built here.

## Recently changed (last commits on master)

| Commit | Date | Change |
|---|---|---|
| `cd72ab2` | 2022-06-23 | Initial application |
| `2230b19` | 2022-06-24 | Initial commit |
| `16d1793` | 2022-07-01 | CodeDeploy app spec, Bitbucket pipeline, deploy script, and hook scripts |

No feature commit exists after the import.

## Deprecated or removed

- The maintenance splash in `public/index.php` is commented out (a full-page image and a "technical difficulties" message).
- `IndexController` blocks that counted a company's users, permits, and events are commented out.
- The call to `postEmailToFp` is commented out. SMTP is the path that remains.
- The company-card check that hid "New Permit" unless `Ref` was set is commented out. Every company shows the button.

## Not features of this product

- Approving or declining a permit. No action sets status `4` or `6`.
- Checking a vehicle in or out (status `7` and `9`). The badges exist only on the unreachable dashboard.
- A health and safety file upload.
- A second company administrator, despite the staff screen being able to insert one. The FAQ forbids it, and the screen is unwired.
- SonarQube project files. A discovery note listed `sonar-project.properties` and `sonarqube_scan.bat`. They are not in git at `16d1793`.
