docs: update documentation to OKF v0.1 format
This commit is contained in:
@@ -12,6 +12,7 @@ timestamp: 2026-07-22T19:18:00Z
|
|||||||
|---|---|
|
|---|---|
|
||||||
| `backend/src/main.ts` | Bootstraps Nest, middleware, OpenAPI, static assets, and SPA fallback. |
|
| `backend/src/main.ts` | Bootstraps Nest, middleware, OpenAPI, static assets, and SPA fallback. |
|
||||||
| `backend/src/app.module.ts` | Wires feature modules and global providers. |
|
| `backend/src/app.module.ts` | Wires feature modules and global providers. |
|
||||||
|
| `backend/src/config/env.schema.ts` | Zod-validated runtime config; canonical defaults for `DATABASE_PATH` (`./data/db.sqlite`) and `UPLOAD_DIR` (`./data/uploads`). |
|
||||||
| `backend/src/database/database.module.ts` | Configures TypeORM with SQLite. |
|
| `backend/src/database/database.module.ts` | Configures TypeORM with SQLite. |
|
||||||
| `backend/src/database/database-init.service.ts` | Initializes the database and runs migrations; `verifySeed()` also asserts the canonical six system-category keys and reports missing/duplicate rows. |
|
| `backend/src/database/database-init.service.ts` | Initializes the database and runs migrations; `verifySeed()` also asserts the canonical six system-category keys and reports missing/duplicate rows. |
|
||||||
| `backend/src/database/migrations/1700000000400-RepairCategorySchemaAndSystemCategories.ts` | Forward-only repair migration: adds `created_at`/`updated_at` to legacy six-column `category` tables, deletes obsolete `FOR`/`OSI` system rows, rewrites canonical row metadata, inserts any missing canonical key, and re-asserts unique indexes. Exports `CANONICAL_SYSTEM_CATEGORIES`. |
|
| `backend/src/database/migrations/1700000000400-RepairCategorySchemaAndSystemCategories.ts` | Forward-only repair migration: adds `created_at`/`updated_at` to legacy six-column `category` tables, deletes obsolete `FOR`/`OSI` system rows, rewrites canonical row metadata, inserts any missing canonical key, and re-asserts unique indexes. Exports `CANONICAL_SYSTEM_CATEGORIES`. |
|
||||||
@@ -35,6 +36,10 @@ timestamp: 2026-07-22T19:18:00Z
|
|||||||
| File | Responsibility |
|
| File | Responsibility |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `frontend/src/main.ts` | Bootstraps Angular and registers HTTP interceptors. |
|
| `frontend/src/main.ts` | Bootstraps Angular and registers HTTP interceptors. |
|
||||||
|
| `frontend/proxy.conf.json` | Angular dev-server proxy: forwards `/api` and `/uploads` to `http://localhost:3000`. |
|
||||||
|
| `frontend/angular.json` | Angular workspace config; the `serve` target references `proxy.conf.json`. |
|
||||||
|
| `package.json` (root) | Root npm scripts; `dev` runs both workspaces via `concurrently`, `dev:backend` / `dev:frontend` run one at a time. |
|
||||||
|
| `setup.sh` | Idempotent setup: installs root + workspace deps, builds both packages, creates `./data/uploads`. |
|
||||||
| `frontend/src/app/app.routes.ts` | Defines public, shell, child, and admin routes. |
|
| `frontend/src/app/app.routes.ts` | Defines public, shell, child, and admin routes. |
|
||||||
| `frontend/src/app/core/services/bootstrap.service.ts` | Caches and exposes bootstrap state, refreshes it after admin updates, and applies the resolved theme. |
|
| `frontend/src/app/core/services/bootstrap.service.ts` | Caches and exposes bootstrap state, refreshes it after admin updates, and applies the resolved theme. |
|
||||||
| `frontend/src/app/core/services/bootstrap.types.ts` | Defines bootstrap/theme payload types and maps theme tokens to CSS custom properties. |
|
| `frontend/src/app/core/services/bootstrap.types.ts` | Defines bootstrap/theme payload types and maps theme tokens to CSS custom properties. |
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ Browser ──HTTPS──▶ NestJS process (PORT, default 3000)
|
|||||||
├── /api/v1/* ── controllers → services → TypeORM
|
├── /api/v1/* ── controllers → services → TypeORM
|
||||||
│ │
|
│ │
|
||||||
│ ▼
|
│ ▼
|
||||||
│ better-sqlite3
|
│ better-sqlite3
|
||||||
│ (DATABASE_PATH)
|
│ (DATABASE_PATH, default ./data/db.sqlite)
|
||||||
│
|
│
|
||||||
├── /api/docs, /api/docs-json ── Swagger UI (OpenAPI 3.1)
|
├── /api/docs, /api/docs-json ── Swagger UI (OpenAPI 3.1)
|
||||||
│
|
│
|
||||||
├── /uploads/* ── static file server (UPLOAD_DIR)
|
├── /uploads/* ── static file server (UPLOAD_DIR, default ./data/uploads)
|
||||||
│
|
│
|
||||||
└── /* ── SPA fallback (FRONTEND_DIST/index.html)
|
└── /* ── SPA fallback (FRONTEND_DIST/index.html)
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ timestamp: 2026-07-22T16:44:54Z
|
|||||||
|
|
||||||
# Purpose
|
# Purpose
|
||||||
|
|
||||||
Some persistent `/data/hipctf/db.sqlite` databases were created before
|
Some persistent HIPCTF databases (default path
|
||||||
|
[`./data/db.sqlite`](/database/schema.md)) were created before
|
||||||
the canonical six system categories existed. They contain a legacy
|
the canonical six system categories existed. They contain a legacy
|
||||||
six-column `category` table (no `created_at` / `updated_at`) and
|
six-column `category` table (no `created_at` / `updated_at`) and
|
||||||
system rows whose `system_key` / `abbreviation` no longer match the
|
system rows whose `system_key` / `abbreviation` no longer match the
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ timestamp: 2026-07-22T16:44:54Z
|
|||||||
|
|
||||||
HIPCTF uses **SQLite via better-sqlite3** with TypeORM migrations. The
|
HIPCTF uses **SQLite via better-sqlite3** with TypeORM migrations. The
|
||||||
database is a single file (`DATABASE_PATH`, default
|
database is a single file (`DATABASE_PATH`, default
|
||||||
`/data/hipctf/db.sqlite`) running in **WAL journal mode** for better
|
`./data/db.sqlite`, resolved relative to the process working directory)
|
||||||
concurrent read/write performance.
|
running in **WAL journal mode** for better concurrent read/write
|
||||||
|
performance.
|
||||||
|
|
||||||
The schema is created by a single migration
|
The schema is created by a single migration
|
||||||
(`backend/src/database/migrations/1700000000000-InitSchema.ts`) and seeded
|
(`backend/src/database/migrations/1700000000000-InitSchema.ts`) and seeded
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
---
|
||||||
|
type: guide
|
||||||
|
title: Local Development Workflow
|
||||||
|
description: How to run the backend and frontend together in development, including the root dev script, Angular dev-server proxy, and project-local data directory.
|
||||||
|
tags: [guide, dev, dev-server, proxy, concurrently, setup, tester]
|
||||||
|
timestamp: 2026-07-22T19:54:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Overview
|
||||||
|
|
||||||
|
The HIPCTF monorepo ships a single root command — `npm run dev` — that
|
||||||
|
boots the NestJS backend and the Angular dev server in parallel, with
|
||||||
|
the Angular dev server proxying `/api` and `/uploads` calls to the
|
||||||
|
backend on port 3000. All persistent runtime files (SQLite database,
|
||||||
|
uploaded icons / attachments / logos) live under the project-local
|
||||||
|
`./data/` directory.
|
||||||
|
|
||||||
|
# How to start the full stack (tester steps)
|
||||||
|
|
||||||
|
1. From the repository root, install workspace dependencies once:
|
||||||
|
```
|
||||||
|
npm ci
|
||||||
|
```
|
||||||
|
2. Start both servers in parallel:
|
||||||
|
```
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
This uses `concurrently` to run:
|
||||||
|
* `npm --workspace backend run start:dev` (NestJS watch mode on `http://localhost:3000`)
|
||||||
|
* `npm --workspace frontend run start` (Angular dev server on `http://localhost:4200`)
|
||||||
|
Process names `backend` and `frontend` are prefixed per output line.
|
||||||
|
If either process exits with a non-zero status, the other is killed
|
||||||
|
(`--kill-others-on-fail`).
|
||||||
|
3. Open the browser:
|
||||||
|
* **Frontend (preferred for app work):** `http://localhost:4200/`
|
||||||
|
* **Backend (single-port mode, serves built SPA later):** `http://localhost:3000/`
|
||||||
|
4. To run them individually during debugging:
|
||||||
|
```
|
||||||
|
npm run dev:backend
|
||||||
|
npm run dev:frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
# Project-local data directory
|
||||||
|
|
||||||
|
| Path | Purpose | Backed by env var |
|
||||||
|
|-------------------|-------------------------------------------------------|---------------------|
|
||||||
|
| `./data/` | Root runtime data directory (gitignored). | — |
|
||||||
|
| `./data/db.sqlite`| SQLite database file (created on first boot). | `DATABASE_PATH` |
|
||||||
|
| `./data/uploads/` | Uploaded category icons, challenge files, site logos. | `UPLOAD_DIR` |
|
||||||
|
|
||||||
|
Both defaults are declared in `backend/src/config/env.schema.ts` and
|
||||||
|
re-declared as fallbacks in every backend code path that calls
|
||||||
|
`ConfigService.get` so direct/unit construction cannot silently revert
|
||||||
|
to the legacy absolute paths. Relative paths are resolved with
|
||||||
|
`path.resolve` against the process working directory — when launched
|
||||||
|
via the root scripts, that is the repository root.
|
||||||
|
|
||||||
|
The legacy absolute defaults (`/data/hipctf/db.sqlite`,
|
||||||
|
`/data/hipctf/uploads`) have been removed; set `DATABASE_PATH` and
|
||||||
|
`UPLOAD_DIR` explicitly if you need to point at an external location
|
||||||
|
(e.g. a mounted volume in production).
|
||||||
|
|
||||||
|
The data directory is created automatically:
|
||||||
|
* `DatabaseModule` ensures the parent directory of `DATABASE_PATH`
|
||||||
|
exists before connecting.
|
||||||
|
* `main.ts`, `UploadsController`, `buildMulter`, and
|
||||||
|
`UploadsStaticMiddleware` all `mkdir -p` the upload directory on
|
||||||
|
startup.
|
||||||
|
* `setup.sh` creates `./data/uploads` before any build so first-boot
|
||||||
|
Multer writes never fail.
|
||||||
|
|
||||||
|
# Angular dev-server proxy
|
||||||
|
|
||||||
|
`frontend/proxy.conf.json` is wired into the `serve` target in
|
||||||
|
`frontend/angular.json` so relative URLs from the SPA hit the backend
|
||||||
|
without CORS prompts:
|
||||||
|
|
||||||
|
| Origin path | Target | Notes |
|
||||||
|
|-------------|-------------------------|--------------------------------------------------------|
|
||||||
|
| `/api` | `http://localhost:3000` | All REST controllers + SSE endpoints. `changeOrigin: true`. |
|
||||||
|
| `/uploads` | `http://localhost:3000` | Static files served by `UploadsStaticMiddleware`. |
|
||||||
|
|
||||||
|
The proxy is **development-only.** In production (`npm start` /
|
||||||
|
`backend/dist/main.js`) the backend serves the built SPA directly and
|
||||||
|
no proxy is involved.
|
||||||
|
|
||||||
|
# Root scripts
|
||||||
|
|
||||||
|
| Script | What it does |
|
||||||
|
|---------------------|--------------------------------------------------------------------|
|
||||||
|
| `npm run dev` | Start backend + frontend together via `concurrently`. |
|
||||||
|
| `npm run dev:backend` | Start only the NestJS backend in watch mode. |
|
||||||
|
| `npm run dev:frontend` | Start only the Angular dev server. |
|
||||||
|
| `npm start` | Run the **production** backend (`node backend/dist/main.js`). |
|
||||||
|
| `npm run build` | Build both workspaces (frontend first, then backend). |
|
||||||
|
| `npm run start:dev` | Alias for `npm run dev` (kept for backwards compatibility). |
|
||||||
|
| `npm test` | Run the full Jest project (backend + frontend). |
|
||||||
|
|
||||||
|
# Expected behavior (tester)
|
||||||
|
|
||||||
|
* `npm run dev` displays interleaved backend and frontend logs, each
|
||||||
|
prefixed with the process name and a color.
|
||||||
|
* The Angular dev server prints `Application bundle generation complete`
|
||||||
|
within a few seconds and the page is reachable at
|
||||||
|
`http://localhost:4200/`.
|
||||||
|
* Visiting `http://localhost:4200/` triggers
|
||||||
|
`GET /api/v1/bootstrap` (proxied to port 3000) and shows the
|
||||||
|
appropriate public, login, or bootstrap page.
|
||||||
|
* Uploads (e.g. category icons via the admin UI) land under
|
||||||
|
`./data/uploads/` and are immediately readable from the dev frontend
|
||||||
|
via `/uploads/...` (proxied).
|
||||||
|
* Pressing `Ctrl+C` once terminates both processes cleanly.
|
||||||
|
|
||||||
|
# See also
|
||||||
|
|
||||||
|
- [System Overview](/architecture/overview.md)
|
||||||
|
- [Database Schema Overview](/database/schema.md)
|
||||||
|
- [Uploads Endpoints](/api/uploads.md)
|
||||||
|
- [Key Files Index](/architecture/key-files.md)
|
||||||
+4
-1
@@ -11,7 +11,7 @@ scoreboard, an event window with a public countdown, theming, and admin
|
|||||||
controls.
|
controls.
|
||||||
|
|
||||||
The docs below are organized by purpose so agents can pull just the slice
|
The docs below are organized by purpose so agents can pull just the slice
|
||||||
they need. Last regenerated 2026-07-22T19:18:00Z.
|
they need. Last regenerated 2026-07-22T19:54:00Z.
|
||||||
|
|
||||||
# Architecture
|
# Architecture
|
||||||
|
|
||||||
@@ -80,6 +80,9 @@ they need. Last regenerated 2026-07-22T19:18:00Z.
|
|||||||
* [Cross-Tab Authenticated Shell Invalidation](/guides/cross-tab-invalidation.md) -
|
* [Cross-Tab Authenticated Shell Invalidation](/guides/cross-tab-invalidation.md) -
|
||||||
How a logout in one tab, or an unauthorized SSE response, instantly clears
|
How a logout in one tab, or an unauthorized SSE response, instantly clears
|
||||||
and redirects every other open tab of the SPA.
|
and redirects every other open tab of the SPA.
|
||||||
|
* [Local Development Workflow](/guides/dev-workflow.md) - How to run the
|
||||||
|
backend and frontend together (`npm run dev`), the Angular dev-server
|
||||||
|
proxy, and the project-local `./data/` directory.
|
||||||
* [Session Restoration on Reload](/guides/session-restoration.md) - How
|
* [Session Restoration on Reload](/guides/session-restoration.md) - How
|
||||||
the SPA keeps a user signed in across hard refreshes and how the
|
the SPA keeps a user signed in across hard refreshes and how the
|
||||||
guards wait for bootstrap + auth hydration before deciding where to
|
guards wait for bootstrap + auth hydration before deciding where to
|
||||||
|
|||||||
Reference in New Issue
Block a user