stadtwerke/innungsapp/CLAUDE.md

117 lines
4.5 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
**InnungsApp** is a multi-tenant SaaS platform for German trade guilds (Innungen). It consists of:
- **Admin Dashboard**: Next.js 15 web app for guild administrators
- **Mobile App**: Expo React Native app for guild members (iOS + Android)
- **Shared Package**: Prisma ORM schema, types, and utilities
## Commands
All commands run from `innungsapp/` root unless noted.
```bash
# Development
pnpm install # Install all workspace dependencies
pnpm dev # Start all apps in parallel (Turborepo)
# Per-app dev
pnpm --filter admin dev # Admin only (Next.js on :3000)
pnpm --filter mobile dev # Mobile only (Expo)
cd apps/mobile && npx expo run:android
cd apps/mobile && npx expo run:ios
# Type checking & linting
pnpm type-check # tsc --noEmit across all apps
pnpm lint # ESLint across all apps
# Database (Prisma via shared package)
pnpm db:generate # Regenerate Prisma client after schema changes
pnpm db:migrate # Run migrations (dev)
pnpm db:push # Push schema without migration (prototype)
pnpm db:studio # Open Prisma Studio
pnpm db:seed # Seed with test data
pnpm db:reset # Drop + re-migrate + re-seed
# Deployment
vercel --cwd apps/admin # Deploy admin to Vercel
cd apps/mobile && eas build --platform all --profile production
cd apps/mobile && eas submit --platform all
```
## Architecture
### Monorepo Structure
- **pnpm Workspaces + Turborepo** — `apps/admin`, `apps/mobile`, `packages/shared`
- `packages/shared` exports Prisma client, schema types, and shared utilities
- Both apps import from `@innungsapp/shared`
### Data Flow
```
Mobile App (Expo)
▼ HTTP (tRPC)
Admin App (Next.js API Routes)
▼ Prisma ORM
PostgreSQL Database
```
The mobile app calls the admin app's tRPC API (`/api/trpc`). There is no separate backend — the Next.js app serves both the admin UI and the API.
### tRPC Procedure Hierarchy
Three protection levels in `apps/admin/server/trpc.ts`:
- `publicProcedure` — No auth
- `protectedProcedure` — Session required
- `memberProcedure` — Session + valid org membership (injects `orgId` and `role`)
Routers are in `apps/admin/server/routers/`: `members`, `news`, `termine`, `stellen`, `organizations`.
### Multi-Tenancy
Every resource (member, news, event, job listing) is scoped to an `Organization`. The `memberProcedure` extracts `orgId` from the session and all queries filter by it. Org plan types: `pilot`, `standard`, `pro`, `verband`.
### Authentication
- **better-auth** with magic links (email-based, passwordless)
- Admin creates a member → email invitation sent via SMTP → member sets up account
- Session stored in DB; mobile app persists session token in AsyncStorage
- Auth handler: `apps/admin/app/api/auth/[...all]/route.ts`
### Mobile Routing (Expo Router)
File-based routing with two route groups:
- `(auth)/` — Login, check-email (unauthenticated)
- `(app)/` — Tab navigation: home, members, news, stellen, termine, profil (requires session)
Zustand (`store/auth.store.ts`) holds auth state; React Query handles server state via tRPC.
### Admin Routing (Next.js App Router)
- `/login` — Magic link login
- `/dashboard` — Protected layout with sidebar
- `/dashboard/mitglieder` — Member CRUD
- `/dashboard/news` — News management
- `/dashboard/termine` — Event management
- `/dashboard/stellen` — Job listings
- `/dashboard/einstellungen` — Org settings (AVV acceptance)
File uploads are stored locally in `apps/admin/uploads/` and served via `/api/uploads/[...path]`.
### Environment Variables
Required in `apps/admin/.env` (see `.env.example`):
- `DATABASE_URL` — PostgreSQL connection
- `BETTER_AUTH_SECRET` / `BETTER_AUTH_URL` — Auth config
- `SMTP_*` — Email for magic links
- `NEXT_PUBLIC_APP_URL` — Admin public URL
- `EXPO_PUBLIC_API_URL` — Mobile points to admin API
- `UPLOAD_DIR` / `UPLOAD_MAX_SIZE_MB` — File storage
## Key Conventions
- **Styling**: Tailwind CSS in admin; NativeWind v4 (Tailwind syntax) in mobile
- **Validation**: Zod schemas defined inline with tRPC procedures
- **Dates**: `date-fns` for formatting
- **Icons**: `lucide-react` (admin), `@expo/vector-icons` (mobile)
- **Schema changes**: Always run `pnpm db:generate` after editing `packages/shared/prisma/schema.prisma`
- **tRPC client (mobile)**: configured in `apps/mobile/lib/trpc.ts`, uses `superjson` transformer