From 1ed5dc15d842a80423255caa01d4fd06759d69fb Mon Sep 17 00:00:00 2001 From: Thibault Pouch Date: Tue, 3 Mar 2026 09:11:24 +0100 Subject: [PATCH] chore: add root-level CLAUDE.md and docker-compose.yml Monorepo root files for documentation and unified Docker Compose that brings up all three services (db, api, front, intra) together. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 123 +++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 50 ++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 CLAUDE.md create mode 100644 docker-compose.yml diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..5b915ac --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,123 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +CrowMate Nest is a community platform for **Headless Hazard**, an indie game. It consists of three monorepo sub-projects: + +- **`nest-backend/`**: REST API (Express + TypeScript + PostgreSQL/Prisma) +- **`nest-front/`**: Public-facing community website (React + Vite, port 5173) +- **`nest-intra/`**: Staff-only internal portal (React + Vite, port 5174) + +## Development Commands + +### Backend (`nest-backend/`) +```bash +npm run dev # ts-node-dev with auto-restart +npm run build # TypeScript compilation to dist/ +npm start # Run compiled dist/index.js +npm run db:push # Push Prisma schema changes (no migration file) +npm run db:migrate # Create and apply a migration +npm run db:seed # Run prisma/seed.ts +npm run db:studio # Open Prisma Studio UI +``` + +### Frontend & Intranet (`nest-front/` and `nest-intra/`) +```bash +npm run dev # Vite dev server +npm run build # tsc + vite build +npm run lint # ESLint +npm run preview # Serve built output locally +``` + +### Environment Setup (Backend) +Copy `.env.example` to `.env`. Key variables: +```env +DATABASE_URL="postgresql://user:password@localhost:5432/nest_db" +JWT_SECRET="..." +PORT=3000 +ADMIN_USERNAME / ADMIN_EMAIL / ADMIN_PASSWORD # Auto-creates admin on startup +FRONT_ORIGIN / INTRA_ORIGIN # Production CORS origins +``` + +## Architecture + +### Backend + +**Tech**: Express 4, TypeScript 5.6, Prisma 5.22, PostgreSQL, JWT (7d), bcryptjs, Zod + +**Request pipeline**: `authenticate()` → `requireStaff()` / `requireAdmin()` middleware, then route handler. JWT payload includes `{ userId, role, isAdmin }`. + +**Route groups** (all under `/api/`): +- `auth`: login, register, /me +- `users`: CRUD + ban/unban (admin) +- `forum`: categories, threads (paginated), replies +- `bugs`: bug reports with uniqueCode (HH-XXXX), comments, internal notes, me-too voting +- `feed`: staff-only post feed +- `events`: announcements/updates/milestones/polls with voting +- `team`: team member profiles + +**Key patterns**: +- All request bodies validated with Zod (`schema.safeParse()`) +- Response shaping via format helpers (`formatBug()`, `formatMember()`, etc.) in `src/lib/` +- Prisma eager-loads relations to avoid N+1 +- Composite primary keys for `MeTooBug` (userId + bugReportId) and `PollVote` (userId + pollOptionId) + +### Frontends (nest-front & nest-intra) + +**Tech**: React 19, Vite 7, Tailwind CSS 4, React Router 6, TypeScript 5.9 + +Both frontends currently use **mock data** — no real API calls are wired up yet. Auth state is simulated with `MOCK_USERS` in `src/contexts/AuthContext.tsx` and persisted to `localStorage`. + +- `nest-front` uses storage key `crowmate_auth_user`; all roles (`user`, `dev`, `com`) can log in +- `nest-intra` uses storage key `crowmate_intra_user`; blocks `role === 'user'` at login — staff only (`dev` / `com`) + +**Shared structure** (both React projects mirror each other): +``` +src/ + App.tsx # Route definitions, React.lazy() imports + contexts/ + AuthContext.tsx # Auth state, role helpers, localStorage + components/ + layout/ # Page wrapper with nav/sidebar + shared/ # ProtectedRoute, PageLoader, DevRoleSwitcher + pages/ # Page components (lazy loaded) + types/index.ts # All TypeScript interfaces + utils/format.ts # formatDate(), timeAgo(), truncate() + data/mockData.ts # Mock users, forum, bugs, events, team +``` + +**DevRoleSwitcher component** (nest-front only): floating UI to switch auth roles instantly without logging out — for development testing only. + +### User Roles & Access + +| Role | Access | +|------|--------| +| `user` | Public site features only | +| `dev` / `com` | Staff features (feed, intranet, bug triage, event creation) | +| `isAdmin: true` | User management, forum moderation, destructive operations | + +### Data Models Summary + +**User**: id, username, email, password (hashed), role, isAdmin, isBanned, avatarUrl + +**Forum**: ForumCategory → ForumThread → ForumReply (cascade deletes on thread) + +**BugReport**: uniqueCode (HH-XXXX auto-generated), severity, status, assignedTo; with BugComment (public), BugReportNote (staff-only), MeTooBug + +**Events**: EventPost (type: announcement | update | milestone | poll) → Poll → PollOption → PollVote (composite key) + +**Team**: TeamMember standalone profiles + +### Docker + +Each sub-project has its own `Dockerfile` and `docker-compose.yml`. The backend uses multi-stage builds; frontends use Nginx to serve the Vite build output (`nginx.conf` included). + +## Key Implementation Notes + +- The backend auto-creates an admin user on startup if `ADMIN_USERNAME/EMAIL/PASSWORD` env vars are set +- `prisma/seed.ts` populates sample data for development +- `nest-intra/public/services.json` defines quick-link cards for dev tools (GitHub, Plane, Jenkins, Proxmox, etc.) shown on the `/intranet/services` page +- Both frontends' `types/index.ts` and `utils/format.ts` are near-identical — changes often need to be mirrored +- When integrating real API calls, replace mock auth in `contexts/AuthContext.tsx` and mock data in `data/mockData.ts` diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..bd32c5b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,50 @@ +services: + db: + image: postgres:16-alpine + restart: unless-stopped + environment: + POSTGRES_DB: nest_db + POSTGRES_USER: nest_user + POSTGRES_PASSWORD: nest_password + volumes: + - db_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U nest_user -d nest_db"] + interval: 5s + timeout: 5s + retries: 5 + + api: + build: ./nest-backend + restart: unless-stopped + ports: + - "3000:3000" + environment: + DATABASE_URL: postgresql://nest_user:nest_password@db:5432/nest_db + JWT_SECRET: ${JWT_SECRET:-change_me_in_production} + PORT: 3000 + ADMIN_USERNAME: ${ADMIN_USERNAME:-admin} + ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@crowmate.fr} + ADMIN_PASSWORD: ${ADMIN_PASSWORD:-change_me} + FRONT_ORIGIN: ${FRONT_ORIGIN:-http://localhost:5173} + INTRA_ORIGIN: ${INTRA_ORIGIN:-http://localhost:5174} + depends_on: + db: + condition: service_healthy + command: > + sh -c "npx prisma db push && node dist/index.js" + + front: + build: ./nest-front + restart: unless-stopped + ports: + - "5173:5173" + + intra: + build: ./nest-intra + restart: unless-stopped + ports: + - "5174:5174" + +volumes: + db_data: