Skip to content

Web Architecture

apps/web is a TanStack Start application that mainly does four things:

  1. Compose the browser/runtime shell.
  2. Connect the shared @life-manager/db data layer to web-specific services.
  3. Persist web-only UI/runtime state in Zustand where needed.
  4. Add browser integrations such as PWA, notifications, Sentry, and route prefetching.

The business data model does not primarily live in apps/web. Most domain reads, writes, collections, and types come from @life-manager/db, while shared workflows and formatting helpers live in @life-manager/shared.

TanStack Start request
-> `src/start.ts` / `src/server.ts`
-> `src/routes/__root.tsx`
- global auth lookup via `getAuthUser()`
- Mantine / dates / notifications / i18n bootstrapping
- devtools, Vercel analytics, Speed Insights
-> route branch
- public routes (`/`, `/$lang/*`, `/auth/*`)
- protected shell (`/_app`)
- onboarding (`/new-user`)
-> protected routes wrap content with:
- `PowerSyncProvider`
- `WebCollectionsProvider`
- `Shell`
src/
routes/ TanStack Router file routes
components/ Web UI and shell composition
db/
powersync/ Browser PowerSync database + connector
queries/ Web-specific query wrappers
supabase/ Server/admin Supabase helpers
confirmations/ Browser confirmation adapter for collection workflows
stores/ Zustand stores for web-only state
hooks/ UI orchestration and browser-aware hooks
lib/ Toasts, logout cleanup, feature helpers
actions/ Server-side auth actions used by TanStack Start
utils/ Small browser utilities

Routing is file-based and generated into src/routeTree.gen.ts.

Route areaRole
__root.tsxGlobal document, auth bootstrap, Mantine/providers, analytics/devtools
index.tsxPublic landing page
$lang.tsxLocale gate for localized public content
$lang/docs/*Public product docs rendered inside the marketing/docs layout
$lang/guides/*Public step-by-step guides
auth/*Sign-in and OAuth callback flow
_app.tsxAuthenticated application entrypoint
_app/dashboard.tsxDashboard
_app/project/overview.tsxWork overview / project index
_app/project/detail.tsxWork detail page keyed by projectId search param
_app/finance.tsxFinance module
_app/calendar.tsxCalendar module
_app/profile.tsxProfile page
_app/settings.tsxDedicated settings route, mainly for mobile
_app/habbit-tracker.tsxPlaceholder route
new-user.tsxOnboarding/initial profile setup for authenticated users
api/*Small server endpoints such as /api/version

src/routes/_app.tsx is the runtime boundary of the authenticated app:

  • it disables SSR for the shell route
  • it redirects unauthenticated users to /auth
  • it mounts PowerSyncProvider and WebCollectionsProvider
  • it waits for both PowerSync and the profile query to become ready
  • it shows a minimum-duration loading screen to avoid flicker
  • it renders Shell only after the offline-first layer is usable

/new-user repeats the same provider stack, but renders InitializeProfile instead of the main shell.

src/components/AppShell/Shell.tsx owns the persistent layout:

  • Header with global controls and the time tracker
  • Navbar with module navigation
  • Main content area
  • Aside panel with collapsible contextual content
  • Mobile navigation drawer
  • Settings modal
  • Offline indicator

The shell is also where several app-wide behaviors start:

  • useProcessRecurringCashflows()
  • useCheckNewVersion()
  • useNotificationHandler()
  • useAppointmentStatusManager()

That makes Shell the operational center of the authenticated UI, not just a layout wrapper.

Two state families are intentionally separated.

  • Read via @life-manager/db/queries
  • Mutated via @life-manager/db/actions
  • Backed by PowerSync + Supabase
  • Available offline once synced
  • Stored in Zustand under src/stores/
  • Used for UI preferences, view state, drawers, selected entities, and computed timer snapshots
  • Persisted only where it is useful for UX

vite.config.ts configures vite-plugin-pwa with:

  • precached JS/CSS/fonts/images
  • network-first caching for Supabase, PowerSync, and navigation requests
  • browser service worker registration in production

RoutePrefetcher then preloads critical authenticated routes after boot to improve offline usability.

  • Sentry is initialized in both router/client (src/router.tsx) and server entry (src/server.ts)
  • Vercel Analytics and Speed Insights are mounted in the root document
  • TanStack devtools, router devtools, pacer devtools, recurring-cashflow devtools, and PowerSync diagnostics are exposed in development

useCheckNewVersion() polls /api/version, compares it against window.__BUILD_VERSION__, and shows a persistent refresh notification when a newer build is available.