# CLAUDE.md ## What this is The **Respellion Learning Platform** — an internal AI-powered learning app that keeps employees current with the company's evolving knowledge base. Employees follow a perpetual **26-week curriculum**, each working through weekly learning sessions and tests. An AI assistant called **R42** is available on every screen. Admins upload source documents that Claude extracts into a knowledge graph. This is a **single-page React application** (Vite) backed by **PocketBase**. There is **no separate backend** — all logic runs in the browser and talks directly to PocketBase collections and (via a proxy) the Anthropic API. --- ## Tech stack | Layer | Technology | |---|---| | Frontend | React 19 + Vite 8, React Router 7 | | Styling | Vanilla CSS (CSS custom properties) + Tailwind v4 utilities mapped to those variables | | Animation | Framer Motion | | Icons | Lucide React | | Graph viz | D3.js (admin knowledge graph only) | | Backend / DB / auth | PocketBase (self-hosted, SQLite) | | AI | Anthropic Claude via a reverse-proxy (Caddy in prod, Vite proxy in dev) | | Retrieval (RAG) | Local TF-IDF over the knowledge graph — **no Qdrant, no embeddings API** | | Validation | Zod on all AI tool output | | Infra | Docker + Caddy; Ansible playbooks under `infra/` | **Claude models** (`src/lib/llm.js`, by tier): - `fast` → `claude-haiku-4-5-20251001` (R42 chat, quiz batches, flashcards) - `standard` → `claude-sonnet-4-6` (extraction, article/slides/infographic, curriculum) - `reasoning` → `claude-opus-4-7` Admins can override any tier's model string from the Settings tab (persisted in localStorage as `admin:model:{tier}`). --- ## Repository structure ``` repo/ ├── CLAUDE.md ← you are here ├── AI_AGENT.md ← detailed architecture/patterns guide — read this ├── README.md ← quickstart ├── PROTECTED.md ← files you must not modify ├── docs/ ← spec files (describe the system as built) ├── src/ ← THE APPLICATION (React/Vite) │ ├── pages/ ← route screens (Dashboard, Leren, Testen, Leaderboard, Login, Onboarding, Admin/) │ ├── components/ ← ui primitives, admin panels, chat (R42), micro_learning │ ├── lib/ ← services: llm, db, extractionPipeline, learningService, │ │ microLearningService, testService, curriculumService, retrieval, pb │ ├── hooks/ ← React hooks │ └── store/ ← AppContext (global state) ├── pb_migrations/ ← PocketBase schema migrations (JS, applied by the PB binary) ├── scripts/ ← setup-pb-collections.mjs (local collection bootstrap) ├── public/ ← static assets, fonts ├── infra/ ← Ansible deploy playbooks (development / production) ├── Caddyfile, Dockerfile, docker-compose.yml ← deployment (frozen) └── stylesheet.css ← authoritative visual reference (frozen) ``` > **Note on `/app`:** the top-level `app/` directory is **abandoned scaffolding** > from the original Next.js + Qdrant design that was never shipped. It is not > wired into `package.json`, Vite, or Docker. **Ignore it.** The real app is `/src`. --- ## Absolute constraints 1. Never modify any file listed in `PROTECTED.md`. 2. Never modify `stylesheet.css` — it is the authoritative visual reference. Use the CSS variables in `src/index.css` and the Tailwind classes mapped to them. 3. Treat the deployment files as frozen unless explicitly asked: `Dockerfile`, `Caddyfile`, `docker-compose.yml`, `infra/`, `.github/workflows/`. 4. Never delete files without explicit confirmation. 5. Never re-enable PocketBase auto-cancellation — `pb.autoCancellation(false)` in `src/lib/pb.js` is deliberate (see AI_AGENT.md §2). 6. There is **no podcast** learning type. It was removed. Do not re-add it. 7. Ask before acting when scope is unclear. --- ## Code conventions - All `src/lib/db.js` functions are `async` — always `await` them. - All Claude tool output is validated through Zod (`src/lib/llmSchemas.js`) before use. Never reach `/api/anthropic` directly — go through `callLLM` in `src/lib/llm.js`. - No client-side API key. The Anthropic key is injected server-side by the proxy. - Reuse the UI primitives in `src/components/ui/` (`Card`, `Button`, `Tag`, `Input`). - Mobile-first — the employee app targets 375px width and scales up. - No hardcoded hex colors; use the design-system CSS variables / Tailwind tokens. --- ## Running locally ```bash npm install ./pocketbase.exe serve # or the muchobien/pocketbase Docker image node scripts/setup-pb-collections.mjs # first run only — bootstraps collections npm run dev # Vite dev server (proxies /api/anthropic) ``` Set `ANTHROPIC_API_KEY` in the environment so the Vite proxy can inject it (`vite.config.js`). PocketBase migrations in `pb_migrations/` apply automatically when the PB binary starts. | Command | Purpose | |---|---| | `npm run dev` | Vite dev server | | `npm run build` | Production build to `dist/` | | `npm test` | Vitest unit tests | | `npm run lint` | ESLint | --- ## Documentation map - `AI_AGENT.md` — detailed patterns, gotchas, and subsystem guide. **Start here for any real work.** - `docs/architecture.md` — system design and data flows - `docs/data-model.md` — every PocketBase collection and field - `docs/ingestion-spec.md` — upload → knowledge-graph extraction - `docs/generation-spec.md` — learning content + micro-learning generation - `docs/curriculum-spec.md` — 26-week per-user curriculum engine - `docs/r42-spec.md` — the R42 chatbot - `docs/frontend-spec.md` — screens, routing, onboarding - `docs/gamification-spec.md` — points, badges, leaderboard - `micro-learning-spec.md` — micro-learning learner experience --- ## When you are uncertain Check the spec files in `docs/` and `AI_AGENT.md` first. If the spec does not cover it, read the actual code in `src/` — it is the source of truth. Flag gaps explicitly rather than assuming. Do not treat the abandoned `/app` scaffolding or `legacy`-style references in old comments as guidance.