// Web app for the {{projectName}} project — the SaaS DASHBOARD that closes the // signup → paywall → app loop against the sibling `api-saas-starter` api. // // Two areas: // - Public pages in a SILENT route group `src/pages/(marketing)/` — `/` and // `/login` (the parens organise files + scope a layout WITHOUT adding a URL // segment). // - The authed app under `src/pages/dashboard/`. Its `layout.tsx` loader is // the auth gate: server-side it asks the api's `session.me` and throws // RedirectError to /login for an anonymous visitor. Those pages are // `renderMode: 'ssr'` so the gate runs per request. // // The pages read the api live with `useSubscription` and write with // `useMutation` / `useAction` — imported from `src/lib/api.ts`, which binds them // ONCE to this api's generated procedure map so every tag and every input/output // type is checked by the compiler. The auth forms POST to the api's `/auth/*`. import { defineEnv, envVar } from '@voltro/env' // Public, build-time env (baked into the bundle; read via `publicEnv`). // Never a secret here — a secret belongs on the api, not the browser bundle. export const env = defineEnv({ VOLTRO_PUBLIC_APP_NAME: envVar.string({ access: 'public', default: '{{capProjectName}}' }), }) export default { type: 'web' as const, name: '{{capProjectName}}{{capAppName}}', port: {{port}}, // Follow the visitor's OS theme, set before first paint (no flash). theme: 'system' as const, env, // Bilingual by default. The framework auto-wires a cookie-driven // from these codes and loads the matching // `src/locales/.ts` catalog — so `` / `useT()` / // `useLocale()` work app-wide (SSR too). The writes the // `voltro:locale` cookie + reloads. Add a code + a `src/locales/.ts` to // grow the app to more languages. locales: ['en', 'de'] as const, defaultLocale: 'en' as const, // The api this dashboard consumes. The NAME ('app') is the lookup key — spelled // ONCE, in `src/lib/api.ts`'s `createHooks('app')`, and then // never again: pages call `useSubscription('projects.list')` / // `useMutation('projects.create')`. (A loader still names the tag itself: // `query('session.me', {})`.) The api's port is auto-discovered from its own // app.config.ts, and codegen pulls its typed rpc surface (including the // plugins' `billing.*` / `/auth`) into that same map. apis: { app: { package: '@{{projectName}}/api' }, }, }