133 lines
5.4 KiB
Markdown
133 lines
5.4 KiB
Markdown
# 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 <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/`)
|
|
|
|
```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
|