AI Implementation feature(847): First-Start Create Admin Modal 1.06 (#9)

This commit was merged in pull request #9.
This commit is contained in:
2026-07-21 17:38:23 +00:00
parent 2ae930f325
commit dda85f8cce
5 changed files with 129 additions and 58 deletions
+20 -4
View File
@@ -3,7 +3,7 @@ type: database
title: User Table
description: The `user` table — accounts, roles, and statuses.
tags: [database, user, auth]
timestamp: 2026-07-21T14:43:00Z
timestamp: 2026-07-21T17:37:18Z
---
# Schema
@@ -37,14 +37,30 @@ timestamp: 2026-07-21T14:43:00Z
When the `user` table is empty of admins, the dedicated
`POST /api/v1/setup/create-admin` endpoint (see
[Setup Endpoint](/api/setup.md)) creates the very first admin and
auto-issues a session. Once any admin row exists the endpoint becomes
inert and returns `404 NOT_FOUND`, so the route is effectively hidden
in production.
auto-issues a session. Once any admin row exists the endpoint rejects
further attempts with `409 SYSTEM_INITIALIZED`, so the route is
effectively hidden in production.
The legacy `POST /api/v1/auth/register-first-admin` route is preserved
for compatibility but the canonical first-admin flow now lives in the
`SetupModule`.
# Concurrent bootstrap safety
Two near-simultaneous `POST /api/v1/setup/create-admin` requests cannot
both succeed. `SetupService.createAdmin` serializes callers on an
in-process promise chain (`#bootstrapChain` + private
`runBootstrap()` in `backend/src/modules/setup/setup.service.ts:111-130`)
so that the first request commits inside its `DataSource.transaction`
before the second request's transaction executes. The loser's
transaction observes `adminCount > 0` and throws
`ApiError(SYSTEM_INITIALIZED, 409)`; the winner is the only request that
creates a `UserEntity(role='admin')` row and mints a refresh token.
The lock is per-process; multi-replica deployments rely on the unique
index and transaction guard, not on this chain. The regression test is
`tests/backend/setup-create-admin.spec.ts` ("only one of two concurrent
first-admin requests succeeds").
# See also
- [Auth and Settings Tables](/database/auth-settings.md)