# Step 3 Output: Database Schema & EF Core ## Summary All database infrastructure from the plan was implemented. The `DbContext` was placed in `MicCheck.Api/Data/` (not `MicCheck.Infrastructure`) to avoid a circular dependency, since `MicCheck.Api` already references `MicCheck.Infrastructure`. --- ## What Was Built ### `MicCheck.Api/Data/MicCheckDbContext.cs` - 18 `DbSet` properties covering all domain entities - `OnModelCreating` delegates to `ApplyConfigurationsFromAssembly` - Uses `using AppEnvironment = MicCheck.Api.Environments.Environment;` alias to avoid collision with `System.Environment` ### `MicCheck.Api/Data/Configurations/` (18 files) One `IEntityTypeConfiguration` per entity with all constraints: | Entity | Key constraints | |---|---| | `Feature` | Name max 150, InitialValue max 20k, unique `(ProjectId, Name)` | | `FeatureState` | Value max 20k, `Version` as concurrency token, unique `(FeatureId, EnvironmentId, IdentityId)`, indexes on `EnvironmentId` and `IdentityId` | | `IdentityTrait` | Value max 2k, unique `(IdentityId, Key)` | | `Environment` | ApiKey max 100, unique index on `ApiKey` | | `ApiKey` | Key max 512, Prefix max 8, unique index on `Key` | | `Identity` | unique `(EnvironmentId, Identifier)` | | `AuditLog` | index on `(OrganizationId, CreatedAt)` | | `Webhook` | index on `EnvironmentId` | ### `MicCheck.Api/Data/DatabaseUrlParser.cs` Parses `DATABASE_URL` (postgresql://user:pass@host:port/db) into an Npgsql connection string. Defaults port to 5432 when not specified. ### `MicCheck.Api/Data/DatabaseSeeder.cs` Seeds a default Organization ("Default"), Project ("My Project"), and three Environments (Development, Staging, Production) on first startup when no organizations exist. Only runs in the Development environment. ### `Program.cs` updates - Registers `MicCheckDbContext` with Npgsql using either `DATABASE_URL` or `ConnectionStrings:DefaultConnection` - Runs the seeder only when `app.Environment.IsDevelopment()` --- ## Deviations from Plan - **DbContext location**: Plan specified `MicCheck.Infrastructure/Data/`. Moved to `MicCheck.Api/Data/` due to circular dependency constraint. `MicCheck.Infrastructure` is reserved for background services (Step 7). - **Migrations**: Not added in this step — requires a running PostgreSQL instance. Run manually with `dotnet ef migrations add InitialSchema --project src/api/MicCheck.Api`. --- ## Tests Added ### `MicCheck.Api.Tests.Unit/Data/MicCheckDbContextTests.cs` (10 tests) Covers all major DbSet operations using `UseInMemoryDatabase`: - Organization CRUD - Project query by organization - Environment query by API key - Feature query by project - FeatureState query by environment - Segment with included rules - Identity with included traits - AuditLog filter by organization - Webhook filter by environment - ApiKey retrieval by hashed key - User retrieval by email ### `MicCheck.Api.Tests.Unit/Data/DatabaseUrlParserTests.cs` (4 tests) - Full URL with all components - Default port (5432) when omitted - Custom port preserved - Special characters in password preserved ### `MicCheck.Api.Tests.Unit/Auth/AuthEndpointsTests.cs` (3 tests, fixed) Integration tests using `WebApplicationFactory`. Fixed by: - Setting `UseEnvironment("Testing")` so the seeder doesn't run at startup - Overriding `ITokenService` with a Moq mock --- ## Issues Encountered 1. **`System.Environment` name collision** — `MicCheck.Api.Environments.Environment` conflicts with `System.Environment` pulled in by implicit usings. Resolved everywhere with the `using AppEnvironment = ...` alias. 2. **`WebApplicationFactory` + seeder crash** — The seeder runs in Development mode and tries to create a `MicCheckDbContext`, which requires a real Npgsql connection. Test factory fixed by setting `UseEnvironment("Testing")` to prevent the seeder block from executing. --- ## Test Results ``` Passed! - Failed: 0, Passed: 73, Skipped: 0, Total: 73 ```