# Technical documentation — track.mypass.zone

Evidence date: 2026-10-01. Source: `master` at `ec4cf5d` (2022-08-25).

## Stack

| Item | Evidence |
|---|---|
| Language | PHP. Front controller turns on `E_ALL \| E_STRICT` and `display_errors` |
| Framework | Zend Framework 1, vendored in `library/Zend`. `Zend_Application` in `public/index.php` |
| UI | Server-rendered `.phtml`. Limitless theme (HTML copied from `demo.interface.club`, HTTrack comment dated 2018-02-02). Bootstrap, jQuery, Font Awesome 5.3.1 from a CDN on the login page. Google font Roboto |
| Database | `pdo_mysql` through `Zend_Db_Table` |
| PDF | Dompdf (`public/dompdf/dompdf_config.inc.php`), A4 landscape |
| Web server | Apache. `scripts/install_dependencies` runs `yum install -y httpd`. `start_server` / `stop_server` use `service httpd` |
| Timezone | `Africa/Johannesburg` set in `public/index.php` |
| Locale resource | `af_ZA` in `application.ini`. UI copy that was read is English |
| Crypto in app code | `md5` for passwords and reset keys. `mcrypt_create_iv` for registration refs and keys. PHP builds that removed `mcrypt` cannot run those paths |

No `composer.json`, no automated test directory, no README, no Dockerfile.

## Request path

Root `.htaccess` rewrites every URI that does not already start with `/public/` into `public/`. The HTTPS-to-www rules in that file are commented out.

`public/.htaccess` serves real files and directories, and rewrites everything else to `index.php`.

`index.php`:

- Defines `APPLICATION_PATH` as `../application`.
- `APPLICATION_ENV` from the environment, otherwise `production`.
- Defines `UPDATE_PATH` as `public/archives/` (the `realpath` result; if `archives` is missing the constant becomes empty because `realpath` fails).
- Puts `library/` on `include_path`.
- Bootstraps `application/configs/application.ini` and runs.

`application/Bootstrap.php` exists and its `_initDbAdapter` is empty. Database comes from the ini resource.

`resources.frontController.moduleDirectory` is `application/modules`. The only module is `default`.

`PG_Controller_Plugin_LayoutPicker` (`library/PG/Controller/Plugin/LayoutPicker.php`) sets the layout name to the module name on `preDispatch`, so the layout used is `default` (`application/layouts/default.phtml`). `application.ini` also sets `resources.layout.layout = default`. Other layout keys in the ini (`admin`, `union`, `referee`, `gir`, `accreditations`) have no matching layout files.

A second bootstrap class, `Default_Bootstrap`, lives at `application/modules/default/controllers/Bootstrap.php` and redirects to HTTPS when the port is not 443. Zend looks for module bootstraps at `modules/{name}/Bootstrap.php`, not under `controllers/`. **Inferred:** the redirect does not run from this path.

## Configuration

`application.ini` sections: `production`, and `staging`, `testing`, `development` inherit production. All environments keep `display_startup_errors`, `display_errors`, and `displayExceptions` at 0. That does not override the `ini_set('display_errors', 1)` in `public/index.php` and at the top of the controllers.

Session cookie lifetime: `864000` seconds.

Database resource (production, inherited by the other sections):

- Host `db.footprintapp.net`
- Database name `teamwizz_SARU`
- Adapter `pdo_mysql`
- Username and password are present in the file. They are not repeated here.

`[production]` is the default because `index.php` falls back to `production` when `APPLICATION_ENV` is unset. There is no separate host or database for staging, testing, or development.

**Security note for reviewers.** The ini file and several controllers contain live credentials (database, SMTP, shared PIN). They are in Git history from 2022-06-24 onward. Silicon Ark intentionally does not copy the secret values. Rotation is a human action.

## Controllers and routes

Zend default routing: `/{controller}/{action}/{param}/...`. Module `default` is omitted from the URL.

| URL prefix | Class | Session rule |
|---|---|---|
| `/` and `/index/...` | `IndexController` | `EVENT.EID` or redirect `/login/` |
| `/login/...` | `LoginController` | Layout disabled. Logout clears auth and session |
| `/register/...` | `RegisterController` | No session required. Layout disabled |
| `/permits/...` | `PermitsController` | `EVENT.EID` or redirect `/login/` |
| `/users/...` | `UsersController` | `Zend_Auth` identity or redirect `/login/` |
| `/company/...` | `CompanyController` | `Zend_Auth` identity or redirect `/login/` |
| `/error/...` | `ErrorController` | Standard ZF1 error handler |
| File `EventsController.php` | Class is `Companies_EventsController` | Not the class name Zend loads for controller `events` |
| File `OrgController.php` | Class is `Company_OrgController` | Same mismatch |
| `/organisation/...` | `OrganisationController` | Actions empty |
| `/authon/...` | `AuthonController` | Actions empty |

`LoginController::init` disables the layout, so the MyPass shell is not used on login, forgot, or reset. Those pages are full HTML documents.

## Data

Models are `Zend_Db_Table` subclasses. `_name` is the table. Several queries bypass the table and read views (`setIntegrityCheck(false)`).

### Used by controllers

| Model | Table or view | Used for |
|---|---|---|
| `Model_AccreditationPermits` | `Accreditation_Permits`; reads `Permits_view`, `Permit_Status` | Permit rows, dashboard, numbers |
| `Model_AccreditationList` | `Accreditation_List`; `getEvent` reads `Accreditations_view` | Event profile, date JSON, permit prefix |
| `Model_AccreditationLoadingZones` | `Accreditation_Loading_Zones` | Zones for an event (`AID`) |
| `Model_AccreditationGates` | `EventGates` | Gates for an event (`AC`) |
| `Model_AccreditationLoadingServices` | `Accreditation_Load_Services_Types` | Service type dropdown |
| `Model_AccreVehicleTypes` | `vehicletypes` | Vehicle type dropdown |
| `Model_CompanyProfile` | `Companies_Profile` | Company registration and profile |
| `Model_UserProfile` | `Company_Members` | People, reset keys, occupant lookup by `IDNumber` |
| `Model_CompanyEvents` | `Company_Events` | Link company to event 44 at registration |
| `Model_AccreCompanyTypes` | `Accre_Company_Types` | Registration company types. The register action constructs this class into a variable named `$db_BBEETypes` |
| `Model_BBEELevel` | `BBEE_Level` | Registration and company profile |
| `Model_Country` | `countries` | Registration and company profile |
| `LoginController::getAuthAdapter` | `CompaniesLogin` columns `Email`, `password` | Unused login method |

Dashboard query (`getPermitsdashboard_all`): `Permits_view` where `EID`, `LoadType`, and `RequestDate` match, ordered by `RequestDate`, `TIME`, `TradingName`.

`RequestDate` is passed as `m/d/Y` from the controller. Whether the view column stores that format is **Unknown / Requires Confirmation**; a format mismatch would return no rows.

Occupants are a JSON column `Accupants` (spelling in the schema). Load-in and load-out active dates are JSON arrays of `d/m/Y` strings on the accreditation row (`LoadinActiveDate`, `LoadOutActiveDate`).

Permit columns cleared on duplicate: `PID`, `Gate`, `Zones`, `DateModified`, `AdminModifiedBy`, `UserModified`, `ConfirmmedBy`, `ConfirmedDate`, `ApprovedBy`, `ApprovedDate`, `DeclinedBy`, `DeclinedDate`, `DeclinedMessage`, `CancelledBy`, `CancelledDate`, `CancelMessage`.

### Present and not referenced by controllers

`Fixture`, `FixtureScores`, `Squad`, `Tournament`, `TournamentFoodSession`, `FoodSessionItems`, `MenuVenues`, `Nutritions`, `Allergens`, `NewsArticles`, `MatchReport`, `GirProfile`, `Profile`, `Positions`, `Unions`, `Ethnicity`, `Logs`, `ComentryAndCiting`, `BBEETypes`, and `Copy of Fixture.php`. **Inferred** copies from the shared SARU application that owns `teamwizz_SARU`.

There are no migrations in this repository. Schema changes are not expressed here.

## Files written at runtime

| Path | Writer |
|---|---|
| `public/archives/companies/{CID}_image.jpg` | `CompanyController::uploadAction`, `LoginController::uploadremotecompanyAction` |
| `public/archives/accreditation/{memberId}_image.jpg` | `UsersController` add and profile |
| `AC_PATH/loadin/pdf/permit_{id}.pdf` | `getpermitpdfAction`. `AC_PATH` is not defined in this repository |

`public/archives/` and `public/files/pics/` are gitignored.

`LoginController::companypicAction` reads `public/archives/companies/{id}_image.jpg` or returns a built-in placeholder image. It sets `Content-type: image/gif` and then echoes JPEG bytes. No auth check.

`public/178.json` begins with the text `Array2018-06-16 12:14:26`. It is not a JSON document. Role **Unknown**.

## Mail

`Zend_Mail_Transport_Smtp` to `mail.sarugby.co.za`, port 25, auth login, username `accreditation@sarugby.co.za`. The password is hardcoded in `IndexController`, `LoginController`, `RegisterController`, and `PermitsController`. Omitted here.

From-name on the message is "Registration at sarugby.co.za". Subject is "SARugby Notification" for every mail, including permit requests and password resets.

`PermitsController` does not set `SMTPSecure`. The other mailers set `$mail->SMTPSecure = 'tls'` on the `Zend_Mail` object (not on the transport). **Inferred:** that property is not how Zend_Mail 1 selects TLS.

Password-reset mail includes the new password in the body.

## Integrations

### footprintapp.net

- Browser: `GET https://footprintapp.net/api/mypass/gettermsandconditions/` expects JSON with `termsandconditions`.
- Server: `file_get_contents('https://www.footprintapp.net/pdf/getpermit/id/' . $id)` then Dompdf. The id is taken from the query string and concatenated into the URL.
- Unused: `POST https://footprintapp.net/email/send` with multipart fields `Email`, `FullName`, `Content`, timeout `86400` seconds.

### AWS

`bitbucket-pipelines.yml` uses image `python:3.5.7`. Branches `qa` and `prod` each zip the working tree to `/tmp/artifact.zip` (this includes `library/` and `public/`), install `boto3==1.3.0`, and run `codedeploy_deploy.py`.

The script uploads the zip to `s3://$S3_BUCKET/$APPLICATION_NAME/{timestamp}-bitbucket_builds.zip` and calls `CreateDeployment`. It waits for the deployment to finish (poll loop in the remainder of the file). `deploymentConfigName` is `DEPLOYMENT_CONFIG`, which the pipeline YAML does not export.

`appspec.yml` (version 0.0, Linux):

- Files: `/` → `/mnt/data/www/html/mypass.zone/track.mypass.zone/`
- Owner and group `apache`
- `BeforeInstall`: `scripts/install_dependencies` (installs httpd) as root, timeout 300
- `ApplicationStop`: `scripts/remove_archives.sh` deletes old CodeDeploy revision directories, as root
- `ApplicationStart`: `scripts/start_server` (`service httpd start`)

`scripts/stop_server` is not referenced by `appspec.yml`. Its shell test is `isExistApp = \`pgrep httpd\`` with spaces around `=`, which is not a valid assignment. **Inferred:** the script would fail if a hook called it.

The cloned remote has only `master`. Pipeline branches `qa` and `prod` do not exist there. A commit to `master` does not match the pipeline.

CodeDeploy destination was set in `100a6e3` (2022-06-30). Later commits did not change the path.

## Auth model

Two mechanisms, only one connected to the form:

1. **PIN session.** `Zend_Session_Namespace('EVENT')->EID = 367`. Checked by dashboard and permits. Not an account.
2. **Zend_Auth** against `CompaniesLogin`. Implemented in `LoginNow`. Not called. Company and user controllers depend on it. Credential column is `password`. The registration code writes `md5` into `Company_Members`, which is a different table from `CompaniesLogin`. Whether a database trigger copies the hash is **Unknown / Requires Confirmation**.

`mcrypt` random ids are used as email validation keys and as `Ref` / `RefNumber`.

SQL fragments in controllers and models concatenate request parameters (`IDNumber`, `Email`, `RegistrationNumber`, permit ids, reset keys). **Inferred** SQL injection exposure on those queries. No prepared-statement binding was found on those paths.

`emailtestAction` and `testAction` are ordinary actions. Anyone with the event session can open them. `testAction` prints a member row. `emailtestAction` sends mail to a fixed personal address. Both are inappropriate on a shared PIN. Addresses and the sample ID number are omitted.

## Front-end assets

`public/` holds `assets`, `assets_old`, `bootstrap2`, `dist`, `dompdf`, `files`, `FILESTO DOWNLOAD`, `fonts`, `global_assets`, `html`, `limitless`, `starters`, plus the WordPress directories. The running layout links `/assets/css/...` and `/global_assets/...`. The login page links `/limitless/assets/...` and `/global_assets/...`.

Third-party script on the login page: `https://cdn.ywxi.net/js/1.js` (Trustwave / McAfee Secure-style include). Provenance: **Implemented** in the page. What account it reports to is **Unknown**.

## Development and testing

No PHPUnit, no CI test step, no seed data, no `.env` example. Local run, from the code alone, is Apache (or the PHP built-in server pointed at `public/`) with `APPLICATION_ENV`, the MySQL credentials, and the `mcrypt` extension. That was not executed for this document.

Sonar properties and `sonarqube_scan.bat` are named in the onboarding brief and are not in `master`.

## Deployment status

Last application commit is 2022-08-25. Whether that revision is what Apache still serves under `track.mypass.zone` is **Unknown / Requires Confirmation**. The CodeDeploy path is the only deploy target written down.
