# PRD — reactFrontend (Footprint Reboot)

Evidence date: 2026-10-05. Source: `git@bitbucket.org:overdrive/reactfrontend.git`, `master` `25c9bd8` (2020-07-17).

Provenance labels: **Documented**, **Implemented**, **Inferred**, **Planned**, **Unknown**.

No formal PRD existed in the repository or in `silicon_ark/reactFrontend/` before this file. Requirements below are recovered from the React screens, the route table, and the API calls those screens make. They are not a new product decision.

A fixed password string passed to `Auth.signUp` in `src/views/app/pages/user/account-management-content.js` is omitted. The Firebase web config in `src/constants/defaultValues.js` is omitted. The files that hold them are named where the behaviour depends on their presence.

## Product purpose

A person opens a web app titled **Footprint Reboot**. The login card says **LEAVING A FOOTPRINT FOR OTHERS TO FOLLOW** and asks for credentials. After a Cognito sign-in, the shell opens at `/app`, which redirects to `/app/dashboards`. The custom navigation then offers Insight, Members, Organisations, Tournaments, Squads, Medical, and Settings.

**Documented** title: `public/index.html`. **Documented** package description: "Footprint, team management software" in `package.json`. **Implemented** login copy: `src/views/user/login.js`.

The app is a front end. It does not contain the member database or the Cognito user pool.

## Users and interactions

The route guard does not read a role. `AuthRoute` in `src/App.js` allows `/app` when Redux `authUser.user` is truthy. That value is initialised from `localStorage` key `user_id` (`src/redux/auth/reducer.js`). Login stores the Cognito `username` under that key.

The top bar separately calls `Auth.currentAuthenticatedUser()` and then `GET /members/{custom:memberid}` (`src/containers/navs/Topnav.js`). Until that returns, `global.GroupID` is set to `2`. On success it becomes `memberDetails.GroupID`.

Permission rows are loaded for a member profile (`POST /footprint/userpermissions` with `ModulePermission: "Members"`). `canRender` does not use them. See FR-012.

No document in the repo names personas (player, official, union administrator). The member profile home tab contains both a "Player" card and an "Official" card shape, and the player branch is what the render uses. **Inferred** from `contentTabs/home.js`. Which person is allowed to open which menu is **Unknown / Requires Confirmation**.

## Major workflows

1. Open `/`. The app redirects to `/user/login`.
2. Submit username and password. Cognito `signIn`. On success, go to `/app`.
3. Open Members → Manage. The page loads organisation types, groups, and roles, then posts a member search.
4. Open a member row. The profile loads verbose member JSON and a permission list, then shows tabs: Home, Profile, Medical, Performance, Documents, Settings.
5. Edit a profile subsection (general, identity, other, address, next of kin, email). The form posts to a `/footprint/updateuser*` path. Success feedback in the general form is an `alert`, including when the post throws (the alert is not inside the `try`).
6. Activate an account from the member Settings tab when a sign-in email is present. The page calls `Auth.signUp`, then posts `updateuuid` and `updatememberactive`.
7. Forgot password from the login link. Cognito sends a code. The reset page submits it. A separate confirm-code page confirms a sign-up and then starts forgot-password.
8. Settings → Groups loads groups and permission modules and can post flag changes.
9. Squads and tournaments open pages whose lists are arrays in the source file. Changing a squad filter shows an `alert` and does not call an API.

## Integrations

| System | Direction | Trigger | Evidence |
|---|---|---|---|
| Amazon Cognito, pool `eu-west-1_16nNqbqeS`, client `54akdkecv9neibv7fapo9r3p80`, flow `USER_PASSWORD_AUTH` | Browser to AWS | Login, logout, forgot password, confirm sign-up, account activation sign-up | `src/helpers/Amplify.js`, `src/views/user/index.js`, `src/redux/auth/saga.js` |
| Footprint HTTP API | Browser to API | Member search, profile load and save, permissions, activation | `src/helpers/footprintAPI.js`, `src/views/user/index.js`, page files under `src/views/app/pages/user` and `settings/groupsAndRoles.js` |
| Second Amplify API endpoint `https://dev.reboot.footprintapp.net/api` | Browser to API | Any Amplify `API` call made before `src/views/user/index.js` has loaded, and after a refresh that never loads that module | `src/helpers/Amplify.js`, imported by `src/App.js` |
| API Gateway `afsxv57muc.../dev/footprint` | Browser GET with query `id=220` | Organisation dashboard mount | `src/views/app/pages/organisation/dashboard.js` |
| S3 bucket `footprint-reboot-app` | Config only | Amplify Storage block. No product upload call found | `src/helpers/Amplify.js` |
| Firebase project `gogo-react-login` | Not started | `src/App.js` comments out `./helpers/Firebase`. Config object remains in `defaultValues.js` | **Implemented** as unused config |

The two live API hosts and the older commented hosts are listed in `technical-documentation.md`. Which host answers production traffic is **Unknown / Requires Confirmation**.

Failure behaviour that is in the code: API `catch` blocks log to the console and clear a loading flag. They do not show a user-facing message, except login and password flows, which raise `NotificationManager.warning`. Activation failures are `console.log` only.

## Constraints

- Create React App, React 16, not ejected. Scripts: `start`, `build`, `test`, `eject`.
- `homepage` in `package.json` is `http://localhost/`.
- `browserslist` excludes Internet Explorer 11 and Opera Mini.
- Default theme colour constant is `dark.blue` (`src/constants/defaultValues.js`). `public/index.html` paints a dark background when the stored theme name contains `dark`.
- English is the default locale. Spanish and an English RTL locale exist in `localeOptions`.
- No server, database, queue, or worker is in this repository.

## Functional requirements

### FR-001 — Unauthenticated entry

Requirement: A request to `/` redirects to `/user/login`. `/user` redirects to `/user/login`.

Who: Any browser.
Trigger: Navigation to those paths.
Inputs: None.
Expected behaviour: `src/views/index.js` and `src/views/user/index.js` render `<Redirect>`.
Outputs: Login screen.
Validation: None.
Error: Any other unknown path under the root `Switch` redirects to `/error`.

Evidence: `src/App.js`, `src/views/index.js`, `src/views/user/index.js`.
Implementation: **Implemented**.
Confidence: High.

### FR-002 — Sign in

Requirement: The login form collects a username and a password. Empty username is rejected with "Please enter your user name". Password shorter than 4 characters is rejected with "Value must be longer than 3 characters". The email-format check is commented out. Submit calls Cognito `signIn`. On a result without a `message` property, the username is stored in `localStorage` as `user_id` and the browser goes to `/app`. Otherwise the Cognito message is shown as a warning for 3 seconds.

Who: A person with Cognito credentials.
Trigger: Login button.
Inputs: `email` field (label is the username message), `password`.
Expected behaviour: `src/redux/auth/saga.js` `loginWithEmailPassword`.
Outputs: Redirect to `/app`, or a notification.
Validation: Field validators in `src/views/user/login.js`.
Error: Cognito errors that are objects with `message` stay on the login page.

Evidence: `src/views/user/login.js`, `src/redux/auth/saga.js`.
Implementation: **Implemented**.
Confidence: High.

### FR-003 — Route guard

Requirement: `/app` and everything under it render only when Redux `loginUser` is truthy or `isDemo` is true. `isDemo` is `false`. Otherwise the browser is sent to `/user/login` with `state.from` set to the attempted location. The guard does not read that `from` value on the login page after success; success always pushes `/app`.

Who: Any browser.
Trigger: Navigation under `/app`.
Inputs: `localStorage.user_id` via the auth reducer.
Expected behaviour: `AuthRoute` in `src/App.js`.
Outputs: App shell, or redirect to login.
Validation: Truthiness of the stored id. It is not checked against Cognito on this path.
Error: A stored id with an expired Cognito session still passes this guard. The top bar's `currentAuthenticatedUser` call can then fail and only logs. **Implemented**.

Evidence: `src/App.js`, `src/redux/auth/reducer.js`, `src/containers/navs/Topnav.js`.
Implementation: **Implemented**.
Confidence: High.

### FR-004 — Sign out

Requirement: Logout calls Cognito `signOut`, removes `user_id`, and pushes `/` (which redirects to login).

Who: A signed-in person using the top bar logout action.
Trigger: `LOGOUT_USER`.
Inputs: History object.
Expected behaviour: `src/redux/auth/saga.js` `logout`.
Outputs: Login page. The saga `catch` is empty.
Validation: None.

Evidence: `src/redux/auth/saga.js`.
Implementation: **Implemented**.
Confidence: High. The menu control that dispatches logout was not clicked in a browser for this document.

### FR-005 — Forgot password and reset

Requirement: `/user/forgot-password` asks Cognito to send a reset code. If the result has `CodeDeliveryDetails`, the app opens `/user/reset-password` and passes `email` on the history location (not the query string). Reset submits `forgotPasswordSubmit(email, code, newPassword)`. The saga treats a falsy return as success and then opens `/user/login`. A truthy return is treated as an error message.

Who: A person who uses the "forgot password" link on the login card. That link target is `/user/forgot-password`.
Trigger: Submit on the forgot-password form, then submit on the reset form.
Inputs: Email, verification code, new password, repeated new password.
Expected behaviour: `watchForgotPassword` and `watchResetPassword`.
Validation: Reset and new-password screens require a verification code. If both password fields are filled and differ, the message is "Please check your new password". No minimum length is set on those screens. `validateNewPassword` reads a values object. It is passed as a Formik `Field` `validate` function, which receives one field value. **Inferred:** the mismatch check does not see both fields. Not executed in a browser.
Error: Missing `CodeDeliveryDetails` surfaces `forgotPasswordStatus.message`.

Evidence: `src/redux/auth/saga.js`, `src/views/user/forgot-password.js`, `src/views/user/reset-password.js`, `src/views/user/new-password.js`, `src/views/user/login.js`.
Implementation: **Implemented** for the Cognito calls. Password-match validation is **Inferred** as not wired to the form values.
Confidence: Medium.

### FR-006 — Confirm code for a new email

Requirement: `/user/confirm-code` calls `Auth.confirmSignUp(email, verificationCode)` and then `Auth.forgotPassword(email)`, then pushes `/user/new-password` with the email on the history location. `/user/new-password` calls `forgotPasswordSubmit` and then pushes `/user/login` without checking the result.

Who: A person opening that URL. No menu item points at it. Login does not link to it.
Trigger: Submit when both fields are non-empty.
Inputs: Email and verification code. The page also reads `location.search` into `params` and does not use it.
Expected behaviour: `src/views/user/confirm-code.js`, `src/views/user/new-password.js`.
Error: Exceptions are logged. The page stays put.

Evidence: those two files.
Implementation: **Implemented**.
Confidence: High for the call sequence. Who is expected to open the page is **Unknown**.

### FR-007 — Register

Requirement: `/user/register` is routed. The register saga calls `auth.createUserWithEmailAndPassword`. The `auth` export is Amplify `Auth` (`src/helpers/Amplify.js`). The login card's Register link points at `/register`, which is not a route. The root switch sends unknown paths to `/error`.

Who: The login card offers Register to "If you are not a member".
Trigger: That link, or a direct open of `/user/register`.
Inputs: Email and password on the register form (Gogo-shaped page).
Expected behaviour: **Inferred** from the method name: Amplify Auth does not implement `createUserWithEmailAndPassword` (that name is the Firebase Auth method). The saga was not executed.
Outputs: **Unknown** at runtime.
Error: A thrown error is stored as `registerUserError`.

Evidence: `src/views/user/index.js`, `src/views/user/login.js` NavLink `` `/register` ``, `src/redux/auth/saga.js`, `src/App.js`.
Implementation: Route **Implemented**. Working registration **Unknown / Requires Confirmation**. The login link target does not match the route.
Confidence: High for the mismatch. Low for runtime success.

### FR-008 — Forgot username support form

Requirement: `src/views/user/forgot-username-password.js` collects name, surname, email, mobile number, and comments. Name, surname, and email are required. Submit waits one second, logs the payload, and alerts "Successfully Submitted Form :)". It does not call Cognito or the Footprint API. The component is not imported by `src/views/user/index.js`.

Who: Nobody, from the route table.
Trigger: None in the router.
Evidence: the file and `src/views/user/index.js`.
Implementation: Page file **Implemented**. Route **not present**. Commit `d275a95` (2020-07-02) says "Added Forgot Username & Password Support Contact page".
Confidence: High.

### FR-009 — Member search

Requirement: `/app/pages/user` redirects to `/app/pages/user/users`. On load the page:

- `GET /footprint/types/13` and builds a type dropdown. The id `13` is a literal. Comment in the function: "From user's Organisation?".
- `GET /footprint/groups`.
- `GET /footprint/roles/0` initially.
- When type, group, and role are all set, `POST /footprint/members` with body `{ union, group, role, search }`.

The table columns are MemberID, FullName, Organisation, Email, Title, MobileNumber, Gender, age, Ethnicity. The first synthetic row comes from `[{}].concat(jsonData)`, so a leading empty object is mapped as well.

Who: A person who passed FR-003.
Trigger: Page load and filter or search changes (the load function closes over the selected values).
Inputs: Dropdown values and search text. Defaults: type, group, and role objects start as `{ name: "All", value: 0 }`. After types load, the selected type becomes `organisationTypes[1]` (the first real row, not "All").
Outputs: Table rows, or an empty table after an error (loading flag cleared, error logged).
Validation: The post runs only when all three selected objects are truthy.
Error: Console log. No notification.

Evidence: `src/views/app/pages/user/user-list.js`, `src/views/app/pages/user/index.js`.
Implementation: **Implemented**.
Confidence: High. The response shape (`response.body` parsed as JSON, while `footprintAPI` uses `response.data`) depends on Amplify's return value. Not executed against the API.

### FR-010 — Add member modal

Requirement: The member list can open `AddNewMemberModal`. Submit calls `handleSubmit` in `user-list.js`, which logs the values and alerts success. It does not post to the API. The dedicated route `/app/pages/user/new` renders the heading `Members.CreateNewUser` and nothing else.

Who: A person on the member list, or opening the Create menu item.
Trigger: Modal submit, or the menu route.
Evidence: `src/views/app/pages/user/user-list.js`, `src/views/app/pages/user/create-user-page.js`.
Implementation: Modal UI **Implemented**. Persistence **not implemented**. Create route is a stub.
Confidence: High.

### FR-011 — Member profile

Requirement: `/app/pages/user/:userID` loads `GET /members/{userID}/verbose` through `footprintAPI` (base `https://dev-api.reboot.footprintapp.net`) and maps fields into personal info, contact info, organisation, settings, and insurance objects. It also `POST`s `/footprint/userpermissions` with `GroupID: global.GroupID`, `ModulePermission: "Members"`, and `personId` from the route.

Tabs:

| Tab | File | Behaviour on this revision |
|---|---|---|
| Home | `contentTabs/home.js` | Renders cards. Age and current organisation come from the user object. Nationality, gender, height, place of birth, weight (uses `user.age`), position, and team are string literals |
| Profile | `contentTabs/profile.js` | Personal, contact, organisation, contract history, apparel, social, bio, transfer history sections, each gated by `canRender` |
| Medical | `contentTabs/medical.js` | Insurance and injuries sections. Health passport status fields in the mapper are literals prefixed with `??` |
| Performance | `contentTabs/performance.js` | Match statistics and activity, plus sanctions and assessments containers |
| Documents | `contentTabs/documents.js` | Text "Documents Tab Content" |
| Settings | `contentTabs/settings.js` | Profile settings (email), access control, account management |

Who: A person who passed FR-003 and opens a member id.
Trigger: Route match.
Inputs: `userID` path segment.
Outputs: Tabbed profile, or a stuck empty state if the GET throws (error logged).
Error: Console log. The effect dependency is `returnUserObject`, which is a new array every render. **Inferred:** the load effect can re-run every render. Not executed.

Evidence: `src/views/app/pages/user/user-detail.js` and the `contentTabs` files.
Implementation: Load and tab shell **Implemented**. Home card values are mixed live and literal. Documents tab is a stub.
Confidence: High.

### FR-012 — Permission flags do not hide cards

Requirement: Profile sections call `canRender(componentID, permissions)` with ids such as `Member_Profile_PersonalInformation_General`, `Member_Medical_Insurance`, `Member_Performance_MatchStatistics`. `canRender` returns `true`. The `VIEW` check is commented out. A comment says "TODO Ensure we check for other types of allowed operations" and "TODO Investigate the API side".

Who: Any person who can open the profile.
Trigger: Render of those sections.
Inputs: Permission rows from FR-011, ignored.
Expected behaviour: Every gated section renders.
Outputs: Full profile body.

Evidence: `src/components/AccessControl/AccessControl.js` and the `canRender(` call sites.
Implementation: **Implemented** bypass. The commented function is **Planned** in the sense that the code still contains it, not in the sense of a written roadmap.
Confidence: High.

### FR-013 — Save profile subsections

Requirement: These posts exist. Bodies are the form values named in each file. General info requires preferred name, full name, surname, title, nationality, country of birth, city of birth, ethnicity, gender, disabled, additional needs, sport safety number, and positive numbers for height and weight (`GeneralForm.js` Yup schema). Dropdown options come from `src/customData/dropdownLookupData.js`, not from the API.

| Action | Method and path |
|---|---|
| General | `POST /footprint/updateusergeneral` |
| Identity | `POST /footprint/updateuseridentity` |
| Other | `POST /footprint/updateuserother` |
| Address | `POST /footprint/updateuseraddress` |
| Next of kin | `POST /footprint/updateusernextofkin` |
| Email | `POST /footprint/updateemail` |

Who: A person editing those cards.
Trigger: Form submit.
Error: `catch` logs. General form still alerts success after the `try/catch`.
Evidence: `src/components/forms/Profile/**`, `src/views/app/pages/user/profile-settings-content.js`.
Implementation: **Implemented** calls. Server acceptance rules are **Unknown**.
Confidence: High for the client calls.

### FR-014 — Account activation

Requirement: Account management shows an activation confirmation only when `signInEmailAddress` is set. Otherwise a modal says an email must be set up in Profile Settings. Confirming activation calls `Auth.signUp` with that email and a fixed password (value omitted here; it is a literal in `account-management-content.js`). On success it posts `/footprint/updateuuid` with `{ uuid: user.userSub, MemberID }` and `/footprint/updatememberactive` with `{ memberId, status: 3 }`. If sign-up throws `UsernameExistsException`, it calls `Auth.forgotPassword` and skips the uuid post, and still posts status `3`. A separate `changeStatus(status)` posts `updatememberactive` with the given status.

`isActive` on the loaded profile is true only when `Status == "Active Member"`.

Who: A person on the member Settings tab.
Trigger: Activation modal "GO".
Inputs: Member id and sign-in email from the loaded profile.
Outputs: Cognito user and two API posts, or a forgot-password email plus one API post.
Error: Logged. The modal still closes (`setShowModal(false)` is outside the `try` blocks' failure paths and runs after they finish).
Validation: Email presence only. No password entry by the operator.

Evidence: `src/views/app/pages/user/account-management-content.js`, status mapping in `user-detail.js`.
Implementation: **Implemented**.
Confidence: High for the client sequence. The meaning of status `3` versus the string "Active Member" is **Unknown / Requires Confirmation**.

### FR-015 — Groups and roles settings

Requirement: `/app/pages/settings` redirects to `/app/pages/settings/groups`. That page loads `GET /footprint/groups`, `GET /footprint/getpermissionmodules/{groupID}`, `POST /footprint/getmoduledetails`, and `GET /footprint/getallcardpermissions`. Saving a permission posts `/footprint/savepermissions` with PRIVATE, VIEW, EDIT, CREATE, DELETE as 0 or 1, plus `id` and `personId: currentUser.username`. Applying to users posts `/footprint/updatepermissions`. A delete call is commented out. A comment says "TODO TEST SAVING OF ITEMS".

Custom permissions for one member post `/footprint/updatecustompermissions` from `UserAccessPermissionsSection.js`.

Who: A person who opens Settings.
Trigger: Page load and save actions.
Evidence: `src/views/app/pages/settings/groupsAndRoles.js`, `src/components/sections/UserAccessPermissionsSection.js`.
Implementation: **Implemented** calls. Whether save persists is **Unknown** (the TODO is still in the file).
Confidence: Medium.

### FR-016 — Other settings pages

Requirement: Countries, venues, organisations, sport codes, qualifications, achievements, library toolbox, surveys, notifications, email templates, and support are routes. Each renders its own name as text and does not call the API.

Who: A person using the Settings submenu.
Evidence: `src/views/app/pages/settings/*.js` other than `groupsAndRoles.js`.
Implementation: Routes **Implemented**. Behaviour beyond the label is absent.
Confidence: High.

### FR-017 — Squads

Requirement: The menu opens `/app/pages/squad`, which redirects to `/app/pages/squad/squads`. The list is five hard-coded national teams (Argentina, Australia, England, Italy, South Africa), each "Senior: International" and "Active", dated `11/05/2020`. Filters (year, squad type, sports code, gender, age group) use `dropdownLookupData` and `alert` the selection. They do not filter the array. Create (`/new`) , reports, and pivot report are separate routes. Squad detail uses a fixed "Blue Bulls" / "Curie Cup" object. `contentTabs/home.js` and `contentTabs/planner.js` contain "TODO - Call API for all this data".

Who: A person using the Squads menu.
Evidence: `src/views/app/pages/squad/squad-list.js`, `squad-detail.js`, `contentTabs/home.js`, `contentTabs/planner.js`.
Implementation: UI **Implemented**. Live squad data **not implemented** on this revision.
Confidence: High.

### FR-018 — Tournaments and fixtures

Requirement: `/app/pages/tournament` redirects to `/tournaments`. The list is four hard-coded competitions (Castle Lager Incoming Tour, Guiness Pro 14, Vodacom Super Hero Sunday, HSBC Sevens Cape Town) with statuses In Progress, Completed, or Upcoming. `servicePath + "/cakes/paging"` is assigned to `apiUrl` and is the Gogo demo host `https://api.coloredstrategies.com`. Create, manage fixtures, reports, pivot report, `/:tournamentID`, and `/fixture/:fixtureID` are routed. Manage-fixtures is not commented out here (the squad copy of that route is commented out).

Who: A person using the Tournaments menu.
Evidence: `src/views/app/pages/tournament/tournament-list.js`, `src/views/app/pages/tournament/index.js`.
Implementation: Routes and static list **Implemented**. A tournament API is **not** called by the list file.
Confidence: High for the list. Fixture detail contents were not line-reviewed beyond the route.

### FR-019 — Organisations

Requirement: `/app/pages/organisation` redirects to `/dashboard`. The dashboard mounts Gogo demo cards (cakes, best sellers, tickets, logs) and, in `componentDidMount`, `GET`s `https://afsxv57muc.execute-api.eu-west-1.amazonaws.com/dev/footprint` with a `URLSearchParams` value `id=220` passed as the axios config argument (not as `params`). The response is stored on `dataSelection` and the render path inspected does not read it. Manage, reports, venues, surveys, forms, and plan-budget render short placeholder components. Organisation list uses in-file options: types Developer, Federation, Union, Club, and names Evolve AV, SA Rugby, Blue Bulls. That list route is `/organisation-list` and is not in `src/constants/menu.js`.

Who: A person using the Organisations menu.
Evidence: `src/views/app/pages/organisation/*`, `src/constants/menu.js`.
Implementation: Dashboard shell and one unused GET **Implemented**. The rest of the section is placeholder or static.
Confidence: High.

### FR-020 — Insight and medical landing pages

Requirement: `/app/pages/insight` renders a heading "Insight". An alert helper `showGreeting` exists and is not referenced from `render`. `/app/pages/medical` renders "Medical Page". Member-level medical content is FR-011, not this route.

Who: A person using those menu items.
Evidence: `src/views/app/pages/insight/insight.js`, `src/views/app/pages/medical/medical.js`.
Implementation: **Implemented** as placeholders.
Confidence: High.

### FR-021 — Transfers, reports, pivot

Requirement: Member transfers, member reports, and member pivot report are menu routes. Transfers and reports render a heading (`Members.Transfers`, `Members.Reports`). The pivot page is the Gogo pivot component fed by local data files where the page imports them. Squad and tournament report routes follow the same pattern of a page file per menu item.

Who: A person using those submenu links.
Evidence: `src/views/app/pages/user/transfers-page.js`, `reports-page.js`, `pivot-report.js`, menu entries in `src/constants/menu.js`.
Implementation: Routes **Implemented**. Domain reports are not backed by the Footprint API in the files read.
Confidence: Medium. Pivot data source was not fully traced.

### FR-022 — Gogo UI kit remains reachable

Requirement: The menu still includes UI forms, UI components, and component demos (charts, pivot table, editable data table, and a link labelled full calendar that targets `/app/applications/formBuilderDemo`). `/app` itself redirects to `/app/dashboards`, which is the template dashboard, not a Footprint home.

Who: Any person who passed FR-003.
Evidence: `src/constants/menu.js`, `src/views/app/index.js`.
Implementation: **Implemented**.
Confidence: High.

### FR-023 — Logged-in identity in the top bar

Requirement: After authentication, the top bar loads `Auth.currentAuthenticatedUser()` and `GET /members/{attributes['custom:memberid']}` via `footprintAPI`. It displays `FullName` and `Email` from `data[0]` and sets `global.GroupID` from `GroupID`. If the attribute or the call fails, the error is logged and the default `global.GroupID` stays `2`.

Who: A person with a Cognito session that includes `custom:memberid`.
Trigger: `TopNav.componentDidMount`.
Evidence: `src/containers/navs/Topnav.js`.
Implementation: **Implemented**.
Confidence: High. Whether every pool user has `custom:memberid` is **Unknown / Requires Confirmation**.

## Important behaviour that is not a written requirement

- Two Amplify.configure blocks target different API endpoints. `App.js` loads `src/helpers/Amplify.js` (`https://dev.reboot.footprintapp.net/api`). The user-route module, once loaded, replaces that with `https://dev-api.reboot.footprintapp.net` and does not append `/api`. `footprintAPI` uses the second host for axios. A refresh on `/app` that does not import the user module leaves Amplify on the first host. **Implemented**. Which one is correct is **Unknown / Requires Confirmation**.
- `footprintAPI` does not attach an Authorization header. The bearer-token helper is commented out, and the sample key in that comment names a person's email. **Implemented** as no header.
- Lookup lists (countries, cities, ethnic groups, genders, positions) are source constants, including values that mix countries and cities (Windhoek and Johannesburg appear under `countries`). **Implemented**. Whether they match the API's codes is **Unknown**.

## Planned, from comments only

Comments mark intended work. They are not a backlog document.

- Enforce `VIEW` (and other verbs) inside `canRender`.
- Call an API for squad home and squad planner data.
- Test saving group permissions.
- Delete-permission call, currently commented out.
- Load the signed-in user's organisation id instead of the literal `13`.

## Unknown / requires confirmation

- The product owner, the sport, and whether "Footprint Reboot" replaced an earlier Footprint app.
- Production host, and whether `dev-api.reboot.footprintapp.net` or `dev.reboot.footprintapp.net` is current.
- Cognito password policy, required custom attributes, and whether self-registration is enabled in the pool.
- Meaning of member status `3` and of the string "Active Member".
- Whether static squads, tournaments, and the organisation names (SA Rugby, Blue Bulls) are demo content or the intended catalogue.
- Relationship to other Silicon Ark Footprint directories.
- Contents of `PowerPoint/Blindside Software Hierarchy.pptx`.
