# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview 国土空间规划课程智能体 (Territorial Spatial Planning Course Agent) — an AI-powered Q&A system for a territorial spatial planning course. Single-container Docker deployment with supervisor managing a FastAPI backend and Next.js frontend. ## Development Commands ### Local Development **Backend** (from project root): ```bash cd backend uv sync # install Python deps (requires uv >= 0.6.15, Python >= 3.12) uv run main.py # start backend on :8000 ``` **Frontend** (separate terminal): ```bash cd web pnpm install # install Node deps (pnpm 10.6.5) pnpm dev # start Next.js on :8001 with Turbopack pnpm build # production build pnpm check # lint + typecheck pnpm lint:fix # auto-fix lint issues ``` ### Docker ```bash docker-compose up -d # build & start all services docker-compose logs -f app # follow logs docker-compose exec app bash # shell into container docker-compose exec db psql -U user -d course_agent_db # database shell ``` Ports: backend API `:8000`, frontend `:8001`, PostgreSQL `:5433` (mapped from container's 5432). ### Environment Setup Copy `env.example` to `.env` and configure. Critical variables: - `SILICONFLOW_API_KEY` — LLM provider API key - `DATABASE_URL` — `sqlite:///...` for local dev, `postgresql+psycopg://...` for Docker - `SECRET_KEY` — JWT signing key ## Architecture ### Backend (`backend/src/`) ``` api/ FastAPI routers: auth, chat, document, image, knowledge_base, course_content, forum, analytics core/ config.py (pydantic-settings), database.py (SQLAlchemy, lazy engine), security.py (JWT) llm/ siliconflow.py — ChatOpenAI wrapper over SiliconFlow API rag/ The RAG pipeline: embeddings.py → SentenceTransformer (text2vec-base-chinese) vector_store.py → Chroma singleton (langchain-chroma) retrievers.py → KnowledgeBaseRetriever (BaseRetriever subclass, filters by knowledge_base_id, distance→score conversion) chains.py → RAGChain (LangChain Runnable API, supports invoke/ainvoke/astream/astream_with_sources) conversation_chains.py → non-RAG conversation chain prompts.py → prompt templates graph/ LangGraph workflow: qa_graph.py defines a linear pipeline analyze → retrieve → generate → format (nodes.py has the node implementations) models/ SQLAlchemy ORM: User, ChatSession, ChatMessage, Document, DocumentChunk, KnowledgeBase, Book/Chapter/Section/Subsection, ForumCategory/Post/Reply, GeneratedImage, CourseModule services/ Business logic: auth, document processing, knowledge base management, LaTeX parser, file watcher, image generation (text-to-image, image-to-image) migrations/ Database migration scripts ``` ### Frontend (`web/src/`) Next.js 15 App Router + React 19 + TypeScript + TailwindCSS + shadcn/ui. ``` app/ (auth)/ login, register pages (main)/ chat, knowledge, course-content, forum, analytics, spatial (text-to-image, image-to-image), profile, settings components/ chat/ chat-interface, message-list, sidebar, knowledge-selector, model-selector, mode-selector, source-references course-content/ knowledge-graph, node-detail-dialog home/ landing page sections ui/ shadcn/ui primitives store/ auth.ts Zustand auth store chat.ts Zustand chat store (session management, streaming SSE handling) lib/ api.ts All API client functions (auth, chat, image, knowledgeBase, document, forum, analytics, courseContent, book) auth.ts NextAuth config types/index.ts TypeScript type definitions ``` ### Key Data Flows **Chat modes:** - `normal` — ConversationChain (LLM only, with chat history) - `rag` — RAGChain: embed query → Chroma similarity search (filtered by `knowledge_base_ids`) → LLM answer generation **Streaming:** Backend sends SSE events (`data: {type: "thinking"|"chunk"|"sources"|"done", ...}`). Frontend's Zustand store accumulates chunks via `requestAnimationFrame` updates. **Knowledge base pipeline:** Upload PDF/DOCX/TXT/MD → `document_service` extracts text → `text_splitters` chunks → embeddings → stored in Chroma with `knowledge_base_id` metadata for filtering. **LLM integration:** All LLM calls go through `SiliconFlowLLM` which wraps `ChatOpenAI` pointed at SiliconFlow API (`https://api.siliconflow.cn/v1`). Default model is configurable via `SILICONFLOW_MODEL` env var. Supports model selection per-request via `model` parameter. ### Database SQLAlchemy ORM with dual support: - **SQLite** — local development default - **PostgreSQL** — Docker deployment (lazy engine initialization with retry for DNS resolution) Engine creation is deferred (lazy) to handle Docker startup ordering — the engine connects only on first actual use, with 10 retries. ## Docker Deployment Multi-stage `Dockerfile`: (1) builds Next.js frontend, (2) installs Python deps via uv, (3) final slim image with Node.js + supervisor. `supervisord` manages both `uvicorn` (backend) and `next start` (frontend) in a single container. Persistent volumes: `./data`, `./runtime` (contains vector_store, logs, generated_images). ## Code Conventions - Backend Python code uses Chinese docstrings and log messages; variable/function names in English - Ruff for Python linting (line-length 88, target Python 3.12) - Frontend uses pnpm (not npm/yarn), ESLint + Prettier with Tailwind plugin - API responses are JSON; streaming uses SSE (`text/plain` with `data: {...}\n\n` lines) - All API endpoints require JWT auth except login/register; tokens stored in `localStorage` as `auth_token` - Embedding model downloads go through `HF_ENDPOINT=https://hf-mirror.com` (China mirror)