AI Implementation feature(848): First-Start Create Admin Modal 1.07 (#10)
This commit was merged in pull request #10.
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
# Implementation Plan: Job 848 — First-Start Create Admin Modal 1.07
|
||||
|
||||
## Status
|
||||
|
||||
**[ALREADY_IMPLEMENTED]**
|
||||
|
||||
The First-Start Create Admin Modal feature is fully implemented end-to-end in
|
||||
this repository. The user-facing symptom reported in the job ("HIPCTF heading +
|
||||
'Frontend not built.' paragraph, no bootstrap dialog, no form controls, no
|
||||
submit button") is produced by the SPA fallback in
|
||||
`backend/src/frontend/spa.controller.ts:27` whenever
|
||||
`frontend/dist/browser/index.html` does not exist on disk at the moment
|
||||
the request is served.
|
||||
|
||||
That `dist/browser/index.html` is now present (rebuilt during the current
|
||||
session), so navigating to `http://localhost:3000/` will serve the Angular
|
||||
SPA, which redirects to `/bootstrap` and renders the create-admin modal.
|
||||
|
||||
No source code changes, no schema changes, and no new tests are required.
|
||||
|
||||
## 1. Architectural Reconnaissance
|
||||
|
||||
- **Codebase style & conventions:**
|
||||
- Monorepo with npm workspaces (`backend/`, `frontend/`).
|
||||
- Backend: NestJS controllers + services, TypeORM repositories,
|
||||
`@nestjs/config`, argon2 for password hashing, class-validator /
|
||||
`ZodValidationPipe` for input, `ApiError` + `GlobalExceptionFilter`
|
||||
for the uniform `{ code, message }` error envelope.
|
||||
- Frontend: Angular 17+ standalone components, `ChangeDetectionStrategy.OnPush`,
|
||||
Angular Signals, reactive forms (`ReactiveFormsModule`), HTTP via
|
||||
`HttpClient` with `withCredentials: true`, separate
|
||||
`BootstrapService` (initialised flag) and `AuthService` (session token).
|
||||
- Persistence: SQLite via TypeORM, file path comes from
|
||||
`process.env.DATABASE_PATH` (default `/data/hipctf/hipctf.db`),
|
||||
`FRONTEND_DIST` env var names the built SPA directory.
|
||||
- **Data Layer:** SQLite (TypeORM). No schema change is needed.
|
||||
- **Test Framework & Structure:**
|
||||
- Jest with two projects (`backend`, `frontend`) configured in
|
||||
`tests/jest.config.js`.
|
||||
- Backend tests use `ts-jest` against an in-memory SQLite DB
|
||||
(`process.env.DATABASE_PATH = ':memory:'`) via
|
||||
`tests/backend/db-helper.ts`.
|
||||
- Frontend tests use `jest-environment-jsdom` with
|
||||
`tests/frontend/jest.setup.ts` providing Angular `TestBed` +
|
||||
`provideHttpClientTesting`.
|
||||
- All tests live under `tests/` and run via a single root command:
|
||||
`npm test` (alias for `jest --config tests/jest.config.js`).
|
||||
- **Required Tools & Dependencies:** No new tools. Existing `npm run build`
|
||||
in `setup.sh` rebuilds `frontend/dist/browser/index.html`, which is the
|
||||
actual fix for the symptom. No new packages are required.
|
||||
|
||||
## 2. Impacted Files
|
||||
|
||||
- **To Modify:** None.
|
||||
- **To Create:** None.
|
||||
|
||||
### Where the feature already lives (for reference / verification)
|
||||
|
||||
Backend:
|
||||
- `backend/src/modules/setup/setup.module.ts`
|
||||
- `backend/src/modules/setup/setup.controller.ts` — `POST /api/v1/setup/create-admin`.
|
||||
- `backend/src/modules/setup/setup.service.ts:39-97` — `createAdmin()` inside a
|
||||
TypeORM transaction with serialized bootstrap via `runBootstrap()`
|
||||
(lines 99-130) — guarantees that two concurrent callers cannot both
|
||||
observe an empty admin table; the loser gets
|
||||
`409 SYSTEM_INITIALIZED`.
|
||||
- `backend/src/modules/setup/dto/create-admin.dto.ts`
|
||||
- `backend/src/common/errors/error-codes.ts` — `SYSTEM_INITIALIZED`,
|
||||
`USERNAME_TAKEN`, `WEAK_PASSWORD`, `VALIDATION_FAILED`, `RATE_LIMITED`.
|
||||
- `backend/src/frontend/spa.controller.ts:11-28` — SPA fallback that emits
|
||||
the placeholder HTML **only** when no built `index.html` is found.
|
||||
|
||||
Frontend:
|
||||
- `frontend/src/app/features/setup/setup-create-admin.component.ts` — the
|
||||
modal component (`data-testid="setup-submit"`, `setup-retry`, etc.).
|
||||
- `frontend/src/app/features/setup/setup-create-admin.component.html`
|
||||
- `frontend/src/app/features/setup/setup-create-admin.component.css`
|
||||
- `frontend/src/app/features/setup/setup-create-admin.service.ts` —
|
||||
`POST /api/v1/setup/create-admin` with CSRF preflight + error mapping.
|
||||
- `frontend/src/app/features/setup/setup-create-admin.validators.ts` —
|
||||
`passwordMatchValidator`.
|
||||
- `frontend/src/app/features/setup/setup-create-admin.field-errors.ts` —
|
||||
pure helpers `usernameError`, `passwordError`, `confirmError`.
|
||||
- `frontend/src/app/core/services/bootstrap.service.ts` — exposes
|
||||
`initialized()`, `markInitialized()`, and `passwordPolicy()`.
|
||||
- `frontend/src/app/core/services/auth.service.ts` — `setSession()` used
|
||||
on success.
|
||||
- `frontend/src/app/app.routes.ts` — `/bootstrap` route, guarded by
|
||||
`authGuard` which redirects to `/bootstrap` while `initialized() === false`.
|
||||
|
||||
Existing tests that already cover this Job:
|
||||
- `tests/backend/setup-create-admin.spec.ts`
|
||||
- `tests/backend/bootstrap.integration.spec.ts`
|
||||
- `tests/backend/registration-rate-limit.spec.ts`
|
||||
- `tests/backend/api-error.spec.ts`
|
||||
- `tests/frontend/setup-create-admin.spec.ts`
|
||||
- `tests/frontend/guard-bootstrap-race.spec.ts`
|
||||
- `tests/frontend/auth-restore.spec.ts`
|
||||
|
||||
## 3. Proposed Changes
|
||||
|
||||
No code changes. The only operational fix is to keep
|
||||
`frontend/dist/browser/index.html` in place.
|
||||
|
||||
If a fresh container runs without it, `setup.sh` already invokes
|
||||
`npm --workspace frontend run build` (line 11) which produces the Angular
|
||||
bundle under `frontend/dist/browser/index.html`. The
|
||||
`SpaFallbackMiddleware` looks for the file in both
|
||||
`frontend/dist/index.html` and `frontend/dist/browser/index.html`, so the
|
||||
standard build output is resolved without any extra wiring.
|
||||
|
||||
## 4. Test Strategy
|
||||
|
||||
No new tests. The relevant behaviour is already covered:
|
||||
|
||||
- **Backend:** `tests/backend/setup-create-admin.spec.ts` exercises
|
||||
`POST /api/v1/setup/create-admin` happy path + each documented error
|
||||
(`SYSTEM_INITIALIZED`, `USERNAME_TAKEN`, `WEAK_PASSWORD`,
|
||||
`VALIDATION_FAILED`, `RATE_LIMITED`).
|
||||
- **Backend concurrency:** the `runBootstrap()` chain in
|
||||
`SetupService` is what serializes concurrent first-admin requests;
|
||||
`tests/backend/bootstrap.integration.spec.ts` exercises the bootstrap
|
||||
endpoint end-to-end.
|
||||
- **Frontend:** `tests/frontend/setup-create-admin.spec.ts` covers the
|
||||
modal's reactive form, server-error states, retry button, and the
|
||||
post-success navigation. `tests/frontend/guard-bootstrap-race.spec.ts`
|
||||
covers the `authGuard` redirect race with `BootstrapService`.
|
||||
|
||||
Run the existing suite from the repo root with:
|
||||
|
||||
```
|
||||
npm test
|
||||
```
|
||||
|
||||
## 5. Why this is reported as "not built"
|
||||
|
||||
`SpaFallbackMiddleware` (`backend/src/frontend/spa.controller.ts:27`)
|
||||
sends:
|
||||
|
||||
```
|
||||
<!doctype html><html><body><h1>HIPCTF</h1><p>Frontend not built.</p></body></html>
|
||||
```
|
||||
|
||||
when neither `frontend/dist/index.html` nor `frontend/dist/browser/index.html`
|
||||
exists. The Angular CLI's `application` builder writes to
|
||||
`dist/browser/index.html`, so after `npm --workspace frontend run build`
|
||||
the file is present and the SPA is served. The reported symptom was a
|
||||
snapshot taken before the build artefact existed; rebuilding resolves it.
|
||||
Reference in New Issue
Block a user