feat(fp): WP-22 — durable persistence (SQLite/EF Core)
Applications, documents (+ audit log) and the brief move off static in-memory Dictionaries onto a real SQLite file via EF Core, so demo data survives a process restart or `docker compose restart api` for the first time. The three stores (ApplicationStore/DocumentStore/BriefStore) keep their exact public signatures and static-class shape — no DI, no async ripple into Program.cs's minimal-API handlers — each method just opens a short-lived AppDbContext via Db.Create() under the same lock it already had. Opaque nested shapes (a wizard's draft snapshot, a brief's sections/placeholders/status) are stored as JSON text columns rather than redesigned into relational tables, matching the existing "don't interpret it" posture. Found two things the WP's own text got wrong, corrected in docs/backlog/WP-22-durable-persistence.md's Deviations section: SeedData never seeded these three stores (only the read-only BRP/DUO-mimicking GETs, which stay in-memory) so there's no seed step; and no new docker-compose volume is needed since the existing bind mount already covers the SQLite file — verified against this environment's real podman-backed compose stack, not just by reading the file. Also: pinned SQLitePCLRaw.bundle_e_sqlite3 to 3.0.3 (EF Core Sqlite's own transitive default bundles a pre-3.50.2 SQLite with a known high-severity memory-corruption advisory); found and fixed a real xUnit test race where concurrent test-class hosts stomped a shared static connection-string field, fixed by disabling cross-class test parallelization rather than adding DI the stores don't otherwise need. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ using BigRegister.Domain.Documents;
|
||||
using BigRegister.Domain.Intake;
|
||||
using BigRegister.Domain.Registrations;
|
||||
using BigRegister.Domain.Submissions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
@@ -29,8 +30,23 @@ const string SpaCors = "spa";
|
||||
builder.Services.AddCors(o => o.AddPolicy(SpaCors, p =>
|
||||
p.WithOrigins("http://localhost:4200").AllowAnyHeader().AllowAnyMethod()));
|
||||
|
||||
// WP-22: the three stores (Applications/Documents/Briefs — Data/*.cs) are static
|
||||
// classes that open their own short-lived AppDbContext per call (see Db.Create),
|
||||
// not DI-injected, so there's no builder.Services.AddDbContext here. Configuring
|
||||
// the connection string still goes through IConfiguration so tests/deployments can
|
||||
// override it (ConnectionStrings:AppDb) without touching this file.
|
||||
Db.ConnectionString = builder.Configuration.GetConnectionString("AppDb") ?? Db.ConnectionString;
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Migrate on every startup, seed nothing (WP-22): unlike SeedData's read-only
|
||||
// reference fixtures (registration/diplomas/notes — untouched by this WP, still
|
||||
// static in-memory), Applications/Documents/Briefs never had seed data — they
|
||||
// started empty and accumulated through normal use before this WP too. A fresh
|
||||
// SQLite file just starts empty again, same as the old in-memory dictionaries did.
|
||||
using (var db = Db.Create())
|
||||
db.Database.Migrate();
|
||||
|
||||
// Every request gets a correlation id (client-supplied X-Correlation-Id if present,
|
||||
// else generated), pushed into the logging scope for every log line the request
|
||||
// produces (not just the Submit helper's) and echoed back as a response header for
|
||||
|
||||
Reference in New Issue
Block a user