# P2-onboarding-profile — findings

| | |
| --- | --- |
| Reviewer | Raheem takes the decisions; Zayed records them and locks |
| Reviewed | — |
| Status | draft |
| Supersedes | — |
| Superseded by | — |

**This prototype is a draft and its outcome column is empty on purpose.** Every
decision below offers at least two defensible answers, both of them actually
built and both reachable from the bar under the prototype header. The choice
follows the reader from screen to screen and is written into the address, so a
screenshot is reproducible by pasting its URL back.

Read this with the prototype open. Nothing here is settled until the reviewer
settles it.

## Outcome per decision

"Outcome" is the answer chosen, in a sentence. "Evidence" is the screenshot the
answer rests on. A decision with no evidence is not settled.

| Id | Decision | Options built | Outcome | Evidence | Writes back to |
| --- | --- | --- | --- | --- | --- |
| **D5** | **Mobile navigation at 390** — deferred to this prototype by the S1 review and settled once for all of Stage 2. A grouped list — nineteen entries across six groups, of which no one account holds more than ten — has to reach a 390px screen without becoming an ungrouped scroller. | a) **a drawer from the header** carrying the rail's grouped list unchanged — `mobile=drawer` b) **a fixed bottom bar of four**, with the same drawer behind "more" — `mobile=bar` | | `screenshots/profile--default--ar--mobile.png`, `screenshots/profile--default--ar--mobile-bar.png`, `screenshots/profile--default--ar--mobile-drawer-open.png`, `screenshots/notifications--default--ar--mobile-bar.png`, `screenshots/notifications--default--ar--mobile-admin-bar.png` | (c) a convention in the web repository |
| D1 | Is the registry-driven profile form one long page with the groups as sections, or one step per registry group with a progress rail? And does **editing** later take the same shape as registering? | a) one step per group with a progress rail — `form=steps` b) one long page — `form=long` | | `screenshots/form--default--ar--steps.png`, `screenshots/form--default--ar--long.png`, `screenshots/form--partial--ar.png`, `screenshots/profile--default--ar.png` | (a) the onboarding epic, and (c) a convention |
| D2 | What decides the control a registry attribute renders as — its data type alone, or its data type **and** the number of options the catalogue holds? | a) the count decides too: a catalogue over a threshold becomes a searchable field and a multi-select becomes chips — `control=rich` b) the data type alone decides, and a catalogue of any size is a native select — `control=plain` | | `screenshots/form--default--ar--rich.png`, `screenshots/form--default--ar--plain.png`, `screenshots/form--default--en--rich.png` | (a) the onboarding epic — **it changes the endpoint's payload** |
| D3 | Where is the claim search offered, so that nobody creates a duplicate of a profile the platform already holds? And does a match **stop** the flow or merely warn beside it? | a) a step inside the flow, before anything is created — `claim=inline` b) a second path from the first screen — `claim=separate` | | `screenshots/register--default--ar--inline.png`, `screenshots/register--default--ar--separate.png`, `screenshots/register--partial--ar.png`, `screenshots/claim--default--ar--inline.png`, `screenshots/claim--empty--ar.png` | (a) the claim epic |
| D4 | What does an agent's own area open on — her clients, or the work addressed to her, given that the landing already shows her the work? | a) clients first, the work owed as a band above — `dash=clients` b) the inbox first, clients as a panel beside it — `dash=inbox` | | `screenshots/agent--default--ar--clients.png`, `screenshots/agent--default--ar--inbox.png`, `screenshots/agent--empty--ar.png` | (a) the mandates epic |
| D6 | An expired session is neither a refused route nor a failed request. Is it a refusal **in place**, with the half-typed form still underneath, or a **route of its own** with a return address? | a) in place, over the screen, the work intact — `session=inline` b) a route of its own — `session=route` | | `screenshots/profile--error--ar--session-inline.png`, `screenshots/profile--error--ar--session-route.png`, `screenshots/auth--no-permission--ar--route.png` | (c) a rule for the code repository |
| D7 | Is "my account" one page with sections, or an area with a tab strip like the club? Must it match the club's answer, or may the two differ? | a) one page, sections in order, one save — `settings=sections` b) a tab strip, one tab per concern, a save per tab — `settings=tabs` | | `screenshots/account--default--ar--sections.png`, `screenshots/account--default--ar--tabs.png`, `screenshots/account--no-permission--ar.png` | (c) a convention |
| D8 | Is the notifications inbox grouped by what happened, or one flat list newest-first with a filter? And **is a notification an action, or a record of something that happened with a link to where the action lives?** | a) grouped by kind, the action on the row — `inbox=grouped` b) one flat list with a filter — `inbox=flat` | | `screenshots/notifications--default--ar--grouped.png`, `screenshots/notifications--default--ar--flat.png`, `screenshots/notifications--default--ar--admin.png`, `screenshots/notifications--empty--ar.png` | (b) a note on the notification-centre epic |

### Secondary questions the same screens answer

Not decisions of their own, but each has a write-back destination waiting, so
none of them should close without an answer.

| Question | Where it is visible | Writes back to |
| --- | --- | --- |
| Sign-up, verification and the registry form are in the **public shell** — no rail, no bell, no account menu. Is that right, or does a half-registered account already belong inside the application shell? | `screenshots/register--default--ar--inline.png` against `screenshots/profile--default--ar.png` | (c) a convention |
| A sign-up error and a sign-in error both refuse to say whether an address has an account. Is that non-disclosure rule worth the confusion it costs a person who simply mistyped? | `screenshots/register--error--ar.png`, `screenshots/auth--error--ar.png` | (c) a rule |
| A value somebody else owns — the club, the contract, the verification tier, the mandate — keeps its place and names its owner, and is **not** the refusal pattern. Does that hold when four of them sit together in one panel? | `screenshots/profile--default--ar.png` | (b) a note on the profile-edit epic |
| The one refusal a professional meets about his own availability is an **injury the club recorded**. Is the club's injury record allowed to override the market status the person owns? | `screenshots/profile--no-permission--ar.png` | (a) the injury-status epic |
| A mandate is confirmed by the represented person and by nobody else. Does the agent's screen say so clearly enough that she does not read the refusal as a fault of her own? | `screenshots/mandate--no-permission--ar.png` | (b) a note on the mandates epic |
| Two verification keys, and most accounts sit with one verified and one not. Should a profile with an unverified phone be invisible in the market, or visible and marked? | `screenshots/verify--partial--ar.png`, `screenshots/done--partial--ar.png` | (a) the onboarding epic |
| In-app notifications cannot be switched off and email can. Is the in-app inbox really a record that must not be silenced? | `screenshots/account--default--ar--sections.png` | (b) a note on the notification-centre epic |
| The inbox is **the record of what happened to one account**, so it differs by account: a platform administrator is a party to no approach and holds no mandate, and neither ever appears in theirs. Is the unread count therefore per account, and does one badge count a club's watchlist alarms and a person's mandate events together? | `screenshots/notifications--default--ar--admin.png` against `screenshots/notifications--default--ar--grouped.png` | (b) a note on the notification-centre epic |

### What P2 proposes on D5, and why

The prototype builds both and **proposes the drawer**. The reviewer is free to
take the bar; the argument for the drawer is written here so that taking the bar
is a decision rather than an omission.

1. **A bottom bar and a form's primary action compete for the same strip.** P2's
   screens are forms, and a form's save is sticky at the foot. At 390 the two sit
   on top of each other, and the one that loses is the one the screen exists for.
   `screenshots/profile--default--ar--mobile-bar.png` against
   `screenshots/profile--default--ar--mobile.png`.
2. **The bar's obvious four mostly restate the chrome.** Three of the four are
   home and the two entries that already carry badges. The badge can ride on the
   drawer's menu button instead, which says the same thing in one control.
3. **The four are not the same four for every account.** A platform
   administrator holds no الطلبات at all — S1 settled that — so the bar either
   differs per role, which is the role switcher S1 rejected arriving by the back
   door, or it shows an entry that account does not hold, which S1 also rejected.
   The prototype renders the administrator's bar with a different second entry,
   so the defect is on screen rather than in an argument:
   `screenshots/notifications--default--ar--mobile-admin-bar.png`.
4. **The drawer is the rail, in another box.** Same six groups, same labels, same
   entries this account holds, same two badges, same absent-not-disabled rule. One list, one
   place, one rule, and nothing new to keep in step.

What the drawer costs, said plainly: **one extra tap on every navigation**, on
every screen, for every user, forever. That is the trade the reviewer is being
asked to accept.

---

# Write-back

Three destinations, one section each. Everything below is copy-paste ready and
is filled in **after** the review, not before.

**No requirement id from any parked requirement document may appear anywhere
below.** Restate it in the project's own words or drop it.

## The exact story format

```
- **As a <actor>**, I <do>, so that <outcome>.
  - Accept: <criteria>.
```

Two lines, the second indented by two spaces. Stories are **append-only**: add to
the end of that epic's `## Stories` block and never reorder, renumber or reword
a story already there, because `story_notes` points at stories by position.

## (a) New stories — appended

Destination epics, by decision: D1, D2 and the two-key verification question to
the **registry-driven self-onboarding** epic; D3 to the **claim a pre-created
profile** epic; D4 and the mandate questions to the **agent representation
mandates** epic; the injury-override question to the **injury status** epic; the
profile-edit questions to the **edit my profile, availability and media** epic.

Written after the review.

> **One of these is urgent and is flagged now rather than after the lock.** If
> D2 is answered "the option count decides too", the registry spec has to return
> an option count per catalogue attribute, and that changes the payload of the
> onboarding endpoint. The endpoint is in Track A and is not yet built. The
> decision has to reach that epic **before** it is built, not after.

## (b) Notes on existing stories

Keyed by the story's 1-based position in that epic's `## Stories` block. Merge
into the epic's `story_notes` object; do not replace it.

Written after the review.

## (c) Rules and conventions for the code repository

These are the ones that belong to no epic, and they go where S1's went — the
"Conventions settled by the S1 whole-surface prototype" neighbourhood of the web
repository's `CLAUDE.md`, under a heading of their own.

| Glob | Title | Note |
| --- | --- | --- |
| — | mobile navigation | **D5's answer, verbatim.** P3 to P6 inherit it; no later prototype re-asks it. |
| — | session expiry | **D6's answer.** Whether the one refusal pattern stretches to a case where nothing was refused. |
| — | the account area's shape | **D7's answer**, and whether it must match the club area's tab strip. |
| — | the public shell's boundary | Where sign-up, verification and sign-in sit, and at what point an account enters the application shell. |

---

## Rejected options

Filled in after the review. What was tried and abandoned, and why — the part
that stops the same argument being had again in three months.

| Option | Why it was rejected | Evidence |
| --- | --- | --- |

## Three screens folded in without a prototyping ticket

Each has a build ticket and no prototyping ticket, and each was built here with a
decision of its own rather than being built without ever being drawn. **They need
tickets writing against what is decided here.**

| Screen | File | The decision it carries | The build epic that owns it |
| --- | --- | --- | --- |
| The auth surface — sign-in, password reset, session expiry | `auth.html` | **D6** | sign-in and account security |
| Account and security settings | `account.html` | **D7** | account and security settings |
| The notifications inbox | `notifications.html` | **D8** | notifications inbox and unread badge |

## Carried forward as stories, not as reasons to hold the lock

1. **Mandate confirmation** — built here (`mandate.html`), because the S1 review
   found it missing and because the mandate routes every approach that will ever
   reach a professional. It belongs to the mandates epic.
2. **My profile and my account** — S1 built one screen called "my profile and
   account"; P2 splits it into the sporting profile (`profile.html`) and the
   account (`account.html`), because one of them is registry data a club reads
   and the other is a password. Whether the navigation carries one entry or two
   is a question for the reviewer, and the prototype renders one entry pointing
   at the account with the profile linked from it.

## Not settled

Named here so a half-answered decision is a finding rather than a silence.

- **A person may hold more than one profile type.** Sign-up asks for one. S1
  settled that there is no role switcher, so a second identity has to be
  *added*, not switched to — and nothing in P2 draws how. It needs a screen in
  whichever prototype owns the account's phase, which today is this one.
- **What raises a verification tier, and who decides.** The tier is shown on
  three screens here and explained on none, because the answer lives in the
  claims queue and therefore in P3.
- **An expired session during a media upload** loses a file rather than a form.
  Neither D6 variant covers it, and the `partial` state of `profile.html` shows
  a failed upload for a different reason, so the two are not the same case.
- **The registry's option count.** See the flag under (a): D2 cannot be
  implemented either way until the registry says whether it returns one.
- **Whether the claim search runs on more than a name and a date of birth.** Two
  people can share both. The screen searches on those two and says so; what a
  second factor would be — a federation number, a club — is not settled.
- **The season correction.** S1's landing reads the current season as 2025/26,
  ending 30 June 2026, which had already passed on S1's own review date. Stage 2
  reads it as **2026/27, 1 August 2026 to 30 June 2027**. S1 is locked and cannot
  be repaired; the correction is recorded in `../FIXTURES.md` and named here so
  it is not discovered later as a contradiction.

## Not built

Anything the timebox did not reach, so a half-built prototype says which half is
missing.

- **Email as a rendered artefact.** The inbox is in-app; what an email looks like
  is a template question and nothing in D8 turns on it.
- **The sign-up of a club administrator who registers a new club.** `role.html`
  offers "إداري" as a profile type and says how it is reached, and the club's own
  registration form is P4's.
