Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ roadmap. See each phase section below for status and issue links.
- [x] Docs site deployed — `docs/site/` (VitePress) via `.github/workflows/deploy-docs.yml`, live at https://docforum.github.io/docforum-core/. Unrelated to the production-deploy decision above; this is a static site with no backend of its own.
- [x] **PR conflict notifier** — `.github/workflows/pr-conflict-notifier.yml` + `.github/scripts/pr-conflict-notifier.cjs`. On every push to `main` (and every 3h) it labels open PRs that conflict with `main` as `needs-rebase` and @mentions the author once per push with rebase steps; the label clears itself when the conflict is resolved. Runs from `main` only and never checks out PR code.
- [x] **Load tests (k6)** — `backend/tests/load/` (`search.js`, `slots.js`, `booking-contention.js`), `backend/scripts/seed-load-test.mjs` (thousands of doctors + slots), and `.github/workflows/load-tests.yml` (manual/nightly, never against the shared Render preview). Thresholds enforce p95 latency on read paths and zero double-bookings; the contention scenario asserts correctness from the database afterwards (exactly one booking per slot), not just response codes. First results committed in `backend/tests/load/REPORT.md`.
- [ ] **Interactive API reference** — VitePress page backed by the generated OpenAPI document, with the narrative API table retained as an overview and a linked error catalogue. Tracked as [issue #134](https://github.com/DocForum/docforum-core/issues/134); blocked on the generator and checked-in spec from [issue #112](https://github.com/DocForum/docforum-core/issues/112).

## Explicitly deferred (not on this roadmap, tracked so they aren't forgotten)
- In-app video/voice consultation (PRD OQ-1 — v1 assumes in-person + async messaging).
Expand Down Expand Up @@ -507,4 +508,4 @@ roadmap. See each phase section below for status and issue links.
- 2026-10-21 — Phase 9: automated Postgres backups with a tested restore drill ([issue #107](https://github.com/DocForum/docforum-core/issues/107)): `scripts/backup-postgres.sh` (gpg-encrypted `pg_dump`, retention), `scripts/restore-drill.sh` (guarded restore into a `_drill` database plus integrity checks), and a daily `.github/workflows/backup-restore-drill.yml`. ADR 0007. No schema or endpoint changes, so `ARCHITECTURE.md` §4 and `docs/api/README.md` are untouched.
- 2026-10-20 — Fixed the backup drill shipped above, which had never run. `backup-restore-drill.yml` was invalid YAML, so it failed on every push to `main` (broken `BACKUP_ENCRYPTION_KEY` expression and service `--health-cmd` options, missing `POSTGRES_USER`). Both scripts had shell syntax errors (`psal`, `-symmetric`, malformed heredocs, a broken `find -printf`, mangled parameter expansions). Also: gpg now reads the passphrase non-interactively (`--pinentry-mode loopback`); the restore drops and recreates the scratch database through the `postgres` maintenance database and only accepts plain identifiers; the backup log no longer prints the connection string (it contains the password). Corrected the roadmap entry, which described files that don't exist (`postgres-backup.yml`, `restore-drill.mjs`, `age`, `docs/backups.md`). Separately, `tests/integration/sessions.test.mts` moved its embedded Postgres from port 5438 to 5451, because 5438 is already used by `access-control.test.mts` and vitest runs integration files in parallel.
- 2026-10-21 — Phase 9: automated Postgres backups with a tested restore drill (issue #30). Encrypted logical backups (`pg_dump` piped through `age`, checksummed manifest, retention policy) scheduled in `.github/workflows/postgres-backup.yml`; a restore script (`scripts/restore-drill.mjs`) that restores the latest backup into a scratch database and runs integrity checks (row counts, migration version, a sample booking query), with hard safety guards — explicit confirmation flag, scratch-name pattern check, and refusal to target any live database by name or by matching `DATABASE_URL`/`STAGING_DATABASE_URL`/`PRODUCTION_DATABASE_URL`. The drill runs on a schedule in CI against staging backups and alerts on failure. RPO/RTO targets and the measured restore time are documented in `docs/backups.md`. Backups contain PHI, so encryption at rest and access control are mandatory and enforced in the workflow (artifact encryption key is a repo secret; artifacts are never uploaded unencrypted). No schema or endpoint changes, so `ARCHITECTURE.md` §4 and `docs/api/README.md` are untouched.
- 2026-10-20 — Hardened the PR automation against transient GitHub API errors. Today a single 500/503 response aborted a whole conflict-notifier run, so no PR after it got labelled. Both `pr-conflict-notifier.yml` and `pr-malware-scan.yml` now set `retries: 3` on `actions/github-script`, so 5xx responses are retried. The notifier also isolates each PR: a PR whose API calls still fail is skipped with a warning, listed as "API error, retried next run" in the run summary, and the remaining PRs are processed normally.
- 2026-10-20 — Hardened the PR automation against transient GitHub API errors. Today a single 500/503 response aborted a whole conflict-notifier run, so no PR after it got labelled. Both `pr-conflict-notifier.yml` and `pr-malware-scan.yml` now set `retries: 3` on `actions/github-script`, so 5xx responses are retried. The notifier also isolates each PR: a PR whose API calls still fail is skipped with a warning, listed as "API error, retried next run" in the run summary, and the remaining PRs are processed normally.
4 changes: 4 additions & 0 deletions changelog.d/134-interactive-api-reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Adds a Scalar-powered interactive API reference and error catalogue to the
VitePress docs site. The site sync validates and copies the generated
OpenAPI document, and fails with a clear dependency message until issue
#112 provides it. This PR is a draft pending that generator.
10 changes: 9 additions & 1 deletion docs/api/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
# API docs

This table is a narrative overview. The generated OpenAPI document is the
source for the [interactive API reference](https://docforum.github.io/docforum-core/api/interactive)
and is validated and copied into the docs site at build time. Error codes
are collected in the [API error catalogue](https://docforum.github.io/docforum-core/api/errors).

Endpoints are grouped by module below. Which phases are built is tracked
in `ROADMAP.md`, not here. Keep this file in sync with
`backend/src/modules/*/routes` (AGENTS.md doc-update rule): when you add or
change an endpoint, add or edit its row in that module's table, and leave
the rest of the file alone.

Base URL: `http://localhost:4000` locally (`PORT` in `.env`). No OpenAPI spec yet — TBD, tracked informally, not blocking Phase 1.
Base URL: `http://localhost:4000` locally (`PORT` in `.env`). The OpenAPI
generator is tracked by [issue #112](https://github.com/DocForum/docforum-core/issues/112);
the docs-site integration depends on that generator and fails fast while the
generated `docs/api/openapi.json` is absent or invalid.

## Auth (`/auth`) — `backend/src/modules/auth`

Expand Down
8 changes: 7 additions & 1 deletion docs/site/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ node_modules/
/architecture/overview.md
/architecture/essentials.md
/architecture/adr/
/api/
!/api/
/api/*
!/api/interactive.md
!/api/ApiReference.vue
!/api/errors.md
/api/reference.md
/api/openapi.json
/roadmap/
/repos/web/readme.md
/repos/web/architecture.md
Expand Down
11 changes: 10 additions & 1 deletion docs/site/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,16 @@ export default defineConfig({
},
],

'/api/': [{ text: 'API', items: [{ text: 'Reference', link: '/api/reference' }] }],
'/api/': [
{
text: 'API',
items: [
{ text: 'Reference', link: '/api/reference' },
{ text: 'Interactive reference', link: '/api/interactive' },
{ text: 'Error catalogue', link: '/api/errors' },
],
},
],

'/roadmap/': [
{
Expand Down
18 changes: 18 additions & 0 deletions docs/site/api/ApiReference.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script setup>
import { ApiReference } from '@scalar/api-reference'
import '@scalar/api-reference/style.css'
import { withBase } from 'vitepress'

const configuration = {
spec: { url: withBase('/api/openapi.json') },
hideTestRequestButton: true,
hideClientButton: true,
theme: 'default',
}
</script>

<template>
<ClientOnly>
<ApiReference :configuration="configuration" />
</ClientOnly>
</template>
18 changes: 18 additions & 0 deletions docs/site/api/errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# API error catalogue

Errors use a stable `code` in addition to the HTTP status and human-readable
message. Clients should branch on `code`, not message text. The interactive
reference is generated from the OpenAPI document; endpoint responses should
link their documented error codes back to this catalogue.

| Code | Status | Meaning |
|---|---:|---|
| [`EMAIL_NOT_VERIFIED`](./reference#email-verification-phase-8-issue-34) | 403 | Verify the account email before using a protected write endpoint. |
| `INVALID_VERIFICATION_TOKEN` | 400 | The verification token is unknown, already used, or invalid. |
| `VERIFICATION_TOKEN_EXPIRED` | 400 | Request a fresh verification email. |
| `EMAIL_ALREADY_VERIFIED` | 409 | The account email is already verified. |
| `EMAIL_VERIFICATION_RATE_LIMITED` | 429 | Wait for the resend interval before requesting another email. |

This catalogue starts with the stable authentication and email-verification
codes currently documented by the API. Add a row in the same change whenever
a new public error code is introduced.
16 changes: 16 additions & 0 deletions docs/site/api/interactive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Interactive API reference

The reference below is rendered from the OpenAPI document generated from the
API's route definitions. The docs sync step validates that document and stops
the site build when it is missing or malformed, so a stale reference cannot
be published accidentally.

<ApiReference />

Endpoint error codes are collected in the [API error catalogue](/api/errors).
The reference is documentation only: request execution and API-client
downloads are disabled.

<script setup>
import ApiReference from './ApiReference.vue'
</script>
Loading
Loading