M3: server core API (E-3 to E-30, E-33), landing page, pictures, rate limiting, recurring generation, bootstrap and pair-device

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 22:00:58 +02:00
parent 6dce4c73a9
commit 7869ec48d8
38 changed files with 7623 additions and 141 deletions
+8 -5
View File
@@ -51,15 +51,15 @@ database is then `$KVITT_DATA_DIR/kvitt.sqlite`. Every connection uses WAL, `for
| `serve` | Works: migrations, `tasks::start`, HTTP server; SIGTERM drains in-flight requests for up to 10 s. | 0 on clean shutdown |
| `migrate` | Works: migrations only. | 0 |
| `healthcheck` | Works: `GET http://127.0.0.1:<port of KVITT_BIND>/health`, used by the compose healthcheck (no curl in the image). | 0 if 200, else 1 |
| `bootstrap` | Prints `not implemented in M2a` (M3). | 2 |
| `pair-device --user <user_id>` | Prints `not implemented in M2a` (M3). | 2 |
| `bootstrap` | Works (M3): cancels a pending `admin_setup` invite, prints a new code, link and expiry; `already initialized` on stderr when users exist. | 0 ok, 2 already initialized |
| `pair-device --user <user_id>` | Works (M3): prints a `device` invite for the user like `bootstrap`. | 0 ok, 3 unknown user |
| `rotate-epoch` | Prints `not implemented in M2a` (M4). | 2 |
## HTTP API
Every route of SPEC §7 is registered in `src/router.rs`. `GET /health` (E-1) and `GET /setup/status` (E-2) are
implemented; every other handler returns 501 `not_implemented` until M3 (E-3 to E-30, E-33) and M4 (E-31, E-32)
fill in the body in their own `src/api/*.rs` file. The rules of SPEC §14.3.1 are layers in `router.rs`:
implemented by M2a, E-3 to E-30 and E-33 by M3; E-31 and E-32 return 501 `not_implemented` until M4 fills in
`src/api/sync.rs`. The rules of SPEC §14.3.1 are layers in `router.rs`:
`X-Kvitt-Protocol: 1` on authenticated routes (426 otherwise, checked before the token), `X-Kvitt-Server-Version`
on every response, body limits 1 MiB / 5 MiB for `PUT /me/picture`, JSON 404 for unknown paths.
@@ -81,7 +81,10 @@ the wire contract makes `tests/openapi_contract.rs` fail against `contracts/open
## Seams for M3, M4 and M9 (SPEC §6.3, D-015)
* **Rate limit (M3):** `src/api/rate_limit.rs` returns the layer that `router.rs` attaches on the line marked
`// M3: the rate limiter …`. In M2a it is the identity layer.
`// M3: the rate limiter …` (SPEC §8.6, AC-2.12; per-IP limits need `ConnectInfo<SocketAddr>` from `serve`).
* **Recurring generation (M3, for M4's scheduler):** `api::recurring::generate_due_periods(&AppState, template_id)`
generates the due periods of one template (SPEC §9.5); `api::recurring::generate_all_due(&AppState)` runs it for
every non-deleted, non-paused template.
* **Background tasks (M4):** `src/tasks/mod.rs` has `pub async fn start(state: AppState) -> Result<(), AppError>`,
called once by `serve` after migrations. In M2a it starts nothing.
* **Audit (`src/audit/mod.rs`, M4 implements, M3 and M9 call):**