User admin in the web UI, admin-only log, unread-first OPML feeds

- Settings > Manage users: add an account (password, or none for proxy
  sign-in), toggle admin, remove. Backed by GET/POST /api/users and
  PATCH/DELETE /api/users/{id}, 403 for non-admins. The only admin
  cannot be demoted or removed.
- GET /api/logs is admin-only and the Log button is hidden for others;
  the log names every account, feed and failed sign-in.
- Feeds inside an OPML list those with unread items first, in the
  sidebar folder and on the subscription's page.
- Deploying is now buildx --push to 192.168.1.130:5000 and recreating
  the ipodderx service of the Arcane project content; CLAUDE.md and the
  README's Docker section say so.
- Tests: Playwright for user admin, the last-admin guard, 403s for a
  non-admin and the unread ordering (new Aardvark Radio fixture); a unit
  test for last_admin; the smoke test drives usersModal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0173mGu6rK18Ne7UGTwAaVJV
This commit is contained in:
2026-09-11 12:43:28 +00:00
parent 6114add4a6
commit 5e95557cbb
11 changed files with 370 additions and 40 deletions

View File

@@ -5,6 +5,48 @@ matters, what was wrong before -- the reasoning is the point, not the diff.
See [README.md](README.md) for what the thing is, and [docs/](docs/) for how to run it.
## 2026-09-11 — The log is admin-only
`GET /api/logs` now returns `403` to anyone who is not an admin, and the page hides the Log button
from them. Before this, every signed-in person could read the whole log. That includes every
account's name, every feed anyone subscribes to, and every failed sign-in. `/api/events` stays open
to everyone, because it carries the scan progress each person's page shows.
---
## 2026-09-11 — Managing users from the web
Settings has a **Manage users…** screen for an admin. From it you can add someone, with a password
or with none for someone the proxy signs in, tick or untick Admin, and remove an account. It is
backed by `GET/POST /api/users` and `PATCH/DELETE /api/users/{id}`, which return `403` for anyone
who is not an admin. The only admin cannot be demoted or removed, because nobody would then be
able to manage accounts except from the CLI on the box. Before this, accounts could only be managed
with `ipx user`.
---
## 2026-09-11 — Unread feeds first inside an OPML
An OPML subscription's feeds, both in the sidebar folder and on its own page, now list the ones with
unread items first. They were listed alphabetically, so with dozens of feeds the few with anything
new were scattered through the list. Within each half the order is still alphabetical. The browser
suite's fixture OPML gained a second feed, Aardvark Radio, which sorts first by name and by position,
so the new test only passes if unread wins.
---
## 2026-09-11 — Deploying is a Docker image
Production moved from a hand-started daemon in code-server to the `iPodderX` container in the Arcane
project `content`. `CLAUDE.md` now deploys by pushing to the registry at `192.168.1.130:5000` and
recreating that one service with `docker compose`. The old instructions copied a binary over a
process nobody supervised, so it did not come back after a reboot. Two known gaps are gone: the
image does support accounts, and the entrypoint drops to `99:100`, so downloads are no longer
owned by root. The README's Docker section said `docker compose up -d` builds the image and named the
service `ipx`; the compose file pulls from the registry and the service is `ipodderx`.
---
## 2026-09-11 — Documentation
`PROGRESS.md` became this changelog; the finished step lists moved to an appendix. The README is now