Imported from amoerie/the-mole (
AGENTS.md). Install upstream withnpx skills add amoerie/the-mole. Copyright stays with the author.
Agent Guide (AGENTS.md)
Welcome, agent! This guide provides technical details on how to maintain, test, and evolve the codebase.
๐๏ธ Project Architecture & Functionality
The project is a web game for "De Mol" (The Mole), where players rank contestants each episode.
- API: A .NET 10.0 Web API using Entity Framework Core (SQLite). It handles authentication, game state, rankings, and scoring.
- Client: A React 19 application built with Vite, TypeScript, and Tailwind CSS. It provides the user interface for ranking, leaderboard, and admin management.
Key Logic: Scoring
Scores are calculated after the mole is revealed. Each episode is worth 0โ100 points based on how high the player ranked the actual mole.
Score = round(((N - R) / (N - 1)) ร 100, 2) (rounded to two decimal places)
๐ Adding a New Feature
1. Backend: Adding a New Endpoint
- Define Model (if needed): Add a new class in
api/Models/. - Update DbContext: Add a
DbSet<T>toapi/Data/AppDbContext.cs. - Create Route Handler:
- Add a new static class in
api/Routes/(e.g.,NewFeatureRoutes.cs). - Use the
WebApplicationextension method pattern:public static void MapNewFeatureRoutes(this WebApplication app). - Register it in
api/Program.csusingapp.MapNewFeatureRoutes().
- Add a new static class in
- Implement Logic: Use Minimal API features (
app.MapGet,app.MapPost, etc.).- Use
AuthHelper.GetUserInfo(ctx)for authentication/authorization. - Return
Results.Ok(),Results.BadRequest(), etc. - Use
WithName("OperationName")andWithTags("Tag")for OpenAPI.
- Use
2. Frontend: Consuming the New Endpoint
- Regenerate Client: Run
dotnet build api/Api.csprojthencd client && npm run generate. - Update Mapper (optional): If the generated types need cleanup, update
client/src/api/mappers.ts. - Update Client Wrapper: Update
client/src/api/client.tsto include the new method, calling the generated function.
3. Frontend: Adding a New Component/Page
- Components: Add to
client/src/components/. Use shadcn/ui components fromclient/src/components/ui/for consistency. - Pages: Add to
client/src/pages/. - Routing: Register the new page in
client/src/App.tsx. - Hooks: Use
useAuth()for user session info anduseQuery(oruseEffect+api) for data fetching.
๐งช Testing
Backend Integration Tests (api.tests/)
- Create a new test class with
IClassFixture<CustomWebApplicationFactory>and hold aTestContextfield (not_factorydirectly). - Construct
TestContextin the constructor:_ctx = new TestContext(factory). Pass optionaluserId,displayName, orrolesfor non-default auth (e.g.roles: ["authenticated"]for non-admin tests). - Use
_ctx.PrepareDb(seed?)to reset the DB and optionally seed data before each test. - Use
_ctx.CreateClient()to get anHttpClient. - Use
TestDatastatic helpers (TestData.Game(),TestData.GameWithContestants(),TestData.GameWithPlayer(),TestData.Player(),TestData.User(),TestData.Episode()) for common seed data instead of constructing entities inline. - Use
_ctx.AsUnauthenticated()or_ctx.AsNonAdmin()(both returnIDisposable) in ausingblock to temporarily change auth state โ no manualTestAuthHandlermanipulation ortry/finallyneeded. - Use
_ctx.ReadDb<T>()/_ctx.ReadDbAsync<T>()to inspect the database after a request instead of opening scopes manually.
Frontend Unit/Component Tests (client/src/test/)
- Use Vitest + React Testing Library.
- Mock the API:
vi.mock('../api/client', ...)to isolate component logic. - Provide auth/context wrappers in your test setup (many tests define a local
renderWithAuthhelper in the test file to do this). - Assert using
screen.getByText,expect(...).toBeInTheDocument(), etc. - Use
fireEventoruserEventto simulate interactions.
๐ ๏ธ Tooling & Maintenance
๐งช Testing & Coverage
We enforce an 80% code coverage threshold for both the API and the Client in CI. Before opening a pull request, run the coverage commands for both backend and frontend locally and ensure new or changed code is covered by tests; avoid lowering coverage thresholds unless there is an explicit team decision and update or add tests whenever you modify behavior.
Backend (.NET)
- Run tests:
dotnet test api.tests/Api.Tests.csproj - Check coverage:
dotnet test api.tests/Api.Tests.csproj --collect:"XPlat Code Coverage" --settings coverage.runsettings
Frontend (React/Vite)
- Run tests:
npm run test(inclient/) - Check coverage:
npm run test:coverage(inclient/) - Thresholds: Configured in
client/vite.config.ts(80% for lines, statements, functions, and branches). - Exclusions:
client/src/api/generated.tsis excluded from coverage as it is auto-generated.
๐ OpenAPI & Client Generation
The frontend API client is generated from the backend's OpenAPI specification.
1. Regenerate OpenAPI Spec
The OpenAPI spec (api/openapi.json) is generated automatically when you build the API project:
dotnet build api/Api.csproj
Note: This is enabled by OpenApiGenerateDocumentsOnBuild in api/Api.csproj.
2. Regenerate Frontend Client
Once api/openapi.json is updated, regenerate the Orval client:
cd client
npm run generate
This updates client/src/api/generated.ts.
๐๏ธ Database Migrations
We use Entity Framework Core with SQLite.
- Add a migration:
dotnet ef migrations add YourMigrationName --project api/Api.csproj - Update database:
dotnet ef database update --project api/Api.csproj
๐งน Code Quality
Backend
- Formatting: We use CSharpier. Run
dotnet csharpier .to format. - Linting: Standard .NET analyzers are enabled via
AnalysisMode: Recommended. - Strict Mode:
TreatWarningsAsErrorsandEnforceCodeStyleInBuildare enabled inDirectory.Build.props. Any violation or warning will fail the build.
Frontend
- Formatting: We use Prettier. Run
npm run format. - Linting: We use ESLint. Run
npm run lint.
๐ CI/CD
- GitHub Actions (
.github/workflows/ci.yml) runs on every push and PR tomain. - It enforces formatting, linting, build, and the 80% coverage threshold.
- Successful builds on
mainare automatically deployed to Fly.io.