docs: update documentation to OKF v0.1 format

This commit is contained in:
OpenVelo Agent
2026-07-21 17:18:52 +00:00
parent cabd393288
commit 721f58a068
4 changed files with 45 additions and 16 deletions
+34 -8
View File
@@ -3,7 +3,7 @@ type: api
title: Setup Endpoint
description: Dedicated POST /api/v1/setup/create-admin endpoint used only while no administrator exists.
tags: [api, setup, bootstrap, first-admin]
timestamp: 2026-07-21T16:48:20Z
timestamp: 2026-07-21T17:18:08Z
---
# Endpoint
@@ -38,13 +38,13 @@ refreshing without storing the raw token in JS.
# Error envelope
| HTTP | `code` | When |
|------|---------------------|----------------------------------------------------------------------|
| 400 | `VALIDATION_FAILED` | zod body validation failed (length, regex, or `passwordConfirm`). |
| 400 | `WEAK_PASSWORD` | Argon2 policy rejects the password (length / mixed-case requirement). |
| 404 | `NOT_FOUND` | An admin already exists — the route is hidden once initialized. |
| 409 | `USERNAME_TAKEN` | Username collision (reachable only during a race before init). |
| 429 | `RATE_LIMITED` | `RegistrationRateLimitService` blocked the IP. |
| HTTP | `code` | When |
|------|-----------------------|----------------------------------------------------------------------|
| 400 | `VALIDATION_FAILED` | zod body validation failed (length, regex, or `passwordConfirm`). |
| 400 | `WEAK_PASSWORD` | Argon2 policy rejects the password (length / mixed-case requirement). |
| 409 | `SYSTEM_INITIALIZED` | An admin already exists. Returned to any request that arrives after bootstrap completes (also returned to the loser of a concurrent race — see *Concurrency* below). |
| 409 | `USERNAME_TAKEN` | Username collision (defensive: reachable only if two concurrent requests with the *same* username somehow slip past the in-process lock). |
| 429 | `RATE_LIMITED` | `RegistrationRateLimitService` blocked the IP. |
# Wiring
@@ -59,6 +59,32 @@ refreshing without storing the raw token in JS.
(before any cookie exists) is not blocked. The middleware still mints
a `csrf` cookie on the response so subsequent calls are covered.
# Concurrency
`SetupService` serializes bootstrap attempts inside a single Nest process
via an in-process promise chain (`#bootstrapChain` + private
`runBootstrap()`). Every caller runs its transaction exactly once; the
chain never short-circuits, so validation and rate-limit semantics stay
identical to the single-request case.
Behavior under contention:
1. Two simultaneous first-admin POSTs enter `runBootstrap()`.
2. The first request runs its transaction and creates the admin row.
3. The second request waits on the first, then runs its own
transaction; the `adminCount > 0` guard inside the transaction
fires and it throws `SYSTEM_INITIALIZED` (HTTP 409).
4. Exactly one admin row and one refresh-token row exist afterwards.
The lock is **per-process**; it does not coordinate multiple Nest
instances behind a load balancer. Multi-replica deployments still rely
on the unique-index/transaction guard, not on this chain.
The matching test lives at
`tests/backend/setup-create-admin.spec.ts` ("only one of two concurrent
first-admin requests succeeds; the other receives a controlled
conflict").
# Frontend consumer
`frontend/src/app/features/setup/setup-create-admin.service.ts` calls