# AGENTS.md ## Commands ```sh # Root (runs both frontend + backend) bun run dev # Individual packages bun run dev:frontend bun run dev:backend bun run build:frontend # Linting (Biome - ESLint was replaced) bun run lint bun run lint:fix # fixes and formats # Prisma (run from backend) bun --filter backend prisma:generate # regenerate client after schema changes bun --filter backend prisma:migrate # apply migrations ``` ## Architecture ``` apps/frontend/ # React + Vite + TanStack Router/Query apps/backend/ # Bun + Hono + Prisma packages/api-contract/ # Shared Zod schemas, types, route definitions ``` **Shared contract pattern:** 1. Update `packages/api-contract` first (schemas/types) 2. Implement handler in `apps/backend` 3. Consume from `apps/frontend` via workspace import `@repo/api-contract` ## Authentication (Better Auth) The project uses **Better Auth** for session management, replacing the legacy Supabase Auth. - **Backend Context**: `AppContext` (mapped via `AppEnv`) provides `c.get('user')` and `c.get('session')`. - **User Roles**: The `User` model includes a `role` field (default: `member`). Use `requireSuperAdmin` middleware for protected admin routes. - **Session Persistence**: - Backend: Hono CORS must have `credentials: true`. - Frontend: `authClient` must have `fetchOptions.credentials: 'include'`. - Frontend: Axios instance must have `withCredentials: true`. ## Key Quirks - **Prisma 7**: Uses `prisma.config.ts`, requires `DATABASE_URL` env var at generate time. - **Gravatar Fallback**: Users without an `image` get an automatic Gravatar Identicon. - Backend: Handled in `user.service.ts` for profile API. - Frontend: Handled in `AuthProvider` (`auth.tsx`) for the session state. - **Zod v4**: Use `.issues` instead of `.errors` for validation errors. - **TanStack Router**: Routes are code-generated. Use `--filter frontend build` not raw vite build. ## Docker Deployment (Dokploy) - **Build Context**: `./` (monorepo root) - **Dockerfile**: `Dockerfile` (in root, not `apps/backend/`) - **Required args**: `DATABASE_URL`, `VITE_API_BASE_URL`, `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL` - **bun.lock must be tracked**: It's in `.gitignore` by default - remove it for Docker builds ## Linting Biome is used (not ESLint). Config in `biome.json`: - Line width: 100 - Quote style: single - Semicolons: always - `noUnusedVariables`: warn ## Environment Variables **Backend** (`apps/backend/.env`): - `DATABASE_URL` - PostgreSQL connection (required for Prisma) - `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL` - Auth core - `APP_BASE_URL` - Frontend URL for trusted origins - `CORS_ORIGIN` - Frontend URL for CORS policy **Frontend** (`apps/frontend/.env`): - `VITE_*` prefix required (Vite embeds these at build time) - `VITE_API_BASE_URL` - Backend URL (default: http://localhost:3000)