v0.6.15: admin-editable storage quotas + S3 usage reporting (#178) #203

Merged
Cordy merged 6 commits from ship-v0.6.15 into main 2026-08-12 04:46:47 +00:00
Owner

For review before deploy (not merged/tagged yet, per checkpoint).

Implements #178: usage visibility + per-user and instance caps that admins edit from the UI and that persist.

Backend

  • S3/Garage Usager (internal/storage/s3/usage.go): Used summed on demand over a flat bucket listing, cached ~60s. Object stores have no capacity, so Total/Free are left for the quota layer to fill.
  • quota decorator now reads limits live (quota.go): SetLimits(getter) (same pattern as SetRetention); the per-user + instance caps come from the settings store at write time. Config quotas remain the seed/default. Usage() overlays the instance allowance as Total when the backend reports none (POSIX real capacity is only tightened, never inflated). New UserUsage(user) exposes the existing per-user tree-walk.
  • Always constructed in main.go now (previously skipped when config quotas were empty) so settings-driven caps enforce with no restart.
  • settings store gains quotaPerUserBytes + quotaInstanceBytes (admin-editable, persisted in the encrypted state-backend, validated non-negative).
  • GET /api/v1/quota: instance figures to admins only; per-user figures (used + limit) to everyone.

Frontend (Cairn's existing dialog/.field system, no new visual language)

  • Admin → Settings: "Storage limits" — per-user quota (GB) + instance allowance (GB) inputs, saved through the existing settings PUT; plus an instance Usage row on the storage card (used / allowance).
  • Every user → account menu: a quiet "Storage: X of Y" (or "X used") line from /quota.

Semantics

  • 0 = no limit on either axis. Enabling a cap on an already-over instance blocks new writes (over-quota error) but never deletes.
  • Per-user cap charges the /home/<user> tree (ciphertext bytes under encryption); instance cap charges the whole bucket.

go vet, full go test ./... (incl. updated /quota tests), node-check, dual-arch build all green.

To try after deploy: set per-user + instance GB in Settings; upload past a cap → visible "quota exceeded"; every user sees their line in the account menu. Nothing merges/deploys until you say go.

**For review before deploy** (not merged/tagged yet, per checkpoint). Implements #178: usage visibility + per-user and instance caps that admins edit from the UI and that persist. ### Backend - **S3/Garage `Usager`** (`internal/storage/s3/usage.go`): `Used` summed on demand over a flat bucket listing, cached ~60s. Object stores have no capacity, so `Total/Free` are left for the quota layer to fill. - **quota decorator now reads limits live** (`quota.go`): `SetLimits(getter)` (same pattern as `SetRetention`); the per-user + instance caps come from the settings store at write time. Config quotas remain the seed/default. `Usage()` overlays the instance allowance as `Total` when the backend reports none (POSIX real capacity is only tightened, never inflated). New `UserUsage(user)` exposes the existing per-user tree-walk. - **Always constructed** in `main.go` now (previously skipped when config quotas were empty) so settings-driven caps enforce with no restart. - **settings store** gains `quotaPerUserBytes` + `quotaInstanceBytes` (admin-editable, persisted in the encrypted state-backend, validated non-negative). - **`GET /api/v1/quota`**: instance figures to admins only; per-user figures (used + limit) to everyone. ### Frontend (Cairn's existing dialog/`.field` system, no new visual language) - **Admin → Settings**: "Storage limits" — per-user quota (GB) + instance allowance (GB) inputs, saved through the existing settings PUT; plus an instance **Usage** row on the storage card (used / allowance). - **Every user → account menu**: a quiet "Storage: X of Y" (or "X used") line from `/quota`. ### Semantics - `0` = no limit on either axis. Enabling a cap on an already-over instance blocks *new* writes (over-quota error) but never deletes. - Per-user cap charges the `/home/<user>` tree (ciphertext bytes under encryption); instance cap charges the whole bucket. `go vet`, full `go test ./...` (incl. updated `/quota` tests), node-check, dual-arch build all green. **To try after deploy:** set per-user + instance GB in Settings; upload past a cap → visible "quota exceeded"; every user sees their line in the account menu. Nothing merges/deploys until you say go.
ci: scout main.go quota construction (temp)
All checks were successful
scout / scout (push) Successful in 1s
259f4ce5e1
ci: v0.6.15 edit script (#178 quotas + S3 usage)
All checks were successful
scout / scout (push) Successful in 1s
151e48cf44
ci: v0.6.15 ship workflow (#178)
Some checks failed
ship-v0615 / ship (push) Failing after 29s
55fd50830e
ci: v0.6.15 test-fix supplement (quota_test new contract)
Some checks failed
ship-v0615 / ship (push) Has been cancelled
a24b52c3d5
ci: run quota_test supplement + self-remove it
All checks were successful
ship-v0615 / ship (push) Successful in 37s
f729bce51d
v0.6.15: admin-editable storage quotas + S3 usage reporting (#178)
All checks were successful
ci / test-and-build (pull_request) Successful in 34s
3c9f3bf0a2
Cordy merged commit c93898b4f0 into main 2026-08-12 04:46:47 +00:00
Cordy deleted branch ship-v0.6.15 2026-08-12 04:46:49 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#203
No description provided.