Add media storage limits, retention, and the near-limit flow

This commit is contained in:
Fisto
2026-09-16 08:49:42 +02:00
parent 6b961ddcef
commit 8f3f153c55
15 changed files with 394 additions and 12 deletions
+8 -3
View File
@@ -1,8 +1,8 @@
# Media archive
Status: design approved 2026-09-16. The engine, the slopbot backend, the `scrape media` command,
and the `/api/media/*` routes are implemented (C3-C5). The Media and Bot tabs are C6. Checkpoints
live in [CURRENT.md](../CURRENT.md).
the `/api/media/*` routes, and storage limits with retention are implemented (C3-C7a). The Media
and Bot tabs are C6; the Settings group is C7b. Checkpoints live in [CURRENT.md](../CURRENT.md).
The media archive saves the media history of a channel. A trusted user runs `scrape media` in the
channel. The daemon walks the history through a scrape backend and indexes every image, GIF,
@@ -101,12 +101,17 @@ The storage limit covers everything under the DB root: databases, downloads, and
Behavior:
1. At or above the warn threshold, a new `scrape media` command is refused and the reply shows the
usage. Re-running the same command accepts. The confirmation lives for a short window.
usage. Re-running the same command within 2 minutes accepts. The API mirror is `confirm: true`
on `POST /api/media/scrape` (otherwise `409 MEDIA_LIMIT`).
2. At or above 100% the oldest completed scrapes are marked `pending-delete`.
3. Above limit + 5% overrun, marked scrapes are deleted oldest first until the usage fits.
4. No data is deleted inside the 5% overrun band. The hover info (small `i` beside the limit field)
explains this.
The planning is a pure function (`media-scrape/src/retention.ts`) with tests. Only `done`,
`failed`, and `paused` scrapes are ever marked; a running scrape is untouched. Deletion removes the
scrape directory and forgets it in the engine.
**Clean media** in Settings lists exactly what will be deleted, with sizes and counts, and states
that deletion is irreversible. The delete button is disabled for a 5 second countdown.
+3 -1
View File
@@ -249,8 +249,10 @@ replaceable.
| GET | `/api/media` | `kind?`, `limit?`, `offset?` | Media items across every scrape, newest first |
| GET | `/api/media/scrapes` | none | Every scrape with state and counters |
| GET | `/api/media/status` | none | Slopbot connection state and the scrape list |
| POST | `/api/media/scrape` | `channelId`, `guildId?`, `mode?` | Start a media scrape |
| GET | `/api/media/storage` | none | Usage against the limit, per-kind sizes, `nearLimit`; marks old scrapes when over |
| POST | `/api/media/scrape` | `channelId`, `guildId?`, `mode?`, `confirm?` | Start a media scrape. Near the limit: `409` with code `MEDIA_LIMIT` unless `confirm: true` |
| POST | `/api/media/scrape/stop` | `id` | Stop a media scrape |
| POST | `/api/media/clean` | `ids?` | Delete the given scrapes, or every scrape when `ids` is absent |
| GET | `/api/logs` | `limit` | The persistent action log |
| GET | `/api/events` | none | Server-sent events |