V1 Web PWA · Surface walkthrough

Profile

A per-surface walkthrough of the V1 Web PWA customer surface: layout, states, interactions, data, and cross-references.

walked
8sections5 minread1table

On this page

Context. surface customer · domain account · route /profile · auth signed-in · source apps/oshun/web/src/app/profile/page.tsx

Last walked. 2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data (2xx), console/page-errors, expected content, screenshot verified; live screen-reader, touch, offline, and telemetry-delivery checks pending a manual AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md' '2026-06-27 Codex route-state addendum — default signed-in profile, noindex metadata, privacy/data-rights highlight deep links, loading/offline/partial outage/error shell fallbacks, standalone PWA restore, anonymous auth gate, sign-out affordance, and upgrade-intent billing card are covered by the E2E references below.' '2026-06-28 Codex shortcut-map addendum — every account shortcut href and WebProfileRoutePath highlight target is enumerated here and verified in profile-settings-flows.spec.ts against the real /profile route.

Purpose#

The signed-in user's account hub — "your account, billing, privacy, devices, and what OSHUN remembers." Renders inside the standard ShellLayout with active="profile", composing the ProfileSettingsPanel plus the shared shell-route surface content resolver. Used as the landing for profile deep-links and as the host for shell-driven upgrade intents.

Entry points#

  • Shell nav: Profile (active="profile")
  • Direct URL / bookmark — yes (auth required)
  • Upgrade-intent deep link: ?intent=<intent>&domain=<id>&requiredTier=<tier> surfaces an upgrade-intent context to ProfileSettingsPanel
  • Sub-route deep link: any WebProfileRoutePath resolved by resolveWebProfileRoutePath(searchParams) (e.g., billing, devices, privacy, account — each highlights a specific row)
  • Cross-domain settings deep links (e.g., from /aaa-upgrade)
  • Sign-out / sign-in confirmation handoff

Layout regions#

page.tsx mounts <ShellLayout active="profile" breadcrumbs=[Home, Profile]> and inside it calls resolveShellRouteSurfaceContent({ surface: 'profile', searchParams, children: <ProfileSettingsPanel highlightPath={highlightPath} upgradeIntent={upgradeIntent} /> }) — the resolver handles offline / fallback / unavailable framings, falling through to the panel as children when the surface is healthy.

  • Shell header: standard shell header with Profile active
  • Breadcrumbs: Home → Profile (passed in via ShellLayout prop)
  • Surface resolver wrapper: resolveShellRouteSurfaceContent decides whether to render the profile panel or a shell-route fallback (offline / unavailable / reason)
  • ProfileSettingsPanel: the actual settings UI (account, billing, privacy, devices, memory, etc.) — composition lives in apps/oshun/web/src/components/ProfileSettingsPanel.tsx. The panel uses highlightPath to open / accent a specific row and upgradeIntent to surface an inline upgrade context

States#

  • Loading — handled by the resolver / panel; no explicit loading.tsx at this segment
  • Default (no params) — full settings panel renders
  • Highlight pathsearchParams.path (or equivalent) resolves via resolveWebProfileRoutePath; the panel accents the matching sub-section
  • Upgrade intent active — when intent, domain, or requiredTier are present, the panel renders an upgrade-intent context above (or inside) the relevant row
  • Offline — shell-route resolver returns the offline fallback
  • Unavailable / reason — shell-route resolver returns partial outage, degraded, retry, and missing-segment fallbacks for the profile surface
  • Error (recoverable) — resolver error state keeps profile inside the shell with primary and secondary recovery affordances; row-level profile validation errors remain panel-owned and are covered by the relevant interaction specs
  • Anonymous user — middleware redirects to /welcome
  • Standalone PWA — shell restores /profile from standalone launch and keeps the mobile nav within the viewport

Interactions#

Interactions live inside ProfileSettingsPanel; the page itself only wires highlight + upgrade-intent state. Current route-state coverage is:

  • apps/oshun/web/e2e/profile-settings-flows.spec.ts — signed-in default profile, canonical/noindex metadata, privacy/data-rights highlight routing, full account shortcut href + highlight-target matrix, loading/offline/ partial-outage/error resolver cards, standalone PWA restore, profile writes, preferences, data export, and legal navigation
  • apps/oshun/web/e2e/profile-channel-bindings.spec.ts — "Notification channels" email/SMS binding lifecycle on the real /profile surface: address/code issue, BFF read-back, route reload persistence, revoke read-back, wrong-code non-verification, and 390 px 44 px/no-overflow controls with the real service worker enabled
  • apps/oshun/web/e2e/shell-surface-states.spec.ts and apps/oshun/web/e2e/shell-route-signoff.spec.ts — exhaustive shell fallback matrix for the profile surface across loading, empty, offline, partial outage, degraded, retry, partial response, and error states
  • apps/oshun/web/e2e/customer-paywall-upgrade-surfaces.spec.ts/profile billing upgrade intent for free/pro/premium entitlement states and the no-intent control
  • apps/oshun/web/e2e/auth-entry-flows.spec.ts — anonymous /profile redirect, signup/onboarding handoff back to /profile, and sign-out control coverage

Surface-resolver framing#

  • Offline framing — surfaces a network-issue message instead of the panel
  • Unavailable framing — surfaces partial outage / degraded shell recovery copy and trace/missing-segment notes instead of the panel

Highlight target (panel-level)#

  • Highlight row open/accent — when highlightPath is set, the panel opens and accents the corresponding row (account / billing / devices / privacy / memory / safety etc.)

Upgrade-intent context (panel-level)#

  • Upgrade intent banner — when any of intent, domain, requiredTier is set, the panel surfaces an in-context upgrade affordance referencing the intent

Sub-route navigation#

ProfileSettingsPanel exposes the account shortcut rail (data-profile-account-links) with this route/highlight contract:

Shortcut label Hook id Href Highlight result
Account account /profile?path=account Account shortcut active; no section
Activity & stats stats /profile?path=stats Domain statistics section force-open
Plans & billing billing /profile?path=billing Plans and billing section force-open
Personalization personalization /profile?path=personalization Personalization section force-open
Privacy & access privacy /profile?path=privacy Privacy and access section force-open
Data rights data-rights /profile?path=data-rights Data requests section force-open
Devices & sessions sessions /profile?path=sessions Devices & sessions section force-open
Operator access operator-access /profile?path=operator-access Operator access section force-open

The resolver also accepts alias-only highlight values that do not have rail shortcuts: billing-support → billing, preferences → personalization, assistant / assistant-controls / memory → Assistant and memory, notifications → Notifications, calendar / calendar-sync → Calendar sync, consent / consent-controls → Consent center, and onboarding / onboarding-setup → Onboarding setup.

Data & contracts#

  • Reads:
    • resolveWebProfileRoutePath(searchParams)WebProfileRoutePath | undefined
    • WEB_SHELL_ROUTE_PATHS.home for the breadcrumb
    • ProfileSettingsPanel reads BFF account/billing/devices endpoints (verify exact list on walk)
  • Writes: panel-driven (account update, billing, devices, etc.)
  • Realtime: device sessions list may subscribe to a session feed (verify)
  • Caching: SSR shell; SWR within the client panel
  • Auth/role check: signed-in; middleware enforces
  • Metadata: title: 'Profile', description: 'Your account, billing, privacy, devices, and what OSHUN remembers.', robots: { index: false, follow: false }, alternates.canonical: '/profile'

Cross-references#

  • Shell: shell/01-app-shell.md, shell/04-auth-session.md
  • Sub-routes:
  • Upgrade flow: ../13-system/aaa-upgrade.md
  • E2E coverage:
    • apps/oshun/web/e2e/profile-settings-flows.spec.ts
    • apps/oshun/web/e2e/profile-channel-bindings.spec.ts
    • apps/oshun/web/e2e/shell-surface-states.spec.ts
    • apps/oshun/web/e2e/shell-route-signoff.spec.ts
    • apps/oshun/web/e2e/customer-paywall-upgrade-surfaces.spec.ts
    • apps/oshun/web/e2e/auth-entry-flows.spec.ts
  • Component sources:
    • apps/oshun/web/src/components/ProfileSettingsPanel.tsx
    • apps/oshun/web/src/components/ShellLayout.tsx
    • apps/oshun/web/src/app/shellRouteState.ts
    • apps/oshun/web/src/navigation/routes.ts

Open questions / known gaps#

  • Enumerate every settings row exposed by ProfileSettingsPanel and map to WebProfileRoutePath highlight values — the shortcut matrix above is backed by profile-settings-flows.spec.ts, and alias-only highlight values are documented separately.
  • Document the full set of supported intent values for upgradeIntent and their tier-requirement mapping
  • Confirm whether the panel exposes a sign-out affordance here or relies on the shell header — the panel exposes data-profile-signout-btn, covered in auth-entry-flows.spec.ts and shared-shell-entry-routes.spec.ts
  • Confirm device-session realtime updates
  • Document offline behaviour for in-flight settings edits