A self-hostable personal super app — a Next.js 14 monorepo hosting modular mini-apps behind a profile + PIN login. Runs locally on port 3000 and is reached from your phone as an installable PWA via Tailscale.
Mini-apps included: Assistant (AI chat + tools), Stocks, Trades, Budget, Music, Security (camera DVR). Each can be enabled per-profile by the admin.
This is a template. It ships with no personal data — you provide your own via
apps/web/.env.localand the gitignoredapps/web/config/*.jsonfiles.
pnpm install
cp .env.example apps/web/.env.local # then edit it (see Environment below)
pnpm dev # web on http://localhost:3000On first load you will land on the login screen with a single Admin profile. Tap it to set your PIN. From the profile menu you can then create additional profiles for family members and choose which mini-apps each one sees.
| Tool | Version | Notes |
|---|---|---|
| Node | >= 20 | Use nvm / fnm, or nvm-windows |
| pnpm | 9.15.0 | corepack enable && corepack prepare pnpm@9.15.0 --activate |
| Git | any recent | Set core.autocrlf=true on Windows |
| Tailscale | latest (optional) | For phone PWA access + public sharing (see step 5) |
git clone https://github.com/<your-org>/<your-repo>.git
cd <your-repo>
pnpm installThe web app reads apps/web/.env.local (gitignored). Copy the template and fill
it in:
cp .env.example apps/web/.env.localSee .env.example for every variable and how to generate it. The essentials:
AUTH_SECRET— sign session cookies (openssl rand -base64 32).ADMIN_PROFILE_NAME— the name shown for your admin profile on the login screen.AUTH_URL— the origin the PWA is served from (localhost, or your Tailscale host).- VAPID keys +
PUSH_INTERNAL_TOKEN— for Web Push. FINNHUB_API_KEY— for the Stocks mini-app.- Assistant/Security paths — only if you use those mini-apps.
Some mini-apps read local, personal data from JSON files that are not committed. Copy each example and edit:
cp apps/web/config/budget-members.example.json apps/web/config/budget-members.json
cp apps/web/config/budget-categories.example.json apps/web/config/budget-categories.jsonbudget-members.json— your household members + the card-member spellings that map to each.budget-categories.json— local/regional merchant → category rules on top of the built-in national-chain rules.
SQLite file at apps/web/local.db is created on first run (initializeDatabase
runs lazily) and seeds the admin profile. To start fresh, delete the file.
pnpm db:generate # regenerate Drizzle migrations when the schema changes
pnpm db:studio # browse the DBThe PWA connects to your dev server over Tailscale, not localhost.
- Install Tailscale on the host and sign in.
- Note the machine's Tailscale hostname:
<machine>.<your-tailnet>.ts.net. - Set
AUTH_URLin.env.localto that origin. - To reach it from anywhere (not just your tailnet), enable a Funnel:
tailscale funnel --bg --https=443 http://localhost:3000 - On the phone, open the URL in Chrome/Safari → "Add to Home Screen", and grant notification permission for Web Push.
Because a Funnel is public, the profile + PIN login is your access gate. PINs are rate-limited and lock out after repeated failures.
pnpm dev
# Visit http://localhost:3000, set the admin PIN, log in
# Open /stocks — verify quotes load
# Open /assistant — send "hi", verify a reply streams inapps/
web/ Next.js 14 (App Router). The shell, auth, and API routes.
web/config/ Gitignored per-app data (*.example.json templates committed)
miniapps/
assistant/ Chat + tools (pluggable LLM backend)
stocks/ Watchlist, quotes, fundamentals
packages/
ui, core, database, Shared workspace packages
config, tailwind, typescript, eslint
- A single admin profile is seeded on first run (name from
ADMIN_PROFILE_NAME). - The admin creates member profiles and assigns which mini-apps each can use.
- Members set their own 6-digit PIN on first login; anyone can change their PIN in Settings.
- The admin can switch into any profile without a PIN (useful for setup/support).
- All routes are gated by middleware; per-app access is enforced server-side.
pnpm dev # all apps via turbo
pnpm --filter @mysuperapp/web dev # just the web app
pnpm --filter @mysuperapp/web test # vitest run
pnpm --filter @mysuperapp/web lint
pnpm build- PWA loads but nothing works: the API isn''t reachable — usually the tunnel.
Check
tailscale funnel statusshows "Funnel on", and pull-to-refresh on the phone to clear a stale service worker. - Push notifications silent: VAPID keys changed → re-subscribe from Settings.
- Assistant backend errors: check
LLM_BACKENDand the matching CLI path env var are set for your chosen backend.