From b9e7c258aecaf9b6c5ebbefa081f36f5ac20767b Mon Sep 17 00:00:00 2001 From: Jaap-Jan de Wit | DodoTech Date: Wed, 29 Jul 2026 12:17:59 +0200 Subject: [PATCH] Point the design-time factory at the stack the repo ships MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `dotnet ef database update --project src/DodoSSH.Infrastructure` — the command the README documents — failed on a clean machine. The design-time default named `dodossh_design` as user `postgres` with no password, which is a database this repository never creates, while the development compose stack creates `dodossh`/`dodossh`. The failure arrives as a SCRAM authentication error, so it reads like a broken container rather than a stale default. The default is now the compose stack, since that is the only local database the repo defines. DODOSSH_DESIGN_CONNECTION still overrides it, and a real deployment migrates through that or the migrator job. Also documents running the thing end to end, which the README never covered: the four commands in order, that migrations are a separate step because the API deliberately fails readiness rather than migrating, and the three M1 gaps visible in the first five minutes — so they are expected rather than diagnosed. --- README.md | 39 ++++++++++++++++++- .../DodoDbContextFactory.cs | 20 ++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0571cfa..f06f112 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,28 @@ The tests need a Docker daemon. Everything that touches the database, the identi server uses Testcontainers rather than a stub or a shared instance, so there is nothing to start first and nothing to clean up after — but with no daemon those suites fail rather than skip. -Run the API locally: +## Running it + +Four commands, in order. The first two are once per machine. + +**1. The development dependencies** — PostgreSQL and Keycloak, with the `dodossh` realm imported: + +```bash +docker compose -f deploy/docker-compose.dev.yml up -d +``` + +**2. The schema.** The API never migrates anything: it fails readiness while a migration is pending, and +says which one. `dotnet-ef` is pinned in `.config/dotnet-tools.json`, so run `dotnet tool restore` first if +you have not: + +```bash +dotnet ef database update --project src/DodoSSH.Infrastructure +``` + +With nothing else configured this targets the compose stack above. Set `DODOSSH_DESIGN_CONNECTION` to point +it at another database. + +**3. The server:** ```bash dotnet run --project src/DodoSSH.Api @@ -87,6 +108,22 @@ dotnet run --project src/DodoSSH.Api It listens on `http://localhost:5233`, serving `/healthz/live`, `/healthz/ready` and — in Development — `/openapi/v1.json`. +**4. The desktop client:** + +```bash +dotnet run --project src/DodoSSH.Client.App +``` + +In the app, enter `http://localhost:5233` as the server. Your browser opens for sign-in — the realm ships +`alice` / `alice` — then choose a vault passphrase and **write down the recovery code**, which cannot be +skipped and cannot be recovered from the server. You can then add a host and open a shell on it. Keycloak's +admin console is at `http://localhost:18080` (`admin` / `admin`). + +Three of M1's known gaps are visible immediately, so they are worth expecting rather than diagnosing: a +connection asks for the host's password every time, because credentials are not a synced entity type yet; +host key trust lasts one session, because known hosts do not live in the vault yet; and unlock asks for the +passphrase on every launch, because no device key is registered. + ### End-to-end verification One suite runs against a real server rather than a stub. It needs a Docker daemon and nothing else, so it diff --git a/src/DodoSSH.Infrastructure/DodoDbContextFactory.cs b/src/DodoSSH.Infrastructure/DodoDbContextFactory.cs index 71d8262..4833f5f 100644 --- a/src/DodoSSH.Infrastructure/DodoDbContextFactory.cs +++ b/src/DodoSSH.Infrastructure/DodoDbContextFactory.cs @@ -17,14 +17,28 @@ public sealed class DodoDbContextFactory : IDesignTimeDbContextFactoryEnvironment variable naming the database to work against. /// /// Only database update and dbcontext script actually connect. Generating a migration - /// needs a provider but not a reachable server, which is why there is a usable default at all. + /// needs a provider but not a reachable server, which is why the default below is allowed to be a + /// guess at all. /// public const string ConnectionVariable = "DODOSSH_DESIGN_CONNECTION"; + /// + /// Where dotnet ef connects when nothing says otherwise. + /// + /// + /// The development compose stack, because that is the only local database this repository defines. A + /// default naming a server nobody creates makes the documented dotnet ef database update fail on + /// every clean machine, which is a poor first impression of a self-hosted product — and the failure + /// arrives as a SCRAM authentication error, which reads like a broken stack rather than a stale + /// default. These credentials are the compose file's own; a real deployment migrates through + /// or the migrator job. + /// + private const string DevelopmentStackConnection = + "Host=localhost;Port=5432;Database=dodossh;Username=dodossh;Password=dodossh"; + /// public DodoDbContext CreateDbContext(string[] args) => - Create(Environment.GetEnvironmentVariable(ConnectionVariable) - ?? "Host=localhost;Database=dodossh_design;Username=postgres"); + Create(Environment.GetEnvironmentVariable(ConnectionVariable) ?? DevelopmentStackConnection); /// /// Builds a context for one database, configured as the API configures its own.