Project scaffolding
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user