# Technical documentation — myPass-registration

Evidence date: 2026-10-09. Source: `git@bitbucket.org:overdrive/mypass-registration.git`, `master` at `e1a887a` (2023-01-18).

## Summary

Static registration front end. No build, no package manifest, no application server, no database. The browser loads `index.html`, which loads the Enabled theme, `domains.js`, and `scripts/core.js`. Registration state is JavaScript variables plus one `localStorage` copy of the event payload. Persistence of applications is the Footprint API.

## Repository layout

| Path | What it is |
|---|---|
| `index.html` | Registration page, success panel, limit panel, terms modal, warning sheet |
| `scripts/core.js` | Product logic. This is the file to change for behaviour |
| `scripts/custom.js` | Vendored theme: preloader, icon validation, menus, service worker, PWA prompt |
| `scripts/bootstrap.min.js` | Bootstrap 5.0.0-beta2 bundle plus theme libraries (header credits Enabled / `http://enableds.com`) |
| `scripts/core_old.js`, `scripts/core_epic.js` | Previous client. Not referenced by `index.html` |
| `domains.js` | Fallback `demo` config and unused domain entries |
| `_service-worker.js` | Cache-first worker for `index.html` |
| `styles/`, `scss/` | Compiled theme CSS and SCSS sources, including highlight palettes. The page links `styles/bootstrap.css` and `styles/style.css?v1.002`. No compile step is configured in the repo |
| `plugins/cropme/` | Cropme source and minified build. The page loads the minified JS and CSS |
| `plugins/charts/charts.js` | Chart library. Not referenced by `index.html` |
| `fonts/` | Font Awesome |
| `images/` | Theme and form images, including the orange loader gif and the profile placeholder |
| `app/icons/` | Default favicon and apple touch icon (`app/icons/favicon.ico`, `app/icons/icon-192x192.png`) |
| `exports/` | Design HTML and CSS for an older multi-screen MyPass app. Not linked |
| `menu-*.html`, `screen_result_review_old.html` | Theme leftovers. Not the registration flow |
| `php/contact.php` | Unused PHP `mail()` script |
| `bitbucket-pipelines.yml` | Deploy |
| `sonar-scanner.bat` | SonarScanner Windows launcher. `SONAR_SCANNER_HOME` is `C:\sonar-scanner\bin\..`. No `sonar-project.properties` is in this revision |

The onboarding inventory that created OVER-204 also named `sonar-project.properties` and `sonarqube_scan.bat`. They are not in `master` at `e1a887a`.

`.gitignore` is a generic template (`node_modules/`, `dist/`, IDE files, logs). There is no Node build for those entries to ignore.

## Runtime

### Scripts the page loads

Order at the bottom of `index.html`:

1. Inline `page = "registration"`. `load_js` is defined and not called. It also appends the wrong element (`script` rather than `script2`), so it would not load `core.js` a second time correctly if it were called.
2. `scripts/bootstrap.min.js`
3. `scripts/custom.js?v1.000`
4. `domains.js`
5. `scripts/core.js?v1.307`

Cropme is loaded from inside the body, before the form: `plugins/cropme/cropme.min.js` and `cropme.min.css`.

`core.js` expects a global `page` and a global `domains`. Both are set by the tags above. `custom.js` and `core.js` each declare `var pwaName = "MyPass"`.

### Page load sequence

`DOMContentLoaded` in `core.js`:

1. Read subdomain from the hostname.
2. Hide `#ethnicity_row`.
3. `POST` styling.
4. Apply styling or replace the body with `domains.demo`.
5. Call `doPageLoad`.

`doPageLoad` for `page === "registration"`:

1. Fire `getevent` (async).
2. Paint the active tab from `data-highlight` when that attribute is present (`4fe97e6`).
3. Fill `#birthdayYear` and bind the file input.
4. Apply `form` show/hide: for each key, set `{key}_row` and `{key}_label` display. Demo `form` keys are `ethnicity`, `gender`, `additional`, `message`. `message` is an object, so that iteration throws inside the per-key `try` and is logged as "Invalid div". `additional_row` does not exist and takes the same path. `ethnicity_row` and `gender_row` do exist.

The `getevent` callback then fills the event, or hits the close-date return.

`debug` gates `loging`. It is `false`, so those logs are silent.

### State

| Store | Contents |
|---|---|
| `registerUser` | Mutable object posted on submit. `profileImage` may be set before the rest of the fields |
| `staticEventID` | Event id. Initial value `346` is replaced in `doResponse` before `getevent` |
| `formFields` | `form` from styling or from `domains.demo` |
| `localStorage['regFormDetails']` | Full `getevent` JSON, used by `roleSelect` |
| `localStorage['MyPass-Highlight']` | Forced to `green` on every load |
| `localStorage['MyPass-PWA-Timeout-Value']`, `MyPass-PWA-Prompt` | Theme install prompt. Prompt UI is absent, timeout key can still be set when `isPWA` is true |
| `croptimes` | `1` after a successful crop. Gates the automatic crop on later steps |

No cookie and no server session in this repo.

## API

Base: `https://footprintapp.net/api/mypass/`.

`qa` is `""`. A non-empty `qa` would insert a subdomain (`https://qa.footprintapp.net/...` if `qa` were `"qa."`). That is not the current assignment. Commit `3d778f4`.

All calls use `fetch`. POST bodies are `JSON.stringify` with `Content-Type: application/json; charset=UTF-8` and `mode: 'cors'`. No `Authorization` header.

### POST `/getstyling`

Body: `{ "domain": "<first hostname label>" }`.

Client reads: `eventID`, `form`, `styling`. Styling objects may contain `style` (CSS properties), `data-highlight` (two colour pairs separated by `;`, each pair comma-separated), and `src` (image `src`, or `href` when the key is `favicon`).

Field map:

| Styling key | Element ids |
|---|---|
| `favicon` | `favicon`, `appleFavicon` |
| `regTopDiv` | Both top bars and the primary buttons: `nextBtnOne`, `searchBtn`, `file-upload`, `editBtn`, `cropBtn`, `nextBtnTwo`, `nextBtnThree`, `submitRegistration`, `regConfClose` |
| `regBotDiv` | `staticRegBotDiv`, `dynRegBotDiv` |
| `eventName` | `eventName`, `eventName2` |
| `regTabBar` | `staticRegTabBar`, `dynRegTabBar` |
| `tabs` | `tab1`–`tab4` and `tab11`, `tab21`, `tab31`, `tab41` |
| `headers` | `h1`, `h2`, `h3`, `h4` (ids, not tag names). Those ids are not on the registration page, so header styling no-ops |

Failure: `doResponse({})`, which selects `domains.demo`.

### GET `/getevent/EventID/{id}`

Client reads:

| Path | Use |
|---|---|
| `AccreditationTitle` | HTML under the banner |
| `DATA.AccreditationName` | Both titles |
| `DATA.MypassBackground` | `document.body.style.backgroundImage` |
| `DATA.AccreBanner` | `#topBanner` |
| `DATA.CloseDate` | Close check |
| `DATA.TermsAndConditions` | Terms modal HTML |
| `DATA.AccreditationNote` | Not used. Assignment to the Covid label is commented out |
| `DATA.RequireOrganisationReference` | `"0"` hides the reference |
| `RegistrationFields.Address`, `.City` | CSS display |
| `Cats[].ACID`, `.Category` | Category select |
| `Roles[].ARID`, `.Role`, `.ACID` | Role select |
| `MediaEvent` | `"0"` hides Events |
| `Linked[].LID`, `.Acc_Secondary` | Event checkboxes |

The whole object is stored and later parsed in `roleSelect`.

### GET `/getorganisation/ORefNumber/{ref}`

`ref` is uppercased and placed in the path with no extra encoding in the client.

Client reads `json[0].TradingName` and `json[0].LimitReached`.

### POST `/postaccreditation`

Body is the `registerUser` object documented as FR-010 in `prd.md`. Response fields read: `EVENTNAME`, `REFNUMBER`. `EMAIL`, `FIRSTNAME`, and `SURNAME` are mentioned only in comments.

## Domain fallback object

`domains.demo` is the only entry `core.js` uses.

```text
eventID: 87
form.ethnicity: block
form.gender: block
form.additional: none
styling colours: #798a7f
regTabBar data-highlight: #ffffff,#798a7f;#798a7f,#ffffff
```

`form.message.role` is a long string about race crew. The show/hide loop does not treat `message` as copy, and nothing assigns it to `#role_message`.

## Deployment and environments

`bitbucket-pipelines.yml` uses image `atlassian/default-image:2`.

One pipeline, branch `master`, deployment environment name `production`:

1. Pipe `atlassian/aws-s3-deploy:0.5.0` with `LOCAL_PATH: $BITBUCKET_CLONE_DIR`.
2. Pipe `atlassian/aws-cloudfront-invalidate:0.3.3`.

Variables (names only; values are not in the repo):

- `REGISTER_PROD_AWS_ACCESS_KEY_ID`
- `REGISTER_PROD_AWS_SECRET_ACCESS_KEY`
- `REGISTER_PROD_AWS_DEFAULT_REGION`
- `REGISTER_PROD_AWS_S3_BUCKET`
- `REGISTER_PROD_CLOUDFRONT_DISTRIBUTION_ID`

No staging or QA pipeline. No Docker, CodeDeploy, or server config.

The public URL, bucket name, and whether dotfiles such as `.git` are included by that pipe version are **Unknown / Requires Confirmation**.

Local viewing is a static file open or any HTTP server. `custom.js` comments say AJAX page transitions need a server; the registration flow does not use those transitions. `isAJAX` is `true` in the theme script.

## PWA and cache

| Setting | Value | File |
|---|---|---|
| `isPWA` | `true` | `custom.js` |
| Scope | `/` | `custom.js` |
| Worker | `/_service-worker.js` | `custom.js` |
| Cache name | `Cache-Version-v1.309` | `_service-worker.js` |
| Precache | `index.html` only | `_service-worker.js` |
| Fetch strategy | Cache match, otherwise network | `_service-worker.js` |
| `pwaNoCache` | `false` | `custom.js` |
| Remind | 1 day | `custom.js` |
| HTML | `Pragma: no-cache`, `Expires: -1`, apple mobile web app capable | `index.html` |

There is no web app manifest link in `index.html`.

Install adds only `index.html`. The fetch handler returns any cache hit, then the network, and does not write later responses back into the cache. A cached `index.html` keeps the script URL `scripts/core.js?v1.307`. That query string, the stylesheet `v1.002`, `custom.js?v1.000`, the worker name `v1.309`, and commit `28c48e5` ("Changed version to 1.308") are independent of each other.

## Security

Observed in this repository:

- Applications are anonymous. The API URL is in the script.
- ID number, contact details, and a photo data URL are in the JSON body.
- Event JSON, including terms HTML, is stored in `localStorage`.
- `AccreditationTitle` and `TermsAndConditions` are written with `innerHTML`.
- Organisation reference is concatenated into a URL path.
- `php/contact.php` builds mail headers from POST fields and is unused. It is still in the tree that the pipeline uploads.
- No captcha, rate limit, or CSRF token on the form. CSRF is less meaningful without a cookie session; the API's own rules are **Unknown**.
- Pipeline secrets are variable references, not literals.

## Auth, jobs, queues, monitoring

None in this repository. No background worker, queue, or metrics client. SonarScanner launcher is present without a project properties file.

## Development and testing

No `package.json`, Composer file, PHPUnit, Jest, or CI test step. The pipeline only deploys.

To inspect behaviour, serve the directory over HTTP and load `index.html`. Event content will not appear unless `footprintapp.net` answers `getstyling` for that hostname's first label. Forcing the demo path requires the styling call to fail or to omit `eventID`.

`debug = true` also forces domain `cpt7smedia` and turns `console.log` on via `loging`. That flag is off in `e1a887a`.

## Legacy client (not loaded)

`core_old.js` wraps the same host in `requestAPI(request, body)` as `POST` or path-style URLs under `/api/mypass/`. Calls found there, besides registration:

- `getlogin`, `getpwdreset`, `postpwd`, `postuserprofile`
- `geteventsperuser`, `getmypassdetails`
- `getupcomingtest`, `getresults`, `gethealthcertificatevaccine`

`core_epic.js` follows the same pattern and contains a comment referencing `https://app.mypass.zone/index.html` and `http://local.mypass/index.html` for a symptom page. Those URLs are comments, not the registration page's API host.

Do not treat that client as the current product. `index.html` never loads it.

## External theme behaviour that can surprise a change

`custom.js` runs on `DOMContentLoaded` and will throw or no-op when expected theme nodes are missing. Known interaction with this page:

- Preloader `#preloader` is hidden after 150ms.
- `.menu` elements are set to `display: block`, which includes the terms modal and the red warning sheet.
- `checkDivInputs` shows `#menu-warning` when a step is invalid. The sheet's own copy is still the theme sentence "You can continue with your previous actions." It is not a field-level error.
- Install-prompt code is skipped because the install menus are absent.
- `online` and `offline` listeners call `isOnline` / `isOffline`, which expect `.online-message` and `.offline-message`. Those nodes are not in `index.html`. Submit does not check `navigator.onLine`.

## Related Silicon Ark project

`track.mypass.zone` documents a different repository (Zend Framework, MySQL, PIN login, event id `367`). This repo's unused `domains.rwcsevens` entry also uses `367`, and both talk about MyPass accreditation. A shared backend is **Unknown / Requires Confirmation**. This front end does not connect to the track database.
