Initial commit, project structure and domain models

This commit is contained in:
2026-04-07 09:14:06 -07:00
commit 7b15086fe5
111 changed files with 19818 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
The api project for MicCheck will contain the admin endpoints needed to manage features, environments, projects, settings and users. It will also contain the endpoints for checking if a flag is enabled and returning current state of a flag.
## Requirements
1. Create a new asp.net project in /src/api/ called MicCheck.Api using .net 10 and asp.net webapi.
2. Ensure the project is configured to use OpenAPI and Swagger to document all endpoints
3. Create a GetToken endpoint that returns a JWT user token when requested
4. Create a corresponding unit test project in /tests/api called MicCheck.Api.Tests.Unit and use the latest version of NUnit and Moq as the testing frameworks
5. Create a .slnx solution file at the root of the project called MicCheck.slnx and create src and tests solution folders within it
6. Add the MicCheck API and Unit tests projects to the MicCheck.slnx
7. Ensure the solution builds and all tests pass.
## Acceptance Criteria
- A new asp.net project exists at /src/api
- A corresponding unit test project exists with any code covered by unit test cases
- A new solution file called MicCheck.slnx was create and builds successfully
- Unit tests run without error

77
docs/api/00-output.md Normal file
View File

@@ -0,0 +1,77 @@
# MicCheck.Api ASP.NET Project — Implementation Output
All source files have been created. The `dotnet` CLI is not on the PATH in the current shell session, so the build and tests could not be run. See setup instructions below.
## Getting Started
```bash
# If dotnet is not on your PATH, install the SDK:
wget https://dot.net/v1/dotnet-install.sh && bash dotnet-install.sh --channel 10.0
source ~/.bashrc
# Then from the repo root:
cd /home/james/src/mic-check
dotnet build MicCheck.slnx # 0 errors expected
dotnet test MicCheck.slnx # 7 tests expected to pass
```
---
## Files Created
### Solution (`/`)
- `MicCheck.slnx` — XML solution file with `/src/` and `/tests/` solution folders
### API Project (`src/api/MicCheck.Api/`)
- `MicCheck.Api.csproj``net10.0`, nullable enabled, LangVersion latest
- `Program.cs` — OpenAPI + Scalar UI + JWT bearer auth + `ITokenService` DI registration
- `appsettings.json` — JWT config (`SecretKey`, `Issuer`, `Audience`, `ExpiryMinutes`)
- `appsettings.Development.json` — debug-level logging for development
- `Auth/TokenRequest.cs``record TokenRequest(string Username, string Password)`
- `Auth/TokenResponse.cs``record TokenResponse(string Token, DateTime ExpiresAt)`
- `Auth/ITokenService.cs` — service interface
- `Auth/TokenService.cs` — JWT generation using `System.IdentityModel.Tokens.Jwt`
- `Auth/AuthEndpoints.cs``POST /auth/token`, 400 on empty credentials, 200 + token on success
### Test Project (`tests/api/MicCheck.Api.Tests.Unit/`)
- `MicCheck.Api.Tests.Unit.csproj` — NUnit 4.5.1 + Moq 4.20.72 + `Microsoft.AspNetCore.Mvc.Testing`
- `Auth/TokenServiceTests.cs` — 4 BDD tests directly against `TokenService`
- `Auth/AuthEndpointsTests.cs` — 3 BDD tests via `WebApplicationFactory<Program>` with mocked `ITokenService`
---
## Stack
| Concern | Technology |
|---|---|
| Framework | .NET 10 (`net10.0`) |
| API style | ASP.NET Minimal API |
| OpenAPI document | `Microsoft.AspNetCore.OpenApi` 10.0.5 |
| OpenAPI UI | `Scalar.AspNetCore` 2.5.14 (available at `/scalar/v1` in Development) |
| JWT | `System.IdentityModel.Tokens.Jwt` 8.16.0 + `Microsoft.AspNetCore.Authentication.JwtBearer` 10.0.5 |
| Test framework | NUnit 4.5.1 + NUnit3TestAdapter 6.2.0 + Microsoft.NET.Test.Sdk 18.3.0 |
| Mocking | Moq 4.20.72 |
---
## Endpoints
| Method | Path | Description |
|---|---|---|
| `POST` | `/auth/token` | Returns a JWT for the provided username/password |
| `GET` | `/openapi/v1.json` | OpenAPI document (Development only) |
| `GET` | `/scalar/v1` | Scalar API UI (Development only) |
---
## Test Cases
| Class | Test | Coverage |
|---|---|---|
| `TokenServiceTests` | `WhenAUsernameIsProvided_ThenATokenIsReturned` | Token is non-empty |
| `TokenServiceTests` | `WhenATokenIsGenerated_ThenItContainsTheUsernameAsSubjectClaim` | JWT `sub` claim |
| `TokenServiceTests` | `WhenATokenIsGenerated_ThenItHasAFutureExpiry` | Expiry is in the future |
| `TokenServiceTests` | `WhenATokenIsGenerated_ThenItHasTheConfiguredIssuer` | JWT `iss` claim |
| `AuthEndpointsTests` | `WhenUsernameIsEmpty_ThenBadRequestIsReturned` | 400 on empty username |
| `AuthEndpointsTests` | `WhenPasswordIsEmpty_ThenBadRequestIsReturned` | 400 on empty password |
| `AuthEndpointsTests` | `WhenValidCredentialsAreProvided_ThenOkIsReturnedWithToken` | 200 + token body |