docs: update documentation to OKF v0.1 format
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
---
|
||||
type: database
|
||||
title: Challenge Tables
|
||||
description: category, challenge, challenge_file, and solve tables — how CTF challenges and scoring are stored.
|
||||
tags: [database, challenge, category, solve]
|
||||
timestamp: 2026-07-21T14:18:00Z
|
||||
---
|
||||
|
||||
# Tables
|
||||
|
||||
## `category`
|
||||
|
||||
| Column | Type | Description |
|
||||
|----------------|---------|------------------------------------------------------------------------------|
|
||||
| `id` | TEXT PK | UUID v4. |
|
||||
| `system_key` | TEXT | One of `crypto`, `forensics`, `pwn`, `web`, `misc`, `osint` (unique where NOT NULL) or `NULL` for user-created categories. |
|
||||
| `name` | TEXT | Display name (e.g. `Cryptography`). |
|
||||
| `abbreviation` | TEXT | Short label (e.g. `CRY`). |
|
||||
| `description` | TEXT | Optional description. |
|
||||
| `icon_path` | TEXT | Default icon URL (e.g. `/uploads/icons/crypto.svg`). |
|
||||
|
||||
The seed migration inserts one row per `SYSTEM_CATEGORY_KEYS` value from
|
||||
`backend/src/config/env.schema.ts`.
|
||||
|
||||
## `challenge`
|
||||
|
||||
| Column | Type | Description |
|
||||
|-------------------|----------|-----------------------------------------------------------------------------------|
|
||||
| `id` | TEXT PK | UUID v4. |
|
||||
| `name` | TEXT | Display name. |
|
||||
| `description_md` | TEXT | Markdown description. |
|
||||
| `category_id` | TEXT | FK → `category.id`. |
|
||||
| `difficulty` | TEXT | `'low'` / `'med'` / `'high'`. |
|
||||
| `initial_points` | INTEGER | Starting point value. |
|
||||
| `minimum_points` | INTEGER | Floor after decay. |
|
||||
| `decay_solves` | INTEGER | Number of solves at which decay reaches the minimum. |
|
||||
| `flag` | TEXT | Submission string expected from players. |
|
||||
| `protocol` | TEXT | `'nc'` (netcat-style connection) or `'web'` (browser-based). |
|
||||
| `port` | INTEGER | TCP port when relevant (nullable). |
|
||||
| `ip_address` | TEXT | IP the challenge listens on (defaulted from `setting.defaultChallengeIp`). |
|
||||
| `created_at` | TEXT | ISO 8601 timestamp. |
|
||||
|
||||
## `challenge_file`
|
||||
|
||||
| Column | Type | Description |
|
||||
|---------------------|---------|--------------------------------------|
|
||||
| `id` | TEXT PK | UUID v4. |
|
||||
| `challenge_id` | TEXT | FK → `challenge.id`. |
|
||||
| `original_filename` | TEXT | Filename from upload. |
|
||||
| `stored_path` | TEXT | Path on disk under `UPLOAD_DIR/challenges/`. |
|
||||
|
||||
## `solve`
|
||||
|
||||
| Column | Type | Description |
|
||||
|------------------|---------|----------------------------------------------------------------------|
|
||||
| `id` | TEXT PK | UUID v4. |
|
||||
| `challenge_id` | TEXT | FK → `challenge.id`. |
|
||||
| `user_id` | TEXT | FK → `user.id`. |
|
||||
| `solved_at` | TEXT | ISO 8601 timestamp the solve was recorded. |
|
||||
| `points_awarded` | INTEGER | Points actually awarded (after decay). |
|
||||
| `base_points` | INTEGER | Snapshot of `challenge.initial_points` at solve time. |
|
||||
| `rank_bonus` | INTEGER | Extra points from rank (e.g. first-blood). |
|
||||
|
||||
Uniqueness is enforced by `uq_solve_challenge_user` on
|
||||
`(challenge_id, user_id)` — a user can solve a given challenge only once.
|
||||
|
||||
# Scoring formula
|
||||
|
||||
`points_awarded = clamp(initial_points - decay, minimum_points, initial_points)`
|
||||
where `decay = max(0, base_points - minimum_points) * solvesBefore / decay_solves`,
|
||||
and additional `rank_bonus` may be added for early solves.
|
||||
|
||||
(The exact scoring algorithm lives in the future solve-recording service
|
||||
and is consumed by `SseHubService` whenever a new solve is published.)
|
||||
|
||||
# See also
|
||||
|
||||
- [Database Schema Overview](/database/schema.md)
|
||||
- [System Endpoints](/api/system.md) (SSE scoreboard stream)
|
||||
- [Scoreboard Stream](/guides/scoreboard-stream.md)
|
||||
Reference in New Issue
Block a user