# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Repository Structure Mono-repo with two projects: - `PageManager.Api/` — .NET 10 Web API (solution root contains `PageManager.Api.slnx`) - `PageManager.Api/PageManager.Api/` — the actual C# project - `PageManager.Api/PageManager.Api.Tests/` — xunit test project - `PageManager.Web/` — React 19 + Vite + TypeScript SPA - `compose.yaml` — root-level Docker Compose orchestrating both services ## Development Commands ### API (`PageManager.Api/`) ```bash cd PageManager.Api dotnet run --project PageManager.Api # runs on http://localhost:5278 dotnet build dotnet test # all tests dotnet test --filter "FullyQualifiedName~Unit" # unit only (no Docker needed) dotnet test --filter "FullyQualifiedName~Integration" # integration only (Docker required) ``` ### Migrations (`PageManager.Api/`) EF Core tooling targets the `PageManager.Api` project. All commands run from `PageManager.Api/`. ```bash # Create a migration after changing Data/Models dotnet ef migrations add --project PageManager.Api # Apply pending migrations to the database dotnet ef database update --project PageManager.Api # Roll back to a specific migration dotnet ef database update --project PageManager.Api # Generate SQL script for a migration (useful for production deploys) dotnet ef migrations script --project PageManager.Api ``` Install the EF global tool if not present: `dotnet tool install --global dotnet-ef` ### Web (`PageManager.Web/`) ```bash cd PageManager.Web npm install npm run dev # http://localhost:5173 npm run build npm run preview # preview production build locally npm test # single pass (CI) npm run test:watch # interactive watch (development) npm run test:coverage ``` ### Docker (both services) ```bash docker compose up --build # web → :8080, api → :5278 ``` ## Architecture ### API → Web connection **Dev:** Vite dev server proxies `/api/*` to `http://localhost:5278` (configured in `PageManager.Web/vite.config.ts`). The API enables CORS for `http://localhost:5173` in `Program.cs` — only in the `Development` environment. **Production (Docker):** nginx (`PageManager.Web/nginx.conf`) proxies `/api/*` to `http://pagemanager.api:8080` (the compose service name). All other routes fall back to `index.html` for SPA routing. ## Conventions - Controllers are thin — logic lives in Services - EF Core models in Data/Models, DTOs in Api/Dtos - React components in PascalCase, files match component name - API calls go through src/api/*.ts typed wrappers, never raw fetch in components - Design reference: src/Leafreader.Web/design-reference.html ## Testing **Rule: every code change must be followed by running the relevant tests and fixing any failures before the task is considered done.** ### After API changes ```bash cd PageManager.Api dotnet test --filter "FullyQualifiedName~Unit" # always run; no Docker needed # If integration-relevant (endpoint, EF query, DB schema): also run: dotnet test --filter "FullyQualifiedName~Integration" # requires Docker ``` ### After Web changes ```bash cd PageManager.Web npm test ``` ### Test locations | Layer | Location | Tool | |---|---|---| | API unit | `PageManager.Api.Tests/Unit/Services/` | xunit + NSubstitute + FluentAssertions | | API integration | `PageManager.Api.Tests/Integration/` | xunit + Testcontainers (postgres:17-alpine) + WebApplicationFactory | | Web unit | `src/**/__tests__/` | Vitest + Testing Library | ### What to test and when - **New service method or DTO mapping** → add unit test in `Unit/Services/` - **New or changed endpoint** → add integration test in `Integration/BooksControllerTests.cs` (or a new `*ControllerTests.cs`) - **New utility function** (`utils.ts`) → add unit test in a sibling `__tests__/` folder - **New React component with logic** → add component test in `__tests__/` - **Private logic inside a component** → extract to `utils.ts` first, then test the exported function ### What does NOT get tested - `BooksRepository` — pure EF Include chains, covered by integration tests - `BooksController` — too thin, covered by integration tests - CSS Modules, `Sidebar` (static nav), `App.tsx` routing - `importQueue.ts` — currently mock stubs; add tests when real HTTP is introduced ### Decision rules - Unit test: any service method, utility function, or DTO mapping with conditional logic or data transformation - Integration test: any new endpoint, EF Core query change, or PostgreSQL-specific feature - Don't duplicate: if unit tests own mapping correctness, integration tests own HTTP contract + DB round-trip - Extract before testing: private logic inside a component must move to `utils.ts` before writing tests ### Infrastructure notes - Integration tests use `[Collection("Postgres")]` — one container shared across all integration test classes - Each integration test class truncates tables in `InitializeAsync` to ensure isolation - `Book.Formats` and `Book.Genres` are `text[]` (PostgreSQL-specific) — always use real Postgres for integration tests, never InMemory - `TestWebAppFactory` sets `UseEnvironment("Testing")` — CORS and OpenAPI middleware are skipped