# Technical documentation — media.accreditations.sarugby.online

Evidence date: 2026-10-09. Source: `master` at `773e00f` (2020-01-10, `heinrichoverdrive`). Remote: `git@bitbucket.org:overdrive/media.accreditations.sarugby.online.git`. Only branch: `master`.

## Stack

| Item | Evidence |
|---|---|
| Language | PHP. No `composer.json` at the repository root. Dompdf under `public/dompdf` has its own `composer.json` |
| Framework | Zend Framework 1.11.10 (`library/Zend/Version.php`) |
| UI | Limitless theme (Bootstrap), jQuery, DataTables. Assets under `public/limitless` and `public/global_assets`. Login markup was saved from a Limitless demo via HTTrack (HTML comment dated 2018-02-02) |
| Database | MySQL through `pdo_mysql`. Schema name `teamwizz_SARU`. Host `db.footprintapp.net` since `773e00f`. Before that commit the host was `qadb.footprintapp.net` |
| Web server | Apache `mod_rewrite`. CodeDeploy hook installs and starts `httpd` |
| Timezone | `Africa/Johannesburg` in `public/index.php` |
| Locale config | `af_ZA` in `application.ini`. No translation files found |

PHP version is **Unknown / Requires Confirmation**. The code uses `mcrypt_create_iv`, which PHP 7.2 deprecated and later PHP removed.

## Repository layout

```text
.htaccess                      sends requests into public/ unless the URI already starts with /public/
application/
  Bootstrap.php                empty _initDbAdapter
  configs/application.ini
  layouts/default.phtml        layout the plugin selects
  layouts/layout.phtml         unused Footprint portal layout
  models/                      Zend_Db_Table classes
  modules/default/
    controllers/
    views/scripts/
    views/helpers/
library/Zend                   framework
library/PG                     LayoutPicker and other plugins
public/index.php               front controller
public/.htaccess               rewrite to index.php
public/limitless, global_assets, dompdf, archives
scripts/                       CodeDeploy hooks
appspec.yml
bitbucket-pipelines.yml
codedeploy_deploy.py
```

`public/FILESTO DOWNLOAD/` duplicates portions of `dompdf` and CKEditor assets. It is not referenced by the collection controllers.

There is no root README, no PHPUnit configuration, and no test directory.

## Request path

1. Root `.htaccess` rewrites to `public/{path}` when the URI does not already start with `/public/`. The HTTPS and `www` redirect is commented out (change in the 2020-01-10 commits).
2. `public/.htaccess` serves real files and rewrites everything else to `index.php`.
3. `public/index.php` defines `APPLICATION_PATH`, `APPLICATION_ENV` (default `production`), and `UPDATE_PATH` (`public/archives`). It loads `Zend/Application` with `application/configs/application.ini`.
4. Front controller module directory is `application/modules`. The only module is `default`, so routes are `/{controller}/{action}` with the default controller `index` and action `index`.
5. Plugin `PG_Controller_Plugin_LayoutPicker` sets the layout to the module name (`default`) on every request. Controllers that call `disableLayout` (login, `getapplicants`, `collect`) skip it.

`application/Bootstrap.php` does not register extra resources. Database comes from the `resources.db` ini keys.

## Configuration

`application.ini` sections: `production`, `staging`, `testing`, `development`. The non-production sections inherit production. Differences are limited to error-display flags, and `public/index.php` then sets `display_errors` to `1` anyway.

Database credentials and the mail password are in the repository. This document does not copy them. Keys:

- `resources.db.params.host`, `username`, `password`, `dbname`
- SMTP username and password inside `LoginController::sendMail` and `PermitsController::sendMail`

`resources.frontController.params.displayExceptions` is `0`.

Session cookie lifetime: `864000` seconds.

Autoload namespace: `PG_`.

## Controllers

All under `application/modules/default/controllers/`.

| File | Class | Gate |
|---|---|---|
| `IndexController.php` | `IndexController` | `EVENT.EID` or redirect `/login/` |
| `LoginController.php` | `LoginController` | Layout disabled. PIN form does not require a session |
| `PermitsController.php` | `PermitsController` | `EVENT.EID` |
| `RegisterController.php` | `RegisterController` | None. Layout disabled |
| `CompanyController.php` | `CompanyController` | `Zend_Auth` identity |
| `UsersController.php` | `UsersController` | `Zend_Auth` identity |
| `EventsController.php` | `Companies_EventsController` | Class name does not match the file, so the front controller will not load it as `events` |
| `OrgController.php` | `Company_OrgController` | Same class-name mismatch |
| `OrganisationController.php` | `OrganisationController` | No auth check. `profileAction` is empty |
| `AuthonController.php` | `AuthonController` | Empty actions |
| `ErrorController.php` | `ErrorController` | Zend error handler |

## Data

Zend_Db_Table names that the collection path and the imported accreditation path use:

| Model | Table name | Used by |
|---|---|---|
| `Model_AccreditationList` | `Accreditation_List` | `getApplications` actually selects from `Accreditation_Collections` with integrity check off |
| `Model_AccreditationApplicantsServices` | `Accreditation_Applicants_Services` | `IndexController::collectAction` |
| `Model_UserProfile` | `Company_Members` | Registration, password reset, staff |
| `Model_CompanyProfile` | `Companies_Profile` | Registration, company profile |
| `Model_CompanyEvents` | `Company_Events` | `RegisterController` event link |
| `Model_AccreditationPermits` | `Accreditation_Permits` | Permit actions |
| `CompaniesLogin` | referenced only as an auth adapter table name | `LoginController::getAuthAdapter` |

`Accreditation_Collections` is not a Zend table class. **Unknown / Requires Confirmation** whether it is a view joining applicants, services, and organisations. Columns read by the dashboard: `ID`, `organisation`, `ServiceStatus`, `AASID`, `Ref`, `FullName`, `Rol`, `ServicesText`, plus search columns `FirstName`, `Surname`, `IDNumber`, `Barcode`, and filter column `AC`.

Collect updates columns `Status`, `LastUpdate`, `Collected` on `Accreditation_Applicants_Services`.

Other model files (fixtures, squads, tournaments, food, news, ethnicity, country, B-BBEE, gates, zones, vehicle types, loading services) are in `application/models/` and are only reached if a permit or registration action loads them. `Copy of Fixture.php` is an extra copy of the fixture model.

No migration directory is in the repository. Schema changes are **Unknown**.

## Auth

Two mechanisms exist:

1. **PIN session.** `LoginController::indexAction` compares the POST password to a literal and sets `Zend_Session_Namespace('EVENT')->EID = 63`.
2. **Database auth.** `LoginNow` uses `Zend_Auth_Adapter_DbTable` on `CompaniesLogin` with identity column `Email` and credential column `password`. It also sets `EID` `63` and writes `LastLogin`. The login form does not call it. Credential treatment (plain or hashed) is whatever is stored in `CompaniesLogin.password`. The adapter is constructed without `setCredentialTreatment`, so Zend compares the posted value to the stored column as-is.

Company member passwords written by this app are `md5`. Reset keys are `md5` of `mcrypt` random bytes.

`uploadremotecompanyAction` and `companypicAction` accept a company id from the query and read or write image files with no session check.

Search and collect concatenate request values into SQL.

## Mail

`Zend_Mail_Transport_Smtp` to `mail.sarugby.co.za` port `25`, auth login, from `accreditation@sarugby.co.za`. Used by forgot-password, reset confirmation, registration, and permit notification. Exceptions are caught and discarded.

`postEmailToFp` is an alternate POST to `https://footprintapp.net/email/send` and is not called.

## Files on disk

`UPDATE_PATH` is `public/archives`.

- Company images: `public/archives/companies/{cid}_image.jpg`
- Staff images: `public/archives/accreditation/{memberId}_image.jpg`

`companypicAction` returns `image/gif` even when the file is JPEG. If the file is missing it prints a hardcoded placeholder image.

## Deployment

`bitbucket-pipelines.yml` uses image `python:3.5.1`. Branches `qa` and `prod` each export AWS and CodeDeploy variables from Bitbucket (`QA_*` or `PROD_*`: access key, secret, region, application name, deployment group, S3 bucket), install `zip` and `boto3==1.3.0`, zip the working tree to `/tmp/artifact.zip`, and run `codedeploy_deploy.py`.

`codedeploy_deploy.py` uploads the zip to `s3://$S3_BUCKET/$APPLICATION_NAME/{timestamp}-bitbucket_builds.zip` and creates a CodeDeploy deployment. The script header says it is the Amazon Bitbucket Builds template, version 1.0.0.

`appspec.yml` (version 0.0, os linux):

- Files: `/` to `/mnt/data/www/html/sarugby.online/media.accreditations.sarugby.online/`
- Permissions: owner and group `apache`
- BeforeInstall: `scripts/install_dependencies` (`yum install -y httpd`) as root
- ApplicationStop: `scripts/remove_archives.sh` deletes CodeDeploy revision directories other than the last successful install
- ApplicationStart: `scripts/start_server` (`service httpd start`)

`scripts/stop_server` is not referenced by `appspec.yml`. Its `isExistApp = ` assignment is not valid Bash (spaces around `=`).

The zip includes the whole tree (`zip -r /tmp/artifact.zip *`), so a pipeline run would pack `library/`, `public/`, and `application/configs/application.ini`.

Pipeline variables and the live CodeDeploy application names are **Unknown / Requires Confirmation**. They are not committed.

## Security notes for reviewers

These are observations, not a remediation plan.

- Database password, SMTP password, and the shared PIN are in Git.
- `public/index.php` and controllers enable `display_errors`.
- Search and the collect predicate build SQL from request strings.
- Password reset emails the new password.
- `md5` and `mcrypt` are used for member passwords and reset keys.
- `emailtestAction` addresses a personal mailbox.
- `IndexController::testAction` queries a hardcoded national ID number.

## Monitoring and testing

No application log configuration beyond Zend defaults was found. No health check, queue, cron, or worker is defined. No automated tests.

SonarQube project files are not in this revision. See `features.md`.

## Local development

**Unknown / Requires Confirmation.** There is no documented local setup. A developer would need PHP with the Zend 1 library on the include path (the front controller adds `library/`), Apache or the equivalent rewrite to `public/index.php`, and network access to `db.footprintapp.net`. Default environment is `production`.
