# Business rules — myPass

Evidence date: 2026-10-09. Source: `git@bitbucket.org:overdrive/mypass.git`, `master` at `803166e` (2022-01-27).

There is no business-rules document in the repository. Rules below are taken from the page and from `scripts/core.js`. Each rule is marked **Inferred** when the code enforces it and nobody wrote it down as policy, or **Documented** when the page states it in copy.

Rules that the Footprint API may also enforce are not visible here. This client is the only enforcer in this repository.

## Event access

### BR-001 — One event per hostname label

**Inferred.** The first dot-separated label of the hostname must be a key in `domains.js`. That key's number is the only event id the page will load (`staticEventID`).

The map is the one listed in the PRD (FR-002). `local` and `9hour` both use event `346`. `bil2021media` uses `325`, which is also the variable's initial value before the lookup.

### BR-002 — Unknown host shows no form

**Inferred.** If the label is not in the map, the page content is replaced with the text "Please check subdomain". There is no fallback event.

### BR-003 — Registration closes on the event end date

**Inferred** from `dateInPast`, and **Documented** by the sentence "Registration for this event is now closed."

`DATA.DateTo` is compared as a calendar date in the browser's local timezone. If that date is today or earlier, the personal-details block is hidden and the rest of the event setup (terms, linked events, organisation-reference flag) does not run. The header and the empty step tabs remain.

Who sets `DateTo` is outside this repository.

## Personal details

### BR-004 — Address line 2 is optional

**Inferred.** `checkDivInputs` ignores an empty `#address2`. Other empty inputs, textareas, and selects on the step block Next. The page marks many fields "(required)". The gate does not match those labels for controls whose value is already non-empty (see BR-005).

### BR-005 — A non-empty placeholder counts as filled

**Inferred.** The gate tests `value.length == 0` only. Nationality and country placeholders use value `default`. Birth day and month placeholders use value `00`. Those controls do not block Next. The page still labels the fields as required.

### BR-006 — Email shape is not checked here

**Inferred.** `#email` has class `validate-email`. The step gate does not test for `@` or any other pattern. Any non-empty string passes.

### BR-007 — Mobile tick is cosmetic

**Inferred.** A green tick requires length greater than 9. Next does not read that tick. On submit, leading zeros are removed and the dial code is sent separately as `mobileNumberPre`.

### BR-008 — Ethnicity is collected for South Africa only

**Inferred.** The ethnicity control is enabled only when nationality is exactly the string `South Africa`. Options are African Black (`African_Black`), White, Indian, and Coloured.

The script still reads the select when it is disabled, so the posted ethnicity can be the placeholder `default`.

### BR-009 — Prefer not to say is stored as male

**Inferred.** The form offers Prefer not to say. `submitRegistration` sends `F` only when Female is checked, and `M` otherwise. No third code is sent. There is no written rule that says this is the policy.

### BR-010 — Birth year defaults to 1990

**Inferred.** The generated year list selects 1990. The allowed range is 1930 through the current year. Day and month can remain `00` and still pass the step gate (BR-005). The posted birthday string is `{day}-{month}-{year}`.

### BR-011 — Pass name is derived, then editable

**Inferred.** First name replaces the pass name. Each surname change appends a space and the current surname. The field is not locked. The empty check treats it as required on the Identity step.

## Organisation and role

### BR-012 — Organisation reference is looked up, not typed as the name

**Inferred**, except when BR-013 applies. The reference is uppercased and sent to `getorganisation`. The name field stays disabled and is filled from `TradingName` of the first returned row.

Auto-search runs when the typed length is 6. The fetch line's comment example is `07D40F4D5C91` (12 characters). The page also searches on change and on the search button at any length. Which length the business requires is **Unknown / Requires Confirmation**.

The reference field is exempt from the empty check. The name field is not, so Next stays disabled until a name exists.

### BR-013 — Some events do not require an organisation reference

**Inferred.** If `RegistrationFields.RequireOrganisationReference` is the string `"0"`, the reference row is hidden and the visitor types the organisation name.

Any other value, including a missing field, leaves the reference row in place. Provenance: the `if` only tests equality with `"0"`.

### BR-014 — Role list follows the category

**Inferred.** Roles are the event's `Roles` array. If the category value is `0`, every role is listed. Otherwise only roles with the same `ACID` are listed. Category and role ids posted are the option values (`ACID` and `ARID` when the API filled the lists).

### BR-015 — Role description is required by the empty check

**Documented** by the on-page hint: describe function and responsibilities, and include special access and the reason for it. **Inferred** that an empty textarea blocks Identity Next.

### BR-016 — A photo file is required to leave Identity

**Inferred.** The file input sits in the Identity step and its empty value fails `checkDivInputs`.

**Documented** photo rules on the page:

- Clear, sharp, and in focus.
- Both sides of the face visible.
- Face and shoulders centred.
- No hair across the eyes.
- No hats, caps, sunglasses, or head coverings.
- Uniform lighting.

The client does not measure those rules. It only requires a chosen file and offers a crop tool. The hint also says to click CROP before Next. `setTabActive` for steps 3 and 4 calls `cropImage()` anyway when no crop has been stored yet. That call assumes EDIT PHOTO was used. If it was not, the crop call throws.

## Events and declarations

### BR-017 — Linked events are optional for the product only when the event says so

**Inferred.**

- `MediaEvent == "0"`: Events step is not shown. `eventsLinked` is an empty array unless something was checked earlier.
- `MediaEvent` is anything else and `Linked` is missing: same, the step is hidden.
- `Linked` is present and `MediaEvent` is not `"0"`: the visitor must check at least one linked event before Next.

The application event id (`eventID`) is still the subdomain's event. Linked ids are additional.

### BR-018 — Both declarations are required

**Inferred** from `oncheckSubmit`. **Documented** by the checkbox labels.

1. "I have read the Terms and Conditions and accept." Terms body is HTML from `DATA.TermsAndConditions`, shown in a modal. Until the event call returns, the modal says "Waiting for Terms And Conditions".
2. The second label is `DATA.AccreditationNote`. The HTML default, if the API has not replaced it, states that the person has not had close contact with a confirmed Covid-19 case in the last 14 days and has not been diagnosed with Covid-19 in the last 14 days.

Submit sends `tandcCheck` and `covidCheck` as `1` or `0`. The button is only shown when both boxes are checked, so a completed submit sends `1` for both.

## After submit

### BR-019 — The client shows success only when the POST returns JSON

**Inferred.** The success panel is filled from `EVENTNAME` and `REFNUMBER`. There is no check that those properties exist. A JSON error body would still open the panel.

### BR-020 — The contact address is fixed

**Documented** on the success panel as `info@mypass.zone` (commit `097486a`). The API field `EMAIL` is not displayed.

### BR-021 — The page claims a confirmation email was sent

**Documented** in the success copy: "We've sent you a confirmation email with below reference number and you will receive more info once your application has been processed by the {EVENTNAME} Team."

This repository does not send email. Whether the API does is **Unknown / Requires Confirmation**.

### BR-022 — Close starts a new application

**Inferred.** CLOSE clears text inputs and reloads the page. The previous payload is not kept in `localStorage`. `regFormDetails` (the event JSON) remains until the browser clears it; the reload fetches the event again and overwrites that key.

## What this client does not decide

- Whether the organisation reference exists, or whether the organisation has reached a limit. A missing row is an unhandled failure (search spinner can remain). `LimitReached` is not read. The later `myPass-registration` client does read it. That is not a rule of this repository.
- Whether the identity number, email, or photo meets an accreditation standard.
- Whether the application is approved, declined, or printed as a pass.
- Who may use a subdomain. Anyone who can open the URL can submit.

## Conflicts inside this repository

| Topic | What the page says | What the script does |
|---|---|---|
| Required nationality, country, day, month | Labels say required, placeholders look unselected | Values `default` and `00` pass the gate |
| Prefer not to say | Third gender option | Payload is `M` |
| Organisation reference length | Comment example is 12 hex characters; the field says required | Auto-search at 6 characters; the reference is exempt from the empty check |
| Crop before Next | Instruction to click CROP | `setTabActive` also crops, and throws if the cropper was never created |
| Events Next after the step is hidden | Collapse opens Submit | `onclick` still calls `setTabActive('3')`, and `setTabActive('4')` looks up a missing `#tab5` |
| Confirmation email | Success copy says one was sent | No mail code in this repository |
| Contact email | Panel shows `info@mypass.zone` | Response `EMAIL` is ignored |
