# Features — Sunmet2020

Evidence date: 2026-10-02.

Source: `git@bitbucket.org:overdrive/sunmet2020.git`, `master` at `10caee0` (2020-08-04). Product behaviour matches `prod` at `afeb66d` except the database ini filename (see project plan).

No features document existed in the source repository. Status labels mean:

- **Current** — reachable in the deployed-style tree and wired to a view or side effect.
- **Completed** — present and not marked unfinished. This repository has no ticket tracker, so "completed" means the same as current unless noted.
- **In development** — none found. Last product commit is 2020-01-13.
- **Planned** — none found. No TODO list, roadmap, or issue file.
- **Deprecated / removed** — removed or left commented, with the evidence.

## Current features

### Public application wizard

**Status:** Current, completed.

**Where:** `application/modules/default/views/scripts/application/apply.phtml`, `ApplicationController::applyAction`. Home page `index/index.phtml` posts to the same action. Layout title in `application/layouts/default.phtml`.

**Behaviour:** Stepped form (jQuery Steps): Personal, Organisation, Photo, optional Apply (linked events), Finish. Submits to `/application/apply/code/{code}`.

The home controller pins the code to `5DA997A51439E`. `applyAction` uses the code in the URL.

### Event branding from the accreditation record

**Status:** Current.

**Where:** `Model_AccreditationList::getProfile` reads `Accreditations_view` by `aCode`. `getAccreditationName` in both controllers builds the heading from `AccreditationName`, fixture teams when `FID > 0`, otherwise `DateFrom`/`DateTo`, and `Location` or `FixtureLocation`. Banner image is `AccreBanner`.

### Closed-event page

**Status:** Current.

**Where:** `application/modules/default/views/scripts/application/closed.phtml`. Selected when `CloseDate` 24:00 is in the past (`applyAction`, `IndexController::indexAction`).

**Limit:** The switch does not stop a POST from inserting. See business rules.

### Duplicate-email warning

**Status:** Current in the browser.

**Where:** `check_if_Email_Exist` in `apply.phtml` and `profile.phtml`. Endpoints `ApplicationController::checkemailAction` and `IndexController::checkemailAction`. Query `Model_AccreditationList::checkEmails`.

### Headshot crop and upload

**Status:** Current.

**Where:** Cropper UI in `apply.phtml` and `profile.phtml`. Copy asks for a JPG headshot no larger than 1.5mb. The server does not check size or type.

On apply, `SavePhoto` is commented out. The live path is `sendImage` → `https://www.footprintapp.net/accreditations/application/updateimage`. Profile reload reads `https://www.footprintapp.net/accre/photos/{Ref}.jpg`. Placeholder: `public/accre/profile-icon.png`.

`SavePhoto` still exists and writes `AC_PATH . '/photos/'`. `AC_PATH` is not defined anywhere in this repository. `IndexController::indexAction` still calls `SavePhoto` on POST. That POST path is not what the home form uses.

Role flag `photo == 1` removes the browser `required` class from the image field (`getCurrentRole` in `apply.phtml`).

### Media fields and days attending

**Status:** Current.

**Where:** Block `#MediaOnly` in `apply.phtml`.

- Producer name and producer email.
- Day checkboxes "Day 1" … up to `DaysDuration`, only when `DaysDuration > 1`. `countDaysSelected` writes `All` when every day is ticked, otherwise the selected day numbers, into `data[DaysAttending]`.
- The block is shown by PHP when `MediaOnly == 1`. On category change, if `MediaOnly == 0` and the category value is `1`, the script shows the block and marks `.MediaOnly` required; any other category hides it.

### Reason for application

**Status:** Current.

**Where:** `data[Reason_for_pplication]` in `apply.phtml`. Always in the organisation step, outside the media block. Required in the browser. The note says accreditation approval and zone access depend on the description.

### Linked-event application

**Status:** Current.

**Where:** `Model_AccreditationLinks` table `LinkedAccreditations`. Checkboxes `apply[]` in `apply.phtml`. Extra inserts in `applyAction`.

### Terms and accreditation note

**Status:** Current.

**Where:** Finish step of `apply.phtml`. Required checkbox `data[acceptTerms]`. Modal body `TermsAndConditions`. Optional note checkbox `data[acceptnotes]` when `AccreditationNote` is set. Acceptance sentence names SA Rugby’s Tournament and Competitions Accreditations Policy and the Safety at Sports and Recreational Events Act of 2009.

### Supplier registration notice

**Status:** Current (message only).

**Where:** `#suppliers_show_message` in `apply.phtml`, shown when the role's `SupplierReg` (`reg` attribute) is `1`. URL `http://supplier.sarugby.online`. Layout item "Supplier Registration" in `default.phtml` is commented out.

### Applicant login

**Status:** Current.

**Where:** `application/login.phtml`, `loginAction`, `loginnowAction`, `logoutAction`. Session `user_session` (`Code`, `AAID`). Credential is email plus reference, not a password. Login always uses event code `5DA997A51439E`.

Navigation: "Sign-In" in `default.phtml`. "Application Form" and "Login Out" start hidden; login and profile scripts toggle them.

### Applicant profile, status, and edit

**Status:** Current.

**Where:** `profile.phtml`, `profileAction`, `updateAction`, `updateimageAction`.

Status labels: New Application, Pending (`Pending == 1`), In Review (`Status == 0` and `DateApply < LastUpdate`), Confirmed (`Status == 1`), Declined (`Status == 2`), Approved (`Status == 3`). Confirmed, Declined, and Approved set `status_locked` and disable inputs.

Services: `Model_AccreditationApplicantsServices::getProfileServices`. Zones: JSON `aZones` via `Model_AccreditationZone::getZonesByIDs`.

Nothing in this repository sets Confirmed or Approved.

### Attendance confirmation and cancellation

**Status:** Current.

**Where:** `attendanceAction`, `attendance.phtml`. `att=1` confirms and emails `EmailAttandanceConfirmed`. `att=2` sets `Status` 2, `History` "Declined by Applicant", and emails `EmailRejected` when that template exists.

`testattendanceAction` and `testattendance.phtml` duplicate this and print exceptions.

### Application email

**Status:** Current.

**Where:** `EmailApplicant`, `EmailApplicantDeclined`, `sendMail`. Sent when `EmailNotes` is non-empty after insert, and on attendance. From `accreditation@magus.events`. Subject on the wire is "The Sun Met Notification".

### Deployment to QA and production

**Status:** Current as pipeline config. Last pipeline-related code change is the appspec/script updates merged toward `prod` in January 2020 (`bf5865d` and neighbours).

**Where:** `bitbucket-pipelines.yml` (branches `qa` and `prod` only), `codedeploy_deploy.py`, `appspec.yml`, `scripts/install_dependencies`, `scripts/start_server`, `scripts/stop_server`, `scripts/remove_archives.sh`.

Destination path: `/mnt/data/www/html/magus.events/sunmet2020.magus.events/`.

## Features present in code and not on the main path

### Alternate apply actions

**Status:** Current as routes, not linked from the home form.

**Where:** `applymultipleAction` / `applymultiple.phtml`, `applytestAction` / `applytest.phtml`. Same insert and close-date pattern as `applyAction`.

### Barcode image

**Status:** Route exists, dependency missing.

**Where:** `ApplicationController::barcodeAction` includes `Barcode39.php` and draws the literal string `FD5T67`. `Barcode39.php` is not in the repository. Calling the route fails at the include.

### Mail test endpoint

**Status:** Current as an unauthenticated route.

**Where:** `ApplicationController::testAction`. Sends a fixed message to `andre.ferraz@evolveav.co.za`.

### Application index of roles

**Status:** Route exists.

**Where:** `ApplicationController::indexAction` assigns `Model_AccreditationRoles::getAll()` to `application/index.phtml`. That view is a short role table, not the wizard.

### Partners page

**Status:** Empty.

**Where:** `partnersAction` and `partners.phtml` (zero lines of markup).

### Sean view

**Status:** Orphan view.

**Where:** `application/modules/default/views/scripts/sean/index.phtml` prints `$this->DATA` if set. There is no `SeanController`.

### Local photo save and resize helpers

**Status:** Present, not used by `applyAction`.

**Where:** `SavePhoto`, `resize_imagejpg`, `thumbnail_data_uri`, `isMobile` (rotation is commented out). `imageAction` sends a GIF header and decodes `$data`, which that method does not set.

### Models with no controller caller in this repo

**Status:** Code present. Not a user-facing feature here.

**Where:** `Accreditation.php`, `AccreditationAdministrators.php`, `AccreditationGates.php` (`EventGates`), `AccreditationHistory.php`, `AccreditationLoadingServices.php`, `AccreditationLoadingZones.php`, `AccreditationPermits.php` (`Accreditation_Permits`), `AccreditationQueing.php` (`AccriditationApplicationQueing`), `AccreditationServices.php`, `AccreditationEventServices.php`, `AccreditationTypes.php`, `AccreditationApplicationRole.php`.

These wrappers match a larger accreditation product (permits, gates, load-in services, administrators). This portal does not call them. **Inferred** they were copied with the shared library. Whether another repository is the admin is **Unknown / Requires Confirmation**.

### PG library plugins

**Status:** Vendored. Only `PG_Controller_Plugin_LayoutPicker` is registered (`application.ini.bak`). It sets the layout name to the module name (`default`), which matches `application/layouts/default.phtml`.

Other files under `library/PG/Controller/Plugin/` (FPDF, html2fpdf, email layout, image uploaders, match report) have no reference from `application/`. `library/Other/Functions.php` and `Notifications.php` are likewise unused by the module controllers.

## Removed or commented

### Openfield and Roth Media invitation

**Status:** Removed on `qa`/`prod` by `cf9251d` (2020-01-13, "Remove Openfield / Roth media from Sunmet media").

**Where:** In `index/index.phtml` the radios "1. Openfield" and "2. Roth Media" (`data[Invitefrom]`) remain inside an HTML comment. `apply.phtml` on `master` does not render those radios.

The commented block is not submitted. Provenance: **Implemented** removal on the live form; leftover comment on the home view.

### Maintenance splash

**Status:** Commented out.

**Where:** `public/index.php` lines that would print a technical-difficulties message and exit are commented. The application boots.

### HTTPS and www redirect

**Status:** Commented out.

**Where:** Root `.htaccess`. The rewrite into `public/` is active. The `https://www.` redirect is not.

### Older Footprint mailbox

**Status:** Commented out.

**Where:** `sendMail`. Active transport is Gmail as `accreditation@magus.events`. The previous `accreditation@footprintapp.net` / `mail.footprintapp.net` block is commented and still contains a password. Not reproduced here.

### Supplier navigation link

**Status:** Commented out in the layout. The in-form note remains. See Supplier registration notice.

## Planned

None found.

## Recently changed

Relative to a repository that stopped in 2020, the last behaviour change on the deploy branches is `cf9251d` (remove Openfield / Roth media). The last change on `master` is the 2020-08-04 rename of `application.ini` to `application.ini.bak` (`2a47b00` is an ancestor edit of the ini; the rename is the `master` vs `prod` diff).

Favicon update `49255db` ("Updated favicon") is in the history before the January 2020 merges. The layout links `favicon.ico` and `/images/icon.png`.

## Not in Git (scan listing)

`sonar-project.properties` and `sonarqube_scan.bat` were listed when this onboarding task was created. They are not tracked. **Unknown / Requires Confirmation.**
