---
path: /welcome
surface: customer
domain: onboarding-public
auth: anon
source: apps/oshun/web/src/app/welcome/page.tsx
status: walked
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.'
---

# Welcome — Public marketing entry + auth panel

## 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

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

## Interactions

### SmartAppBanner

- [x] **Banner row** (custom) — mobile-only install nudge verified against
      `SmartAppBanner.tsx`; dismissible with seven-day localStorage persistence

### Hero / conversion CTAs (`WelcomePageView`)

- [x] **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' })`
- [x] **Telemetry on CTA click** —
      `trackPublicAuthFunnelCtaClicked({ surface, step, mode, entrySource, redirectPath, href })`

### WelcomeAuthPanel

The interactive auth panel — verify against `WelcomeAuthPanel.tsx`.

- [x] **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
- [x] **Email / password / recovery code fields**
  - Validation per mode
  - Disabled while a submission is in flight
- [x] **Submit button** — primary; honours `redirectPath` post-success
- [x] **OAuth / SSO buttons** — not currently rendered by `WelcomeAuthPanel`;
      auth routes are email/password/recovery only
- [x] **"Need to recover your account?" link** (signin mode only) — switches to
      recover mode via `changeMode('recover')`

### Footer

- [x] **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:
  - [`landing.md`](./landing.md) — editorial marketing variant
  - [`welcome-domains.md`](./welcome-domains.md) — domain landing detail
  - [`welcome-download.md`](./welcome-download.md) — PWA / app install
- Shell auth: [`shell/04-auth-session.md`](../../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

- [x] **Authenticated-user redirect** — verified current behavior: signed-in
      users stay on `/welcome` and see the continuation panel.
- [x] **OpenGraph image routes** — `/welcome/opengraph-image` and
      `/welcome/twitter-image` route handlers exist and return PNG assets.
- [x] **Mode resolution edge cases** — `?expired=1` and `?reauth=1` win over
      `?mode=signup` and force sign-in mode.
- [x] **Exact BFF endpoints** — listed under Data & contracts above.
- [x] **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.
