Web/mobile parity
What the mobile app covers relative to the web app, and the copy-model behind the shared packages/core.
The mobile app is a full-featured client, not a thin companion. It mirrors the web template's core surfaces — auth, dashboard, settings, notifications, and AI chat — using native controls, while reusing the web app's schemas, types, and API client through @valcraven/core. This page maps what's covered and explains the shared-code model.
What the mobile app covers
The app was built out phase-by-phase; each phase maps to a screen (or set of screens) under apps/mobile/src/app/.
| Area | Screens | Notes |
|---|---|---|
| Navigation shell + theme | Root layout, app-header | Light/dark/system theme; tokens mirror the web app. |
| Full auth | (auth)/sign-in, sign-up, forgot-password, two-factor | Email/password, OAuth, TOTP 2FA, and password reset — via @better-auth/expo. |
| Dashboard + items CRUD | (app)/index | The example resource, same as the web /app. |
| Settings | (app)/settings | Profile, appearance, security, billing (read-only), data export, delete account, legal. |
| Notifications + native push | (app)/notifications | List, mark-read, and native push via expo-notifications. |
| AI chat | (app)/chat | Streaming chat over the realtime Worker WebSocket, with voice. |
| Onboarding, legal, errors, deep links | Onboarding wizard, privacy-policy, terms | Plus an ErrorBoundary wrapping the root layout and an offline banner. |
Settings in detail
The settings screen (apps/mobile/src/app/(app)/settings.tsx) mirrors the web /settings page with native controls, section by section:
- Profile — edit name, upload an avatar (picks from the photo library, uploads to
/api/files, persists via/api/settings/avatar), and shows sign-in provider, email-verified badge, and "member since". - Appearance — light / dark / system theme picker.
- Security — enable/disable two-factor authentication, including QR enrollment, manual key entry, and backup codes.
- Billing — read-only plan badge; "Manage billing" opens the Stripe customer portal in the system browser (billing changes happen on the web).
- Account — export all your data as JSON (shared via the native share sheet) and delete your account.
- Legal — privacy policy and terms screens.
Where mobile intentionally defers to the web
A few flows are read-only or hand off to the browser on mobile — most notably billing: the app shows your current plan and opens the Stripe portal in the system browser rather than embedding checkout. The admin console is a web-only surface; the mobile app is an end-user client.
The shared-code model: packages/core
Both apps depend on the shared package as "@valcraven/core": "*". That "*" is a workspace dependency: npm resolves it to a local symlink into packages/core, so apps/web and apps/mobile import the same source at build time. Change a schema once and both platforms pick it up.
What packages/core exports (see packages/core/src/index.ts):
- Zod schemas + inferred types for requests/responses (
schemas/). - Shared chat logic — the model catalog, message building, and context trimming — so the web and mobile chat clients never drift.
- HTTP primitives +
ApiError, and the typedcreateApiClient. - Better Auth
Session/Usertypes (type-only).
The package has a hard constraint: nothing in it may import next/*, drizzle, better-sqlite3, react-dom, Node built-ins, or DOM globals — it must run inside React Native too. That rule is enforced at compile time by its tsconfig.json (no DOM lib, no @types/node).
It's a copy, not a published dependency
@valcraven/core is not a versioned package pulled from a registry. It lives inside your project's monorepo, and a project scaffolded from Valcraven gets its own copy of packages/core. The "*" link is intra-project only — it keeps your apps/web and apps/mobile in sync with each other. Across different apps built from the template, each project's packages/core evolves independently. That's why /valcraven-sync exists: it ports upstream Valcraven improvements (including changes under packages/core/) into a downstream project, rather than relying on a shared dependency bump.
Related
- The Expo app — running the app and its stack.
- Architecture → Monorepo — the workspace layout.
- API endpoints — the routes the mobile app calls.