docs: account creation exists, and has since 69a31051

Three files said there was no way to create a second account. There is:
POST /api/users, owner-gated, with a form under Settings -> User Management,
plus role change, password reset, Linux provisioning and delete. The plan went
further and sequenced a whole phase around building it.

It cost something today. A recommendation to "do phase 5 first, it unblocks
everything" was made from this text, and withdrawn only because opening
api/users/ to write the spec found the route already there.

Worth naming the shape rather than just fixing the sentences: docs:check
compares numbers, so the counts stay honest while the prose rots. Both times
this has bitten, the stale claim was a paragraph nothing could verify. A phase
marked "not built" is worth checking against the tree before planning around
it — a plan is written once, the code moves daily.

The root CLAUDE.md carries the same correction plus the roles-as-a-table state;
it is not in a git repo, so it is fixed on disk only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
2026-08-23 21:02:14 +00:00
co-authored by Claude Opus 5
parent 9cd9d10d50
commit a6509f6456
2 changed files with 22 additions and 10 deletions
+9 -4
View File
@@ -38,10 +38,15 @@ anything under `execution`.
**Mounting a router without a registry entry makes the server refuse to boot** — see "Permissions" **Mounting a router without a registry entry makes the server refuse to boot** — see "Permissions"
below before adding one. below before adding one.
**Still single-user: account creation.** `createUser` has exactly one call site, `auth/bootstrap.ts`, **Account creation exists.** `POST /api/users` (owner-gated), with a form under Settings → User Management:
gated on an empty table. There is no signup route, no invite flow and no admin create-user handler, so it validates the password with the same rules bootstrap uses, refuses a role that is not a row in `roles`,
every existing member was inserted into Postgres by hand. That is the largest gap in the model, not a refuses `Super Admin` outright because there is exactly one owner, optionally takes an inbound SSH key, and
deliberate boundary. provisions the Linux account. `POST /users/:id/provision-linux` retries that half if the host was not ready.
This file said "there is no way to create a second account" for some days after `69a31051` shipped one, and
`docs/roles-and-teams.md` sequenced a whole phase around building it. Neither is checkable by
`bun run docs:check` — it compares numbers, and this was prose. Worth knowing as the shape of the failure:
the counts stay right and the sentences rot.
## Architecture ## Architecture
+13 -6
View File
@@ -179,14 +179,21 @@ D8's warning in front of whoever writes the first script.
code — `permissions/authorize.test.ts` is already pure and mockless, which is what makes that possible. code — `permissions/authorize.test.ts` is already pure and mockless, which is what makes that possible.
4. Teams UI, and the account screen showing which teams a user is in and as what. 4. Teams UI, and the account screen showing which teams a user is in and as what.
### Phase 5 — the thing that actually unblocks all of it ### Phase 5 — account creation — **DONE, and it was done before this phase was written**
**There is still no way to create a second account.** `createUser` has one call site, `auth/bootstrap.ts`, `POST /api/users` is owner-gated and live, with a form under Settings → User Management: same password
gated on an empty table; the existing accounts were inserted by hand. Roles and teams are a permission model validator as bootstrap, a role checked against the `roles` table, `Super Admin` refused outright, an
for accounts that cannot yet exist. optional inbound SSH key, and Linux provisioning with `POST /users/:id/provision-linux` to retry it.
Alongside it: role change, password reset, delete.
Sequenced last here because it is orthogonal, and flagged because a reader will otherwise finish phase 4 and It shipped in `69a31051`. This section spent days telling readers it did not exist and sequencing work
find nothing to test it with. **It may be worth doing first.** around building it — and on 2026-08-23 it produced a concrete cost, when a recommendation to "do phase 5
first" was made from this text and withdrawn only because someone opened `api/users/` to write the spec.
The general lesson, since it is the second time this exact shape has bitten: `bun run docs:check` compares
numbers, so counts stay honest while prose rots quietly. **A phase marked as not built is worth verifying
against the tree before it is planned around**, not because the plan was careless but because a plan is
written once and the code moves every day.
--- ---