# beenvoice workspace Local development layout for the **beenvoice** product: a freelancer/small-business invoicing platform with a Next.js web app and an Expo mobile companion. ``` beenvoice-meta/ ├── beenvoice-web/ # Web API + dashboard (Next.js 16, tRPC, PostgreSQL) ├── beenvoice-app/ # Mobile app (Expo, React Native, dev client) └── beenvoice.icon/ # iOS app icon asset (icon composer) ``` Each subdirectory is its own git repository. This folder is a convenience layout for working on both clients against one API. | Repo | Remote | |------|--------| | Web | [git.soconnor.dev/soconnor/beenvoice-web](https://git.soconnor.dev/soconnor/beenvoice-web) | | Mobile | [git.soconnor.dev/soconnor/beenvoice-app](https://git.soconnor.dev/soconnor/beenvoice-app) | ## Quick start (full stack) ```bash # 1. API + database cd beenvoice-web cp .env.example .env.local # edit DATABASE_URL, AUTH_SECRET, etc. docker compose -f docker-compose.dev.yml up -d bun install && bun run db:push bun run dev # http://localhost:3000 # 2. Mobile (simulator) cd ../beenvoice-app cp .env.example .env # EXPO_PUBLIC_API_URL=http://localhost:3000 bun install bun run ios # Metro on :8082, native dev build ``` Physical iPhone: set `EXPO_PUBLIC_API_URL` to your Mac's LAN IP; ensure `beenvoice-web` has `BETTER_AUTH_URL` matching a host the device can reach (trusted origins are derived from `BETTER_AUTH_URL` / `NEXT_PUBLIC_APP_URL`). ## Production deploy (Docker) From `beenvoice-web` with `.env` configured (see [beenvoice-web/README.md](./beenvoice-web/README.md#docker-deployment-app--database)): ```bash cd beenvoice-web git pull ./scripts/docker-deploy.sh # rebuild app image + restart (not docker-compose.dev.yml) ``` Plain `docker compose up -d` without `--build` reuses the existing local image and will not pick up code from `git pull`. ## How the pieces connect | Layer | Repo | Transport | Auth | |-------|------|-----------|------| | Web UI | `beenvoice-web` | tRPC `/api/trpc` (cookies) | better-auth session | | Mobile UI | `beenvoice-app` | tRPC `/api/trpc` (cookie header) | better-auth + `@better-auth/expo` → SecureStore | | Automation | `beenvoice-web` MCP `/api/mcp` | JSON-RPC | API key (`bv_…`) only | | Public invoices | `beenvoice-web` `/i/[token]` | HTTP | unauthenticated token | Mobile imports **tRPC router types** from `beenvoice-web/src/server/api/root` via `tsconfig` path mapping — keep API changes type-checked in both repos. ## Documentation map | Doc | Contents | |-----|----------| | [beenvoice-web/README.md](./beenvoice-web/README.md) | Web setup, Docker deploy, scripts | | [beenvoice-web/docs/ARCHITECTURE.md](./beenvoice-web/docs/ARCHITECTURE.md) | Server architecture (dense) | | [beenvoice-app/README.md](./beenvoice-app/README.md) | Mobile setup, troubleshooting | | [beenvoice-app/docs/ARCHITECTURE.md](./beenvoice-app/docs/ARCHITECTURE.md) | Mobile architecture (dense) | | [beenvoice-web/docs/](./beenvoice-web/docs/) | UI guides (forms, tables, breadcrumbs, email) | ## Shared domain concepts - **Clients** — billable contacts with optional default hourly rate - **Businesses** — sender profiles (logo, address, Resend email config) - **Invoices** — draft → sent → paid; line items; PDF + email; public share token - **Time entries** — clock in/out; one running timer per user; auto-attach to open invoice - **Recurring invoices**, **expenses**, **payments**, **templates** — full web support; mobile covers a core CRUD subset ## Environment cheat sheet | Variable | Where | Purpose | |----------|-------|---------| | `DATABASE_URL` | beenvoice-web | PostgreSQL | | `AUTH_SECRET`, `BETTER_AUTH_URL` | beenvoice-web | better-auth | | `EXPO_PUBLIC_API_URL` | beenvoice-app | API base for mobile | | `DISABLE_SIGNUPS` | beenvoice-web | `true` blocks new registrations | | `RESEND_*` | beenvoice-web | Invoice / reset email | ## Ports | Service | Default port | |---------|----------------| | Next.js (beenvoice-web) | 3000 | | Postgres (dev compose) | 5432 | | Metro (beenvoice-app) | **8082** (intentionally not 8081) |