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 bysanitizeRecoveryCode) - Mode pre-selection via
?mode=signin|recover|signup - Entry source tagging via
?entry=<source>(parsed byparsePublicEntrySource)
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 byinitialMode,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=signinor?expired=1/?reauth=1force sign-in - Recover mode —
?mode=recoverexposes the recovery form - Recovery code prefill —
?code=<token>populates the recovery input viasanitizeRecoveryCode - Session expired banner —
?expired=1shows expired notice and forces sign-in mode - Re-auth required —
?reauth=1shows re-auth notice and forces sign-in mode - Signed out confirmation —
?signedOut=1shows confirmation - Redirect target preserved —
?redirect=<path>flows through to the post-auth router (sanitised bysanitizeRedirectPath) - Entry-source tagging —
?entry=<source>parsed and forwarded totrackPublicAuthFunnelCtaClicked - Anonymous user opens
/— middleware redirects to/welcome?redirect=%2F - Already signed in — middleware keeps
/welcomepublic; 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 | metiswith CTA labels "Begin with Tara" / "Open Veritas" / "Study with Nisaba" / "Build a path", each callingbuildPublicAuthEntryPath({ mode: 'signup', redirectPath: buildWebDomainRoutePath(domain, { origin: 'home' }), entrySource: 'welcome-<domain>-conversion' }) - Telemetry on CTA click —
trackPublicAuthFunnelCtaClicked({ 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
redirectPathpost-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')
Footer#
- Cross-page nav — Home / Dashboard / Domains / Features (no legal links)
Data & contracts#
- Reads: domain registry via
getShellNavigationDomains(); public entry source viaparsePublicEntrySource - Writes:
WelcomeAuthPanelcallsuseAuth():signUpposts/api/auth/signup-> BFF/v1/auth/signup;signInposts/api/auth/login-> BFF/v1/auth/login;requestRecoveryposts/api/auth/recovery/request-> BFF/v1/auth/recovery/request;recoverAccountposts/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-imageand/welcome/twitter-imageroute handlers,keywordsincludes meditation/study/learning terms,alternates.canonical: '/welcome'
Cross-references#
- Sibling public surfaces:
landing.md— editorial marketing variantwelcome-domains.md— domain landing detailwelcome-download.md— PWA / app install
- Shell auth:
shell/04-auth-session.md - Component sources:
apps/oshun/web/src/components/welcome/WelcomePageView.tsxapps/oshun/web/src/components/welcome/WelcomeAuthPanel.tsxapps/oshun/web/src/components/SmartAppBanner.tsxapps/oshun/web/src/analytics/publicAuthFunnelTelemetry.tsapps/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 +
/welcomesocial-preview image handlers,/welcomeOpenGraph/Twitter/canonical metadata, conversion-path CTA handoff, and public auth telemetry capture
- root crawler preflight, root +
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
- anonymous route redirect to
apps/oshun/web/e2e/first-time-visitor-deepening.spec.ts- expired-session sign-in mode and signed-in
/welcomecontinuation panel
- expired-session sign-in mode and signed-in
apps/oshun/web/e2e/first-time-deepening-2.spec.ts?reauth=1sign-in mode and reauth banner
apps/oshun/web/src/components/welcome/__tests__/WelcomeAuthPanel.test.tsxandWelcomeAuthPanel.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
/welcomeand see the continuation panel. - OpenGraph image routes —
/welcome/opengraph-imageand/welcome/twitter-imageroute handlers exist and return PNG assets. - Mode resolution edge cases —
?expired=1and?reauth=1win over?mode=signupand 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.