# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Luncher is a lunch management app for teams — daily restaurant menus, food ordering, pizza day events, and payment QR codes. Czech-language UI. Full-stack TypeScript monorepo. ## Monorepo Structure ``` types/ → Shared OpenAPI-generated TypeScript types (source of truth: types/api.yml) server/ → Express 5 backend (Node.js 22, ts-node) client/ → React 19 frontend (Vite 7, React Bootstrap) ``` Each directory has its own `package.json` and `tsconfig.json`. Package manager: **Yarn Classic**. ## Development Commands ### Initial setup ```bash cd types && yarn install && yarn openapi-ts # Generate API types first cd ../server && yarn install cd ../client && yarn install ``` ### Running dev environment ```bash # All-in-one (tmux): ./run_dev.sh # Or manually in separate terminals: cd server && NODE_ENV=development yarn startReload # Port 3001, nodemon watch cd client && yarn start # Port 3000, proxies /api → 3001 ``` ### Building ```bash cd types && yarn openapi-ts # Regenerate types from api.yml cd server && yarn build # tsc → server/dist cd client && yarn build # tsc --noEmit + vite build → client/dist ``` ### Tests ```bash cd server && yarn test # Jest (tests in server/src/tests/) ``` ### Formatting ```bash # Prettier available in client (no config file — uses defaults) ``` ## Architecture ### API Types (types/) - OpenAPI 3.0 spec in `types/api.yml` — all API endpoints and DTOs defined here - `yarn openapi-ts` generates `types/gen/` (client.gen.ts, sdk.gen.ts, types.gen.ts) - Both server and client import from these generated types - **When changing API contracts: update api.yml first, then regenerate** ### Server (server/src/) - **Entry:** `index.ts` — Express app + Socket.io setup - **Routes:** `routes/` — modular Express route handlers (food, pizzaDay, voting, notifications, qr, stats, easterEgg, dev) - **Services:** domain logic files at root level (`service.ts`, `pizza.ts`, `restaurants.ts`, `chefie.ts`, `voting.ts`, `stats.ts`, `qr.ts`, `notifikace.ts`) - **Auth:** `auth.ts` — JWT + optional trusted-header authentication - **Storage:** `storage/StorageInterface.ts` defines the interface; implementations in `storage/json.ts` (file-based, dev) and `storage/redis.ts` (production). Data keyed by date (YYYY-MM-DD). - **Restaurant scrapers:** Cheerio-based HTML parsing for daily menus from multiple restaurants - **WebSocket:** `websocket.ts` — Socket.io for real-time client updates - **Mock mode:** `MOCK_DATA=true` env var returns fake menus (useful for weekend/holiday dev) - **Config:** `.env.development` / `.env.production` (see `.env.template` for all options) ### Client (client/src/) - **Entry:** `index.tsx` → `App.tsx` → `AppRoutes.tsx` - **Pages:** `pages/` (StatsPage) - **Components:** `components/` (Header, Footer, Loader, modals/, PizzaOrderList, PizzaOrderRow) - **Context providers:** `context/` — AuthContext, SettingsContext, SocketContext, EasterEggContext - **Styling:** Bootstrap 5 + React Bootstrap + custom SCSS files (co-located with components) - **API calls:** use OpenAPI-generated SDK from `types/gen/` - **Routing:** React Router DOM v7 ### Data Flow 1. Client calls API via generated SDK → Express routes 2. Server scrapes restaurant websites or returns cached data 3. Storage: Redis (production) or JSON file (development) 4. Socket.io broadcasts changes to all connected clients ## Environment - **Server env files:** `server/.env.development`, `server/.env.production` (see `server/.env.template`) - Key vars: `JWT_SECRET`, `STORAGE` (json/redis), `MOCK_DATA`, `REDIS_HOST`, `REDIS_PORT` - **Docker:** multi-stage Dockerfile, `compose.yml` for app + Redis. Timezone: Europe/Prague. ## Conventions - Czech naming for domain variables and UI strings; English for infrastructure code - TypeScript strict mode in both client and server - Server module resolution: Node16; Client: ESNext/bundler ## Code Search Strategy When searching through the project for information, use the Task tool to spawn subagents. Each subagent should read the relevant files and return a brief summary of what it found (not the full file contents). This keeps the main context window small and saves tokens. Only pull in full file contents once you've identified the specific files that matter. When using subagents to search, each subagent should return: - File path - Whether it's relevant (yes/no) - 1-3 sentence summary of what's in the file Do NOT return full file contents in subagent responses.