4.5 KiB
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.
# 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/sharedexports 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 authprotectedProcedure— Session requiredmemberProcedure— Session + valid org membership (injectsorgIdandrole)
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 connectionBETTER_AUTH_SECRET/BETTER_AUTH_URL— Auth configSMTP_*— Email for magic linksNEXT_PUBLIC_APP_URL— Admin public URLEXPO_PUBLIC_API_URL— Mobile points to admin APIUPLOAD_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-fnsfor formatting - Icons:
lucide-react(admin),@expo/vector-icons(mobile) - Schema changes: Always run
pnpm db:generateafter editingpackages/shared/prisma/schema.prisma - tRPC client (mobile): configured in
apps/mobile/lib/trpc.ts, usessuperjsontransformer