Fibretrace Monet docs/Knowledge base/Persona: additional roles

Persona 06 — Additional roles the QC script omits

The QC script tests five personas (FT Admin, Program Owner, Tier 4 Producer, Tier 1 Manufacturer, Tier 0 Retailer). Role/permission handling in both codebases shows four more actors plus an access-control axis. Confidence markers and citation shorthand per README.md.

6a. Auditor — the scan-only field role

company_users.role = "auditor" is a real role with real enforcement: the dashboard force-signs-out any auditor and bounces them to /login — they must never see the brand/producer dashboard. VERIFIED (L:src/pages/Home.tsx:128-133). The team-invite flow defines their permission set explicitly: “Perform verifications” enabled, everything else (manage verifications, facilities, team, billing) disabled. VERIFIED (L:src/components/InviteTeamFlow.tsx:24-38). Their working surface is the SAT PWA, which gates purely on authentication plus GPS permission and gives every authenticated user the identical scan/audit experience — SAT has no persona system at all. VERIFIED (apps/sat ProtectedRoute; no role branches found in apps/sat/src). Canvas likewise models auditors as a company relation (/company/auditors). VERIFIED (canvas companyApi.ts).

Who they are in the real world: the person on the warehouse floor with the Bluetooth scanner. Their good day is entirely physical: pair, scan, pigment found, geolocation accepted, audit synced (or queued offline and synced later). Failure modes are SAT’s, not the dashboard’s: tau mismatch, blocked WiFi, empty offline FTID cache. VERIFIED (memory reference_sat_scan_failure_modes).

6b. The neutral participant (“scanner” persona) — Tier 2/3 and any unregistered company

The old persona hook’s explicit fallback: a company that is neither producer nor brand is a “scanner”. VERIFIED (L:src/hooks/usePersona.ts:39,47). This is the digital home of Tier 2 mills and Tier 3 spinners — companies that receive and ship marked fibre, scan inbound/outbound, maintain partnerships and share sessions, but hold no reservations and make no claims. Their scans build the chain of custody and the supply-chain map; per Malcolm’s retirement rule their scans are never retired by downstream claims, because one mill serves many customers. STATED (BL:wt2:28-29; flow-explained rule 6). The demo’s ACME TIER2 resolves to the manufacturer layout only because seed data gives it incoming POs — persona is data, not tier. VERIFIED observation (BL:gui-walkthrough README case 9; usePersonaContext isManufacturer definition).

First-login state: the generic Home with the SetupGuide/empty sandbox branch (the “Jamie’s Empty Tier 0” dev persona exercises exactly this). VERIFIED (L:src/pages/Home.tsx isEmptySandbox branch; /empty dev route in App.tsx).

Implementation state: this persona’s surfaces (verifications, collections, facilities, scanners, partners, settings) are the best-wired part of monet, since they avoid the PO/claims domain entirely. VERIFIED (M apiAdapter wired mappers list).

6c. The public verifier — customs officer, buyer, consumer

Unauthenticated actors with real routes:

Route What they see
/c/:token (and /c/:token/:claimRef) The public claim page a QR certificate resolves to: programme, tonnage, date, issuer, status — with a “Revoked” banner if the claim was revoked and a “not publicly visible” state when the share token is disabled. VERIFIED (L:src/App.tsx:148-149; PublicClaim.tsx:69-96)
/v/:token Public verification share page. VERIFIED route (L:src/App.tsx)
/verify/:guid Collection preview by blockchain GUID. VERIFIED route (L:src/App.tsx; monet has this wired as CollectionPreview)
/api/v1/claims/:claimId/status The “webhook”: actually a client-side React route rendering a JSON preview — and it takes a bare claimId with NO token or auth check at all. No outbound webhook push exists anywhere. VERIFIED (memory reference_public_claim_webhook; ClaimWebhookPreview; ReviewClaimProposalModal copy “External webhooks stay off until you turn them on in Connections”)
/directory, /calculator Public company directory; public claim calculator. VERIFIED routes

Access is gated by public_verification_tokens rows (token UNIQUE; must reference at least one of session/verification/claim; seeded for trade/sustainability/procurement packs on claim confirmation; per-token enable toggle). VERIFIED (SQL public_verification_tokens; usePurchaseOrders.ts:722-732). The glaring exception is the tokenless webhook route above — a security gap to fix before production. VERIFIED.

Real-backend reality: Fibretrace REST has no unauthenticated read surface at all; the only public-ish endpoints are canvas’s /process-preview and the separate legacy b2c app. Every public page in monet is therefore a stub until BE ships a public token-resolution endpoint. VERIFIED (port-plan.md unit 20 mismatch; canvas agent findings).

6d. Team-role axis (applies inside every company persona)

company_users.role values in live use: owner, admin, auditor, pending (admin-created accounts default “user”). VERIFIED (L:src/pages/Team.tsx:52,112,178; AdminUsers.tsx:68). owner/admin gate: company profile edits, billing, partner accept (real backend returns 403 for non-admins on POST /company and partner accept). VERIFIED (L settings pages isAdmin checks; monet-dashboard-api-v1.md:326,474). The signup-approval bootstrap makes the requester the company’s first admin. VERIFIED (AdminSignupRequests.tsx:64-121). The real backend models this as role: string plus is_company_admin — no enum — and monet’s spec flattens company types[] (canvas array) into a single company_type string, a real divergence to watch. VERIFIED (canvas types.ts:16-36; monet-dashboard-api-v1.md:209-212).

6e. Demo/QC personas (test infrastructure, not product)

The demo modal switches among 7 hardcoded seed users: Tier 4 GIN (SUNDOWN), Tier 4 rPET, Tier 1 (ACME Apparel), Tier 2 (ACME TIER2), Tier 0 (WALMART), Program Office, and a dev-gated Empty Tier 0 (plus an empty Manufacturer v2 in the matrix’s enumeration). switchUser is a pure client-side context swap — no re-login, cannot see newly created companies. Admin Impersonate covers arbitrary users. VERIFIED (L:src/components/DemoNavBar.tsx:15-52; AdminUsers.tsx:83-86; BL:persona-case-matrix.md). The rPET seed is a hybrid (producer sidebar, owner home) — intended or seed-data accident is an open question for Malcolm. STATED (BL:ux-findings-for-malcolm.md).

Login itself in the Lovable MVP is demo-grade: email lookup with any non-empty password, 2FA code displayed on the login screen, invite/approval emails simulated into localStorage — QC pass criteria that mention “receives an email” must accept the in-app log. VERIFIED (L:src/pages/Login.tsx:102-151; L:src/lib/signup.ts:67-70).

Why the persona list stops here

Searched for and ruled out: no data-partner persona (API keys are a settings card, module-gated, not a persona), no distinct QC role, no Tier 3-specific behaviour anywhere, no farm/Tier 5 concept, and no Insights-module persona (the module does not exist). programme_participants.role allows producer/participant/manufacturer values VERIFIED (SQL CHECK, 20260622100114:10) but only participant and manufacturer are consumed by persona logic; the backend spec adds a verifier role value monet never uses VERIFIED (BE-ASK.md:384 vs usePersonaContext) — flagging the mismatch, not a persona.