Apps
The five deployable applications in apps/ — what each one does, its dev port, its deploy target, and what to read next.
At a glance
| Package | Path | Dev port | Deploy |
|---|---|---|---|
@today/web | apps/web | 4060+ | Vercel (today.ai) |
@today/admin | apps/admin | 4061 | Vercel (admin.today.ai) |
@today/onboarding | apps/onboarding | 5174 | Standalone — native WebView shell, not part of apps/web |
@today/webview-bridge-docs | apps/webview-bridge-docs | 3000 | Vercel (default domain) |
@today/dev-docs | apps/dev-docs | 4070 | Vercel (default domain, protected) |
Only apps/web gets per-worktree free-port scanning today —
scripts/dev-server.mjs scans 4060-4069 for the first free port, so two web
worktrees auto-take different ports. apps/admin is hardcoded to 4061
(next dev --turbopack -p 4061) and conflicts on parallel worktrees; same for
apps/onboarding (Vite, --port 5174). Generalizing the scanner to admin is
on the list as a follow-up.
@today/web — main product
apps/web.
The user-facing product. Next.js 16 with the App Router, served at today.ai in
production and todayai.dev in preview/dev.
Notable concerns covered elsewhere in this manual (in upcoming chapters):
- Three dev modes (
localhost-direct/local/remote) — Workflow → Local development - BFF auth proxy (
apps/web/src/app/api/auth/[...all]/route.ts) — Architecture → Auth interaction - Cookie state on the app origin — Architecture → Auth cookie state
- OpenAPI codegen via
pnpm api:generate— Architecture → API codegen - MSW handlers + fixtures under
apps/web/src/lib/msw/— Architecture → MSW mocks - Chat runtime (already documented in
apps/web/docs/chat/) — Architecture → Chat runtime (high-level, links to the local docs) - Playwright config split (smoke / full / visual) — Toolchain → Testing → Playwright
@today/admin — internal admin
apps/admin.
Internal admin / staff app. Independent Vercel project, independent preview URL,
independent deploy workflow (deploy-admin.yml).
Shares most infrastructure with apps/web: same auth client, same OIDC flow,
same TDX components, same testing setup. Visual regression is not wired up
for admin (see TODO.md).
@today/onboarding — native WebView onboarding shell
apps/onboarding.
A standalone Vite app hosted inside the native client's WKWebView / WebView.
It is not mounted under apps/web: the web app implements its own
/onboarding route directly in Next using @today/opal primitives. This Vite
shell exists separately for the native host case, where the onboarding flow
runs inside a WebView with native messaging instead of Next SSR.
The contract is in
apps/onboarding/NATIVE_CONTRACT.md;
the dev workflow for testing inside a WebView is in
apps/onboarding/WEBVIEW_DEV_GUIDE.md.
The app handles file:// / local-files:// loading paths and routes its API
calls through the native bridge rather than the BFF.
Both the web /onboarding route and this Vite shell share the same @today/opal
flow primitives — that's the actual coupling, not "mounted under web."
@today/webview-bridge-docs — bridge contract site
apps/webview-bridge-docs.
A separate Fumadocs site that documents the WebView Bridge wire contract
plus the web SDK (@today/webview-bridge). Read by native client teams (iOS,
macOS, Android, Windows) and by anyone writing web code that runs inside a
WebView.
This site (@today/dev-docs) does not duplicate that content. See
Docs sites for the boundary.
@today/dev-docs — this site
apps/dev-docs.
You are reading it. Engineering manual for the today-platform-web monorepo
itself. Read by new contributors and by AI agents working in the repo.
Adding a new app
The full checklist will live in workspace/adding-package
in PR-CC. The short version:
- Create
apps/<name>/withpackage.json(@today/<name>),tsconfig.json,tsconfig.app.json,tsconfig.node.json,moon.yml. - Run
pnpm installto register the workspace. - Add the project to
tsconfig.json'sreferencesat the repo root if it participates intsgo --build. - If it deploys to Vercel: create a Vercel project, add
VERCEL_PROJECT_ID_<NAME>to GitHub repo variables, add.github/workflows/deploy-<name>.yml.
scripts/affected.ts discovers packages dynamically from
pnpm-workspace.yaml, so you do not need to register the new app there.