docs: update documentation to OKF v0.1 format
This commit is contained in:
+34
-8
@@ -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
|
||||
|
||||
@@ -25,7 +25,7 @@ also registers two global providers:
|
||||
| `SettingsModule` | `backend/src/modules/settings/settings.module.ts` | Exposes `SettingsService` (get/set/getAll over `setting` table). |
|
||||
| `AuthModule` | `backend/src/modules/auth/auth.module.ts` | `AuthController` (`/api/v1/auth/*`) + `AuthService` (login/refresh/logout/register-first-admin).|
|
||||
| `UsersModule` | `backend/src/modules/users/users.module.ts` | `UsersController` (`/api/v1/auth/register-first-admin`) + `UsersService` (last-admin invariant). |
|
||||
| `SetupModule` | `backend/src/modules/setup/setup.module.ts` | `SetupController` (`POST /api/v1/setup/create-admin`) + `SetupService`. Returns 404 once any admin exists (route hidden). |
|
||||
| `SetupModule` | `backend/src/modules/setup/setup.module.ts` | `SetupController` (`POST /api/v1/setup/create-admin`) + `SetupService`. Returns 409 `SYSTEM_INITIALIZED` once any admin exists; serializes concurrent first-admin attempts via an in-process promise chain. |
|
||||
| `SystemModule` | `backend/src/modules/system/system.module.ts` | `SystemController` (`/api/v1/bootstrap`, `/event/status`, SSE streams) + `SystemService`. |
|
||||
| `AdminModule` | `backend/src/modules/admin/admin.module.ts` | `AdminController` (`/api/v1/admin/users*`) + `AdminService`. Gated by `AdminGuard` + `@Roles('admin')`. |
|
||||
| `UploadsModule` | `backend/src/modules/uploads/uploads.module.ts` | `UploadsController` (`/api/v1/uploads/*`). Admin-only multipart. |
|
||||
@@ -37,7 +37,7 @@ also registers two global providers:
|
||||
|------------------------|-------------------------|--------------|--------------------------------------------------------------|
|
||||
| `AuthController` | `/api/v1/auth` | Mostly public (login, refresh, logout, csrf) | `backend/src/modules/auth/auth.controller.ts` |
|
||||
| `UsersController` | `/api/v1/auth/register-first-admin` | Public (bootstrap-only) | `backend/src/modules/users/users.controller.ts` |
|
||||
| `SetupController` | `/api/v1/setup/create-admin` | Public (bootstrap-only; 404 once an admin exists) | `backend/src/modules/setup/setup.controller.ts` |
|
||||
| `SetupController` | `/api/v1/setup/create-admin` | Public (bootstrap-only; 409 `SYSTEM_INITIALIZED` once an admin exists) | `backend/src/modules/setup/setup.controller.ts` |
|
||||
| `AdminController` | `/api/v1/admin` | Admin only | `backend/src/modules/admin/admin.controller.ts` |
|
||||
| `SystemController` | `/api/v1` | Public | `backend/src/modules/system/system.controller.ts` |
|
||||
| `UploadsController` | `/api/v1/uploads` | Admin only | `backend/src/modules/uploads/uploads.controller.ts` |
|
||||
|
||||
@@ -3,7 +3,7 @@ type: guide
|
||||
title: First-Run Bootstrap
|
||||
description: How a fresh HIPCTF instance is initialized by the very first administrator.
|
||||
tags: [guide, bootstrap, first-admin, onboarding, tester]
|
||||
timestamp: 2026-07-21T16:48:20Z
|
||||
timestamp: 2026-07-21T17:18:08Z
|
||||
---
|
||||
|
||||
# When this flow runs
|
||||
@@ -15,12 +15,15 @@ to create the very first admin user. This is gated by the
|
||||
| `initialized` | User experience |
|
||||
|---------------|---------------------------------------------------------------|
|
||||
| `false` | Every route is redirected to `/bootstrap` until an admin is created. |
|
||||
| `true` | The setup route becomes a 404 and the modal can never appear again. |
|
||||
| `true` | The setup endpoint becomes a 409 `SYSTEM_INITIALIZED` and the modal can never appear again. |
|
||||
|
||||
The `authGuard` enforces the redirect on the client side; the backend
|
||||
independently rejects `/api/v1/setup/create-admin` with `404 NOT_FOUND`
|
||||
once any admin row exists, so the flow is safe even if the SPA is
|
||||
bypassed.
|
||||
independently rejects `/api/v1/setup/create-admin` with
|
||||
`409 SYSTEM_INITIALIZED` once any admin row exists, so the flow is safe
|
||||
even if the SPA is bypassed. Concurrent first-admin requests are
|
||||
serialized inside the Nest process so that two simultaneous submissions
|
||||
cannot both succeed — the loser receives the same `SYSTEM_INITIALIZED`
|
||||
409 (see [Setup Endpoint — Concurrency](/api/setup.md)).
|
||||
|
||||
# How to access (tester steps)
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ scoreboard, an event window with a public countdown, theming, and admin
|
||||
controls.
|
||||
|
||||
The docs below are organized by purpose so agents can pull just the slice
|
||||
they need. Last regenerated 2026-07-21T16:48:20Z.
|
||||
they need. Last regenerated 2026-07-21T17:18:08Z.
|
||||
|
||||
# Architecture
|
||||
|
||||
|
||||
Reference in New Issue
Block a user