Skip to main content

PRD: Pre-Onboarding E2E + Multi-Role Verification (Client Portal)

Status: Draft — Awaiting Approval Version: 1.0 Author: Product Manager (upsquad-product-manager[bot]) Date: 2026-04-22 Repo: upsquad-ai/upsquad-core (cross-cuts upsquad-ai/upsquad-client) Portal: client (app.upsquad.ai) — admin portal explicitly OUT of scope Labels: prd, awaiting-approval, portal:client, qa-e2e


1. Purpose

UpsQuad's own pilot onboarding — where UpsQuad itself becomes the first real tenant — is imminent. Over the past four days, the platform has shipped Dashboard Data Integration (PRD #824), dev-bypass removal (client#110), mock-import CI gate (client#116), BYOA governance (core#827), agent lifecycle governance (core#826), Wave K.2.3 (core#917), and six UX bug fixes (client#117–#122). The platform is technically functional end-to-end, but it has never been exercised as a real user from sign-up through daily operation.

This PRD gates pilot cutover on behavioral verification: every persona, on every surface, doing the real flows, with the real data. It complements (it does not replace) the structural criticism in /tmp/ux-audit-client-portal.md.

1.1 Success Metrics

  • Zero P0 bugs open at sign-off.
  • ≤ 3 P1 bugs open, each with a documented, product-acceptable workaround.
  • All personas (Owner / Director / Lead / Member / Agent) complete their canonical happy-path flows without hitting developer-surfaced artifacts (UUIDs, enum slugs, RPC names, TODO comments).
  • All visibility boundaries verified — no persona sees data or controls above their clearance.
  • All governance enforcement points verified — denied actions are actually denied, approved actions are actually executed, every action is audited.
  • Top 15 flows captured as Playwright regression guards after the manual pass.

1.2 Non-Goals

  • Admin portal verification (only ~5% built; admin#2 PRD is gated on this PRD passing).
  • Paid/billing capture — PRD #552 (Pricing & Packaging) is explicitly out. Founder confirmation 2026-04-21: "paid MVP enabled after initial UpsQuad onboarding."
  • Agent lifecycle upgrade flow (PRD #550) — in-scope for correctness of what exists, not of what is not yet shipped.
  • Advanced UX polish, redesigns, or large IA restructures — tracked by the UX audit and by PRD #553 (Dashboard Intelligence) and #573 (Quad). This PRD does not block on those.
  • Performance / load / stress testing — separate effort (see PRD #615 Sandbox Benchmark).
  • Security penetration testing — separate effort.
  • Accessibility full WCAG AA conformance — this PRD covers only basics (keyboard nav, labeled controls, no colour-only state).

2. Scope

2.1 In Scope

  • Every src/app/(portal)/**/page.tsx surface in upsquad-client.
  • The sidebar and top-bar controls.
  • Clerk sign-up → webhook → MemberService sync.
  • Org creation and first-admin promotion.
  • Agent deploy → LLM call → audit event.
  • BYOA tool config, governance denial, budget cap enforcement.
  • Approval request → approve → execute path, plus denial path.
  • Session durability across page reload.
  • Real-time badge and notification surfacing.
  • Top-10 pages on a 375 px-wide viewport.
  • Keyboard-only navigation on the top-5 pages.

2.2 Out of Scope

  • Everything in §1.2 Non-Goals.
  • Webhook endpoints exposed to third-party SCM platforms (separate PRD).
  • Multi-tenant billing reconciliation (PRD #552).
  • SCIM provisioning beyond smoke-test (PRD #549 / #550 scope).

3. Personas Matrix

Fixtures live in testdata/e2e/acme-corp.json (QA to create). Tenant is acme-corp-test — explicitly not upsquad-ai itself, so the real tenant onboarding starts clean.

3.1 Org Hierarchy (Fixture Tenant)

Acme Corp (tenant)
└── Engineering (pillar) ── Director: Dana ── Owner: Oscar
├── Platform Team ── Lead: Leo ── Members: Mia, Max
└── Product Team ── Lead: Lila ── Members: Mel, Mark
└── Operations (pillar) ── Director: Dina
├── Finance Team ── Lead: Lee ── Members: Meg, Matt
└── HR Team ── Lead: Lars ── Members: Min, Mo
└── Go-to-Market (pillar) ── Director: Drew
├── Marketing Team ── Lead: Lana ── Members: Moe, May
└── Sales Team ── Lead: Lyle ── Members: Mira, Miles

Plus three agents: copilot-engineering, copilot-finance, copilot-marketing, each deployed into its respective pillar's Platform / Finance / Marketing team.

3.2 Personas

IDNameClearanceStarting StateMust Succeed AtMust Be Denied
fx-oscar-ownerOscarL5 AdminFirst user, creates orgFull sign-up flow, org bootstrap, first admin promotion, create first team, deploy first agent, configure first guardrail, approve any request, view audit across org, manage API keys, access Billing + SettingsNothing (ceiling persona)
fx-dana-directorDanaL4 PrivilegedInvited by Oscar, acceptsCreate sub-teams in Engineering pillar, approve Lead deploy requests, configure team-level tool budgets, view audit for Engineering pillar, manage roles within pillarSee / edit Operations or GTM; platform-wide guardrails; platform metrics; org-wide billing edits
fx-leo-leadLeoL3 SensitiveInvited by Dana, acceptsDeploy agent to Platform Team, set Platform Team budget cap, review approvals addressed to Platform Team, view audit for Platform Team, create API key for own scopeSee / act on other teams; view org-wide budget; create another Lead; configure platform guardrails
fx-mia-memberMiaL1 StandardInvited by Leo, acceptsSign in, see own activity feed, chat with assigned copilot, see own submitted approvals, request an approvalDeploy or edit agents; change budgets; create keys; view other members' activity; view billing or admin sections
fx-copilot-eng-agentcopilot-engineeringL3 (bot)Deployed by LeoCall whitelisted tools within Platform Team budget, submit approval requests, write to its own team's audit, respond in Quad chatCall out-of-scope tools, exceed budget cap without approval, cross-team write, impersonate humans

Canonical Clerk user IDs are assigned at fixture seeding time and recorded in testdata/e2e/acme-corp.json alongside the org ID, team IDs, and role assignments.

3.3 Acceptance Criteria (per persona)

Each persona gets a Persona Checklist — a markdown checklist file under tests/e2e/personas/<id>.md enumerating every surface × allowed-action and every surface × denied-action. QA completes the checklist per persona per surface. Sign-off is gated on 100% completion.


4. Function Inventory (by sidebar section)

Each row: Surface → Test Case → Expected State → Visibility Matrix. The matrix cells mean:

  • RW = persona sees and can edit
  • R = persona sees (read-only)
  • = persona does not see the control / page at all
  • D = persona sees a "denied" or "insufficient clearance" state (with a friendly message, not a stack trace)

4.1 Workspace

#SurfaceTest CaseExpected StateOscar (L5)Dana (L4)Leo (L3)Mia (L1)
W1/dashboard — KPI barLoad pageAll 4 KPI tiles render with real data from MemberService + analyticsRWR (pillar-scoped)R (team-scoped)R (own activity only)
W2/dashboard — Activity feedPaginate + filterOnly events visible to the persona's scopeRW full orgR pillarR teamR own
W3/dashboard — Cost forecast widgetLoad30-day forecast matches /billing/usageRWR
W4/dashboard — AlertsTrigger a fake alert via fixtureAlert surfaces in badge + dashboardRWR relevantR relevant
W5/dashboard — Workflows panelList active workflowsOnly in-scope workflows shownRWR pillarR team
W6/quadSend message "hello"Response streams back, session persists across reloadRWRWRWRW
W7/quad — Proactive conflict surfacingTrigger a fixture conflictPinned proactive message appears in QuadRWRW (if in scope)RW (if in scope)
W8/agents — listLoadList shows only in-scope agentsRW allR pillarR teamR assigned
W9/agents/deployWalk deploy wizard for Platform TeamWizard completes; agent appears in list; audit event recordedRWRW (pillar)RW (team)D
W10/agents/[agent_id] — detailLoadConfig, logs, metrics visible per scopeRWR pillarR teamR assigned
W11/agents/[agent_id] — chatSend messageResponse; transcript savedRWRWRWRW (assigned only)
W12/workflowsList and openOnly in-scope workflowsRWR pillarR team
W13/approvals — listLoadOnly requests in persona's approval scopeRW allRW pillarRW teamR (own submitted)
W14/approvals — approveApprove a pending requestRequest moves to approved; originating action executes; audit eventRWRW (pillar)RW (team)D
W15/approvals — denyDeny a pending requestRequest denied; originating action rejected; audit eventRWRW (pillar)RW (team)D
W16/approvals — diff viewOpen diff for a config-change approvalDiff renders legibly (not raw JSON)RWRWRWD

4.2 Governance

#SurfaceTest CaseExpectedOscarDanaLeoMia
G1/audit — listLoad + filter by persona, action, dateEvents scoped; filters workRW allR pillarR teamR own
G2/audit — exportClick exportCSV downloads; contents match current filterRWRWRWD
G3/keys — listLoadKeys scopedRW allR pillarR team (own)
G4/keys — createCreate a key scoped to Platform TeamKey created; secret shown once; audit eventRWRW pillarRW teamD
G5/keys — rotateRotate keyOld key invalidated; new shown onceRWRW pillarRW teamD

4.3 Teams

#SurfaceTest CaseExpectedOscarDanaLeoMia
T1/teams — directoryLoadTeams scopedRWR pillarR teamR assigned
T2/teams/[id] — detail, Tools tabList configured toolsOnly team-scoped toolsRWRW pillarRW teamR
T3/teams/[id] — Budget tabSet monthly budget capCap saved; audit event; over-budget tool calls now deniedRWRW pillarRW teamD
T4/teams/[id] — Members tabAdd / remove memberMember list updates; audit eventRWRW pillarRW teamD
T5/teams/structure — org chartLoadTree renders; persona's own node highlightedRWRW pillarR teamR own

4.4 Billing

#SurfaceTest CaseExpectedOscarDanaLeoMia
B1/billing — subscription overviewLoadCurrent plan + next invoice surface (display-only; paid MVP is out of scope)RW
B2/billing/usage — usage summaryLoadAggregate token / tool / agent-hour usage matches analyticsRW
B3/billing/usage — usage detail drilldownDrillPer-team, per-agent detailRW
B4/billing/plansLoadPlans listed; "upgrade" CTA is disabled or marked "coming soon" (paid MVP out of scope)R
B5/billing/invoicesLoadInvoice list (likely empty for fixture)R

4.5 Settings

#SurfaceTest CaseExpectedOscarDanaLeoMia
S1/settings — profileEdit own nameSaved; audit eventRWRWRWRW
S2/settings — securityView sessions, sign out other devicesCurrent session preserved; others signed outRWRWRWRW
S3/settings/usersInvite userInvitation email sent; pending user appearsRWRW pillar
S4/settings/organizationEdit org name, logoSaved; audit eventRWDDD

4.6 Admin (client-portal admin pages — distinct from admin portal)

These pages exist in client as power-user controls. Several are ComingSoon and are allowed to remain so for this PRD. For each, we verify at minimum that the "coming soon" state renders without errors, and that the route is not accidentally reachable by under-clearance personas.

#SurfaceTest CaseExpectedOscarDanaLeoMia
A1/admin/orgLoadTree renders; edit controls workRWR pillar
A2/admin/usersLoad; bulk role changeWorks; audit eventRWRW pillar
A3/admin/teamsLoadComingSoon state or full pageR
A4/admin/approvals (policies)LoadApproval policies listRWR
A5/admin/rolesLoadRole list; assignRWRW pillar
A6/admin/importSCIM import fixture fileImport runs; results visibleRWRW
A7/admin/guardrailsLoadKnown P0 problem page (UX audit) — verify ONLY that (a) controls enforce correctly regardless of UX, (b) under-clearance users are denied. Do not block pilot on UX here; track UX in PRD #553 / UX audit backlogRWRDD
A8/admin/conflictsLoadComingSoon OK; no crashR
A9/admin/metricsLoadPlatform metrics (may show demo data)R

5. Cross-Cutting Tests

These are not tied to a single page. Each carries a canonical ID used in bug reports.

IDTestSuccess Criterion
C1Clerk sign-up end-to-endNew user completes Clerk flow → lands in portal → MemberService receives webhook → member row exists with correct email + clerk_user_id
C2Org creation + first-admin promotionFirst signed-up user of a new org is promoted to L5; subsequent signups default to L1
C3Clerk → MemberService webhook retrySimulate webhook 500; retry succeeds; no duplicate member row
C4Clearance projectionEvery page renders correctly for each persona; no undefined sections; no blank denials without message
C5BYOA tool config — happy pathConfigure a tool; agent calls tool; call succeeds; audit event recorded; cost charged to team budget
C6BYOA — budget cap denialWith cap at $0.01, trigger a $0.10 tool call; call is denied at gateway; friendly error surfaces in agent chat; audit records the denial reason
C7Agent deploy → real LLM callDeploy copilot-engineering → send a message → response streams from real LLM (not fixture) → audit event logs the call + tokens + cost
C8Governance — autonomy crossingConfigure autonomy level so "delete-file" needs approval; agent attempts delete-file; action pauses; approval request surfaces; on approve → executes; on deny → rejects; both paths audited
C9Approval chain — approveLeo submits; Dana approves; originating action executes; no stuck state
C10Approval chain — denyLeo submits; Dana denies; originating action rejected; Leo sees denial reason
C11Session durability — chatStart a /quad conversation; reload page mid-stream; conversation resumes or is persisted and re-openable
C12Session durability — approvalOpen an approval; reload mid-approve; approval state preserved; no double-execute
C13Real-time — badge countSubmit approval from Leo; Dana's portal badge increments within 10s without page reload
C14Real-time — Quad proactiveTrigger proactive conflict; pinned message appears in Quad within 10s
C15Accessibility — keyboard nav (top 5 pages)Tab / Shift-Tab reaches every interactive control; Enter activates; visible focus ring; Escape closes modals
C16Accessibility — screen-reader labels (top 5 pages)All form inputs have labels; all icon-only buttons have aria-label; landmarks (main, nav) present
C17Mobile (375 px) — top 10 pagesNo horizontal scroll; no overlapping content; key CTAs reachable; sidebar collapses or drawer opens cleanly
C18Error recovery — network blip mid-deployKill network for 3s during /agents/deploy step 3; user sees retry; completes on retry without duplicate agent
C19Error recovery — server 5xx during approvalForce 500 on approve-request; user sees friendly error; state unchanged; retry succeeds
C20Auth token expiryExpire Clerk token mid-session; user is redirected to sign-in with return URL; on sign-in, lands back on original page
C21Dev artifacts absentGrep every rendered page for user-facing strings matching UUID, action_type, org_unit, cascade, sticky-deny, TODO, RPC, *.edit, requires_approval; any hit = P1 bug

6. Test Data / Fixtures

6.1 Tenant

  • Name: acme-corp-test
  • Not upsquad-ai itself — keeps the real tenant clean for founder-run pilot onboarding on acceptance.
  • Clerk organization + subscription seeded via Clerk admin API using fixture script.

6.2 Members

3 pillars × 2 teams × 2–4 members, plus 3 directors and 1 owner = 17 human members + 3 agent members = 20 total. Each has a fixed email of form <role>.<name>@acme-corp-test.upsquad.ai captured by Clerk sandbox.

6.3 Fixture File

  • Location: testdata/e2e/acme-corp.json in upsquad-client.
  • Fields per member: id, clerk_user_id, email, name, clearance, pillar, team, role.
  • Seeded via scripts/e2e-seed.sh which calls Clerk + MemberService using fixture Clerk API key.

6.4 Agents

AgentDeployed ToProfileTools WhitelistedBudget
copilot-engineeringPlatform Teamsoftware-engineergit-read, github-issues-read, jira-read$5 / mo
copilot-financeFinance Teamfinancial-analystgsheet-read, gsheet-write, slack-post$5 / mo
copilot-marketingMarketing Teamcontent-writernotion-read, notion-write, slack-post$5 / mo

7. Test Methodology

7.1 Phase 1 — Manual Pass (QA-led, 1 working day)

  • QA agent drives a real browser as each persona in sequence.
  • Follows persona checklist tests/e2e/personas/<id>.md.
  • Any divergence from expected state → file bug per §8.
  • Screenshots captured for P0 / P1 bugs using browser dev-tools.

7.2 Phase 2 — Fix Wave (1 working day)

  • All P0 bugs fixed. ≤ 3 P1 with documented workaround accepted.
  • P2 / P3 triaged into backlog with labels.
  • Re-verification of just the fixed-bug paths, not full re-run.

7.3 Phase 3 — Automation (parallel, starting Phase 1)

  • Playwright scripts for top 15 flows (all of §5 plus core persona happy paths from §4).
  • Location: tests/e2e/*.spec.ts in upsquad-client.
  • Runs in CI on every client-portal PR.
  • A Playwright failure is a CI gate — blocks merge.

7.4 Tooling

  • Browser: Chromium (primary), Firefox + WebKit smoke on C17 mobile tests.
  • Recorder: Playwright codegen for initial capture, then hand-tuned.
  • Video: recorded on failure only (Playwright trace).
  • Report: playwright-report/ HTML uploaded as CI artifact.

8. Bug-Filing Convention

8.1 Template

Title: bug(P<n>): <one-line symptom> Example: bug(P1): Approvals page shows "action_type: tool_call" to non-technical user

Body (exact template):

**Found in:** PRD #950
**Persona:** <fx-id> (e.g., fx-dana-director)
**Surface:** <route or component> (e.g., /approvals)
**Severity:** P0 | P1 | P2 | P3
**Commit / SHA:** <client commit> / <core commit>

### Reproduction
1.
2.

### Expected


### Actual


### Screenshot / Video
<ref>

### Proposed Fix (optional)

8.2 Labels

Always: bug, qa-e2e, portal:client, one of P0 / P1 / P2 / P3. Also one of: frontend, backend, or devops depending on root cause (QA's best guess; architect can re-label).

8.3 Auto-board-sync

All bugs pick up Status = Todo, Track = qa, Agent = qa-engineer on creation via scripts/board-sync.py. QA then re-triages Agent and Track as bugs are assigned.


9. Severity Rubric

SeverityDefinitionExamples
P0Blocks pilot onboarding. Data corruption, permission bypass, cannot complete a core flow, auth broken, agent runtime broken for any persona.Mia can approve a request; agent deploy 500s every time; sign-up webhook drops payload
P1Pilot-degrading. Misleading state, developer-artifact leak, annoying UX a non-engineer would complain about, recoverable but visible.Page shows a UUID field; "requires_approval" enum string surfaced; badge count wrong by 1
P2Polish; acceptable for pilot with workaround.Minor copy inconsistency; mobile padding off on a non-top-10 page; sluggish animation
P3Nice-to-have.Help-text wording; tooltip delay; icon choice

9.1 Pilot-Cutover Gate

Pilot cutover allowed when:

  • 0 P0 open.
  • ≤ 3 P1 open, each with a comment documenting the workaround and an acceptance note from PM.
  • No limit on P2 / P3 but all must be triaged (labeled + assigned to owner).

10. Acceptance

10.1 QA Sign-off

QA comments on this PRD issue:

QA-E2E SIGN-OFF: All persona checklists complete. Bugs filed: <count> (<P0>P0 / <P1>P1 / <P2>P2 / <P3>P3). Open at cutover: <0> P0 / <≤3> P1. Passes §9.1 gate.

10.2 Architect Review

Principal Architect reviews for systemic concerns (not individual bugs):

  • Are bugs clustered around a single subsystem (indicates deeper flaw)?
  • Are any P1s actually re-classified P0s (permission or data issues)?
  • Sign-off: ARCH REVIEW: No systemic concerns. Cleared for product acceptance.

10.3 PM Acceptance

Product Manager verifies the delivered state against §1.1 Success Metrics and comments: PM ACCEPTANCE: Pre-onboarding E2E verification complete. Ready for pilot cutover.

10.4 Founder Approval

Founder triggers the actual pilot cutover (re-seeding against upsquad-ai real tenant) after PM acceptance. This is explicitly a human-decision item per CLAUDE.md.


11. Delivery Timeline

DayActivityOwner
D0PRD approved; fixture seed script readyPM, QA
D1Manual pass Phase 1 (personas Owner + Director)QA
D1–D2Bugs file as foundQA
D2Manual pass Phase 1 (personas Lead + Member + Agent)QA
D2Playwright scripts for top 15 flows in draftQA
D3Fix wave Phase 2SMEs (backend / frontend per bug label)
D3Re-verify fix-bug pathsQA
D3Playwright green in CIQA + DevOps
D4Architect systemic reviewPrincipal Architect
D4PM acceptancePM
D4Founder cutoverFounder

Aggressive target: pilot cutover by D+4 working days. If fix wave exceeds 1 day, timeline extends day-for-day.


12. Dependencies

  • core#827 (BYOA governance) merged — verified D-2.
  • core#826 (agent lifecycle governance) merged — verified D-2.
  • core#917 (Wave K.2.3) merged — verified D-2.
  • client#110 (dev-bypass removal) merged — verified D-2.
  • client#116 (mock-import CI gate) merged — verified D-2.
  • PRD #824 (Dashboard Data Integration) merged — verified D-2.
  • Clerk sandbox with fixture-user creation API access.
  • Real LLM API key for C7 (already in vault per memory reference_api_keys_dev).
  • Fixture seed script scripts/e2e-seed.sh (to be written).
  • Persona checklists tests/e2e/personas/<id>.md (to be written).

13. Risks & Mitigations

RiskLikelihoodImpactMitigation
Bugs exceed 1-day fix waveHighDelayed cutoverTriage ruthlessly; P2 / P3 never block; timeline extends day-for-day
P0 discovered at persona 4 of 5MediumRe-run earlier personasFix, then targeted re-verify only affected surfaces
Fixture tenant leaks into production analyticsLowData pollutionTenant name acme-corp-test; analytics queries exclude any tenant matching *-test
Real LLM cost blows up in testingLowBudget hitBudget cap of $5/agent/mo enforced; testing in controlled windows
UX audit's P0 on /admin/guardrails forces scope expansionMediumScope creepExplicitly deferred in A7: verify permissions + no-crash only, UX is separate PRD
Playwright flakiness blocks CIMediumMerge frictionQuarantine flaky tests after 2 failures; fix within 3 days or remove

14. Open Questions

  1. Clerk fixture user creation — is there a rate limit on sandbox user creation that would block a 20-member fixture seed in one run? (QA to confirm D0.)
  2. Audit export CSV format — must it match a spec, or is best-effort OK? (PM default: best-effort, spec in a follow-up.)
  3. Mobile breakpoint — is 375 px correct (iPhone SE) or should we target 390 px (iPhone 12)? (Frontend SME to decide; either works for this PRD.)
  4. Playwright in CI — dedicated runner or shared? (DevOps to advise; either works.)

15. Changelog

VersionDateChanges
1.02026-04-22Initial draft. 5 personas, 45 surface test cases, 21 cross-cutting tests, fixture tenant acme-corp-test, 4-day timeline.