# Technical documentation — myPass

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

## Architecture

A static site. One product page, two application scripts, a domain map, and a vendored mobile theme. Persistence and accreditation rules live in the Footprint HTTP API. This repository has no server runtime of its own.

```text
index.html
  styles/bootstrap.css
  styles/style.css
  fonts/  (Font Awesome, local)
  fonts.googleapis.com  (Inter)
  plugins/cropme/cropme.min.js
  scripts/bootstrap.min.js
  scripts/custom.js          theme behaviour, service worker registration
  inline: page = "registration"
  domains.js                 label → event id
  scripts/core.js?v101       form behaviour and API calls
        |
        |  HTTPS, no auth header
        v
https://footprintapp.net/api/mypass/
```

`scripts/core.js` builds the host as `'https://' + qa + 'footprintapp.net'`. `qa` is `""`.

## Repository layout

| Path | Role |
|---|---|
| `index.html` | Registration page. About 1,250 lines, most of them hardcoded nationality, country, and dial-code `<option>`s |
| `domains.js` | Object `domains` |
| `scripts/core.js` | Application script. `debug = true` |
| `scripts/custom.js` | Enabled theme script. `pwaName = "MyPass"`, `isPWA = true`, `isAJAX = true` |
| `scripts/bootstrap.min.js` | Bootstrap bundle used by the page |
| `_service-worker.js` | Cache-first worker |
| `php/contact.php` | Unused theme mailer |
| `country.json` | Unused country dataset |
| `bitbucket-pipelines.yml` | S3 deploy and CloudFront invalidation |
| `styles/`, `scss/`, `fonts/`, `plugins/`, `template/`, `menu-*.html` | Theme |
| `exports/` | Adobe XD HTML exports and images |
| `images/` | Runtime images, including `profilePlasholder.png` and `loading_orange.gif` |
| `app/icons/`, `app/splash/` | PWA icon and splash images. `index.html` links the apple touch icon to `app/icons/icon-192x192.png`. No web app manifest is linked from `index.html` |
| `.scannerwork/` | Committed SonarQube working files |
| `sonar-scanner.bat` | Stock scanner launcher, `SONAR_SCANNER_HOME=C:\sonar-scanner\bin\..` |
| `.gitignore` | Generic Atlassian sample. It does not ignore `.scannerwork/` |

Not present: `package.json`, `composer.json`, README, automated tests, Dockerfile, `sonar-project.properties`, `plugins/nscripts`.

## Languages and libraries

| Item | Evidence |
|---|---|
| HTML, CSS, JavaScript | The page and scripts. No build step is configured |
| Bootstrap | `styles/bootstrap.css`, `scripts/bootstrap.min.js`. The theme script uses `bootstrap.Alert` and `data-bs-toggle="collapse"` |
| Cropme | `plugins/cropme/cropme.min.js`, loaded in the page body |
| Font Awesome | `fonts/css/fontawesome-all.min.css` |
| PHP | `php/contact.php` only. It is not part of the page |
| SCSS | `scss/` is theme source. The page links compiled CSS under `styles/`, not the SCSS |

There is no npm or Composer manifest, so versions are whatever is vendored in the files. They were not extracted beyond the filenames.

## Runtime data

No database and no cookie session.

| Store | Key or object | Contents |
|---|---|---|
| In-memory | `registerUser` | Application payload, including the photo data URL |
| In-memory | `staticEventID` | Event id, initial `325`, then the domain map |
| In-memory | `qa` | Always `""` |
| In-memory | `profileImage` | Cropme instance after EDIT PHOTO |
| In-memory | `croptimes` | `0` until a crop promise resolves, then `1` |
| `localStorage` | `regFormDetails` | Full `getevent` JSON, read back by `roleSelect` |
| `localStorage` | `MyPass-Highlight` | Forced to `green` on every load |
| `localStorage` | `MyPass-Theme`, `MyPass-Gradient`, `MyPass-PWA-Prompt`, `MyPass-Last-Visited`, `MyPass_Visited_Links` | Theme script. The registration page does not render the controls that set most of these |
| Cache Storage | `Cache-Version-v1` | `index.html` only |

`sessionStorage.clear()` is called from the theme script when the PWA flag runs. The registration flow does not read `sessionStorage`.

## API

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

Browser `fetch`. GET responses are parsed as JSON. POST sets `mode: 'cors'` and `Content-Type: application/json; charset=UTF-8`. No `Authorization` header and no API key. A May 2021 commit subject says "new production key" (`5019f27`). The current script does not send a key. What that commit changed was not copied here.

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

Called once on DOM ready when `page == "registration"`.

Consumed members: `AccreditationTitle`, `DATA.AccreditationName`, `DATA.AccreBanner`, `DATA.DateTo`, `DATA.TermsAndConditions`, `DATA.AccreditationNote`, `Cats[]`, `Roles[]`, `MediaEvent`, `Linked[]`, `RegistrationFields.RequireOrganisationReference`.

The whole object is stored under `regFormDetails`.

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

`ref` is the organisation field, uppercased, not URL-encoded in the script. Success path uses `json[0].TradingName` only.

### POST `/postaccreditation`

Body is `JSON.stringify(registerUser)` after the fields in PRD FR-010 are copied onto that object. Success path reads `EVENTNAME` and `REFNUMBER`. `EMAIL`, `FIRSTNAME`, and `SURNAME` are referenced only in comments.

## Page behaviour worth knowing when changing the script

`setTabActive(tabNumber)` clears `data-active` and `class` on `#tab1`–`#tab4` and `#tab11`–`#tab41`, then marks `#tab{n}` and `#tab{n+1}`. For `n == 4`, `#tab5` is null and `setAttribute` throws.

The duplicate tab strip (`#tab11` and so on) is the in-page strip. The header strip is `#tab1`–`#tab4`. Both are `pointer-events: none`.

`checkDivInputs` does not use HTML5 `required`, does not use the theme `validate-name` / `validate-email` classes, and does not skip `disabled` controls. Disabled `#orgName` with an empty value still fails the Identity step.

`onNationality` uses `option.text.includes(nationality)` for both country and dial code, first match wins.

Gender radios are not read by value. Only `#female.checked` is tested.

File input `accept="image/*"`. Crop viewport width 250, height 280, type `square`.

## Service worker

`scripts/custom.js` registers `/_service-worker.js` with scope `/` after `window` `load`, if `isPWA` is true and the root `<html>` element does not already have class `isPWA`. It then adds that class.

The worker:

- Cache name `Cache-Version-v1`.
- Precaches `index.html`.
- `fetch`: return the cache hit, otherwise `fetch(event.request)`.
- `install` calls `skipWaiting`. `activate` calls `clients.claim`.
- It does not delete old caches.

`pwaNoCache` in the theme script is `false`.

## Deployment

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

| Branch | Steps | Variables |
|---|---|---|
| `qa` | `atlassian/aws-s3-deploy:0.4.4`, then `atlassian/aws-cloudfront-invalidate:0.3.3` | `QA_AWS_ACCESS_KEY_ID`, `QA_AWS_SECRET_ACCESS_KEY`, `QA_AWS_DEFAULT_REGION`, `QA_AWS_S3_BUCKET`, `QA_CLOUDFRONT_DISTRIBUTION_ID` |
| `master` | Same pipes | `PROD_AWS_ACCESS_KEY_ID`, `PROD_AWS_SECRET_ACCESS_KEY`, `PROD_AWS_DEFAULT_REGION`, `PROD_AWS_S3_BUCKET`, `PROD_CLOUDFRONT_DISTRIBUTION_ID` |

Both S3 steps set Bitbucket `deployment: production`, including the `qa` branch step.

`LOCAL_PATH` is `$BITBUCKET_CLONE_DIR`, so the upload is the whole clone, not a built `dist/`. That includes `template/`, `exports/`, `php/`, and `.scannerwork/`.

The remote that was cloned has only `master`. Branch `qa` is not on the remote. Whether a `qa` branch existed when the pipeline file was written is **Unknown**.

No deploy secrets are stored in the repository. The variable names above are the only AWS identifiers in git.

## Auth

None on this front end. The form is public. The API calls send no credentials. CORS is requested on the POST (`mode: 'cors'`). Whether the API allows this origin is decided on `footprintapp.net`, which is not in this repository.

## Background work

No queues, cron, or workers. The service worker is a browser cache, not a job runner.

## Monitoring and quality

Commit `da1b9b8` (2021-07-10) is "Sonar-Scan done". The committed report `.scannerwork/report-task.txt` records:

- `projectKey=MyPassRegistration`
- `serverVersion=8.9.1.44547`
- A `serverUrl` and `dashboardUrl` on an IP address (see that file). The address is not repeated here because it is an environment endpoint, not a product rule.

The pipeline does not run SonarQube. `sonar-project.properties` is not in `master`. The onboarding brief also named `sonarqube_scan.bat`, which is absent.

`debug = true` logs API bodies to the browser console via `loging`.

## Development and testing

No test directory, no CI test step, no lint config at the repo root (a stylelint config exists only inside `.scannerwork/css-bundle/`).

Local viewing: the theme script checks `window.location.protocol === "file:"` and notes that PWA registration and AJAX transitions need a server. The registration API calls need network access to `footprintapp.net` and a hostname whose first label is in `domains.js`. Opening the file directly, or opening `localhost` (first label `localhost`, which is not in the map), replaces the form with "Please check subdomain". The label `local` is in the map (event `346`). A host such as `local.something` would take that branch. Provenance: **Implemented**.

Script cache bust on the page is `scripts/core.js?v101` only. Other assets have no query string.

## Security notes visible in the tree

These are observations, not a pentest.

- Terms and the second declaration are assigned with `innerHTML` from the API (`TermsAndConditions`, `AccreditationNote`). Category and role labels are concatenated into HTML option strings. Linked-event labels are concatenated into HTML. If the API returns markup, the page will parse it.
- `php/contact.php` reads POST fields into a mail header (`From`, `Reply-To`) and sends them with `mail()`. It is unused by `index.html`. The recipient is the placeholder `mail@domain.com`.
- The organisation reference is interpolated into the URL path without encoding.
- `localStorage` keeps the full event payload on the visitor's browser.
- The photo is a data URL inside the JSON body.
- `.scannerwork/` is committed, including a scanner report that names an internal SonarQube endpoint.

## Related codebases

| Silicon Ark | What it adds that this repo does not |
|---|---|
| `myPass-registration` | `POST /api/mypass/getstyling` to resolve the event, demo fallback, `LimitReached` on organisation lookup, later close-date and Covid-checkbox edits through 2023-01-18 |
| `myPass-App` | Signed-in PWA: events, health, vaccination, pass QR |
| `track.mypass.zone` | Zend Framework permit dashboard against MySQL `teamwizz_SARU` |

Shared API host `footprintapp.net` is the reason these are listed together. A shared database is **Unknown / Requires Confirmation**.
