V1 Web PWA · Surface walkthrough

Welcome — Public marketing entry + auth panel

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

walked
9sections5 minread

On this page

Context. surface customer · domain onboarding-public · route /welcome · auth anon · source apps/oshun/web/src/app/welcome/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; content re-verified 2026-06-03 against current source; 2026-06-27 targeted reconciliation mapped current Playwright/component coverage for mode resolution, root + welcome social-preview assets, signed-in continuation, BFF auth endpoints, public auth telemetry, SmartAppBanner behavior, and first-time handoff evidence.

Purpose#

The auth-coupled public entry surface. Combines the marketing pitch with sign-up / sign-in / recover modes resolved from URL state. Where /landing is the editorial face, /welcome is the funnel surface that hands users into the signed-in shell.

Entry points#

  • Middleware redirect target for anonymous users hitting any signed-in route (with ?redirect=<path> preserved)
  • Session-expiry redirect (?expired=1)
  • Re-auth flow (?reauth=1)
  • Post-sign-out redirect (?signedOut=1)
  • Direct URL / bookmark — yes (anon)
  • Marketing campaigns / inbound links
  • Recovery emails carrying ?code=<recoveryCode> (sanitised by sanitizeRecoveryCode)
  • Mode pre-selection via ?mode=signin|recover|signup
  • Entry source tagging via ?entry=<source> (parsed by parsePublicEntrySource)

Layout regions#

page.tsx is a server component that sanitises search params and renders <SmartAppBanner /> plus <WelcomePageView />. WelcomePageView is the Lilith-register marketing-and-auth composition.

  • SmartAppBanner: mobile-browser banner offering the native app install (rendered above all other content when conditions match)
  • WelcomePageView root (Lilith register; cream paper, terracotta accent, Cormorant Garamond serif):
    • Broadsheet hero with masthead and lede
    • Domain rooms strip (six rooms — Tara, Veritas, Nisaba, Metis, plus Arete and Nyx via getShellNavigationDomains())
    • Conversion-path tiles (Tara / Veritas / Nisaba / Metis as the marketing-conversion subset)
    • WelcomeAuthPanel — the sign-up / sign-in / recover form, mode driven by initialMode, redirectPath, recoveryCode, expired / reauth / signedOut props
    • Footer with cross-page nav (Home / Dashboard / Domains / Features) — no legal links

States#

  • Default sign-up — no query string; mode='signup'
  • Sign-in mode?mode=signin or ?expired=1 / ?reauth=1 force sign-in
  • Recover mode?mode=recover exposes the recovery form
  • Recovery code prefill?code=<token> populates the recovery input via sanitizeRecoveryCode
  • Session expired banner?expired=1 shows expired notice and forces sign-in mode
  • Re-auth required?reauth=1 shows re-auth notice and forces sign-in mode
  • Signed out confirmation?signedOut=1 shows confirmation
  • Redirect target preserved?redirect=<path> flows through to the post-auth router (sanitised by sanitizeRedirectPath)
  • Entry-source tagging?entry=<source> parsed and forwarded to trackPublicAuthFunnelCtaClicked
  • Anonymous user opens / — middleware redirects to /welcome?redirect=%2F
  • Already signed in — middleware keeps /welcome public; the page renders the signed-in continuation panel instead of redirecting away
  • Smart app banner conditions — component coverage verifies iOS and Android visibility, desktop/web hidden-by-default behavior, and dismissal persistence
  • Offline — static public shell and install assets are covered by PWA smoke/offline infrastructure; auth submissions remain online BFF writes

Interactions#

SmartAppBanner#

  • Banner row (custom) — mobile-only install nudge verified against SmartAppBanner.tsx; dismissible with seven-day localStorage persistence

Hero / conversion CTAs (WelcomePageView)#

  • Conversion-path tiles (link) — four tiles for tara | veritas | nisaba | metis with CTA labels "Begin with Tara" / "Open Veritas" / "Study with Nisaba" / "Build a path", each calling buildPublicAuthEntryPath({ mode: 'signup', redirectPath: buildWebDomainRoutePath(domain, { origin: 'home' }), entrySource: 'welcome-<domain>-conversion' })
  • Telemetry on CTA clicktrackPublicAuthFunnelCtaClicked({ surface, step, mode, entrySource, redirectPath, href })

WelcomeAuthPanel#

The interactive auth panel — verify against WelcomeAuthPanel.tsx.

  • Mode tabs ("New here" / "Returning" / "Recover")
    • Function: switch the form between modes; reflects in URL state
    • Keyboard: Left/Right arrow when within tablist; Enter activates
  • Email / password / recovery code fields
    • Validation per mode
    • Disabled while a submission is in flight
  • Submit button — primary; honours redirectPath post-success
  • OAuth / SSO buttons — not currently rendered by WelcomeAuthPanel; auth routes are email/password/recovery only
  • "Need to recover your account?" link (signin mode only) — switches to recover mode via changeMode('recover')
  • Cross-page nav — Home / Dashboard / Domains / Features (no legal links)

Data & contracts#

  • Reads: domain registry via getShellNavigationDomains(); public entry source via parsePublicEntrySource
  • Writes: WelcomeAuthPanel calls useAuth(): signUp posts /api/auth/signup -> BFF /v1/auth/signup; signIn posts /api/auth/login -> BFF /v1/auth/login; requestRecovery posts /api/auth/recovery/request -> BFF /v1/auth/recovery/request; recoverAccount posts /api/auth/recovery/confirm -> BFF /v1/auth/recovery/confirm
  • Realtime: none
  • Caching: server-rendered with sanitised search params; static marketing copy SW-cacheable
  • Auth/role check: anon; in middleware PUBLIC_PREFIXES
  • Telemetry: trackPublicAuthFunnelCtaClicked({ surface, step, mode, entrySource, redirectPath, href }) fires on conversion CTAs
  • Metadata: rich OpenGraph + Twitter card with /welcome/opengraph-image and /welcome/twitter-image route handlers, keywords includes meditation/study/learning terms, alternates.canonical: '/welcome'

Cross-references#

  • Sibling public surfaces:
  • Shell auth: shell/04-auth-session.md
  • Component sources:
    • apps/oshun/web/src/components/welcome/WelcomePageView.tsx
    • apps/oshun/web/src/components/welcome/WelcomeAuthPanel.tsx
    • apps/oshun/web/src/components/SmartAppBanner.tsx
    • apps/oshun/web/src/analytics/publicAuthFunnelTelemetry.ts
    • apps/oshun/web/src/lib/auth-session.ts (sanitisers)
    • apps/oshun/web/src/lib/public-entry.ts

Automated coverage#

  • apps/oshun/web/e2e/welcome-marketing.spec.ts
    • root crawler preflight, root + /welcome social-preview image handlers, /welcome OpenGraph/Twitter/canonical metadata, conversion-path CTA handoff, and public auth telemetry capture
  • apps/oshun/web/e2e/auth-entry-flows.spec.ts
    • anonymous route redirect to /welcome, sign-up/sign-in/recover submit paths, signed-out confirmation, redirect preservation, and onboarding handoff
  • apps/oshun/web/e2e/first-time-visitor-deepening.spec.ts
    • expired-session sign-in mode and signed-in /welcome continuation panel
  • apps/oshun/web/e2e/first-time-deepening-2.spec.ts
    • ?reauth=1 sign-in mode and reauth banner
  • apps/oshun/web/src/components/welcome/__tests__/WelcomeAuthPanel.test.tsx and WelcomeAuthPanel.accessibility.test.tsx
    • mode tabs, validation, recovery flow, reauth behavior, signed-in continuation, and accessibility
  • apps/oshun/web/src/components/__tests__/SmartAppBanner.test.tsx
    • platform detection, open/dismiss controls, copy, styling contract, and dismissal persistence

Open questions / known gaps#

  • Authenticated-user redirect — verified current behavior: signed-in users stay on /welcome and see the continuation panel.
  • OpenGraph image routes/welcome/opengraph-image and /welcome/twitter-image route handlers exist and return PNG assets.
  • Mode resolution edge cases?expired=1 and ?reauth=1 win over ?mode=signup and force sign-in mode.
  • Exact BFF endpoints — listed under Data & contracts above.
  • Smart app banner standalone suppression — no explicit standalone PWA suppression exists today; visibility is platform + dismissal based, with web users hidden by default unless the component is forced in tests.