5.4 KiB
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 containsPageManager.Api.slnx)PageManager.Api/PageManager.Api/— the actual C# projectPageManager.Api/PageManager.Api.Tests/— xunit test project
PageManager.Web/— React 19 + Vite + TypeScript SPAcompose.yaml— root-level Docker Compose orchestrating both services
Development Commands
API (PageManager.Api/)
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/.
# Create a migration after changing Data/Models
dotnet ef migrations add <MigrationName> --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 <MigrationName> --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/)
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)
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
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
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.tsfirst, then test the exported function
What does NOT get tested
BooksRepository— pure EF Include chains, covered by integration testsBooksController— too thin, covered by integration tests- CSS Modules,
Sidebar(static nav),App.tsxrouting 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.tsbefore writing tests
Infrastructure notes
- Integration tests use
[Collection("Postgres")]— one container shared across all integration test classes - Each integration test class truncates tables in
InitializeAsyncto ensure isolation Book.FormatsandBook.Genresaretext[](PostgreSQL-specific) — always use real Postgres for integration tests, never InMemoryTestWebAppFactorysetsUseEnvironment("Testing")— CORS and OpenAPI middleware are skipped