Files
ipodderx-rs/docs/users.md
rays 6114add4a6 Documentation: docs/, a changelog, and CLAUDE.md
PROGRESS.md becomes CHANGELOG.md with the finished step lists moved to an
appendix. The README is an overview pointing at docs/: configuration,
cli, users, sso (refreshed for accounts and admin-only settings), and
architecture. CLAUDE.md collects what working on this code actually
requires -- pkill -x not -f, the page being compiled in, the dead columns
on entries, the Playwright worker that deleted its own database.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AdXho5tTkjFLeUXKbEjKBh
2026-09-11 03:00:25 +00:00

3.4 KiB

Accounts, and what several people share

ipx serves any number of people from one copy of the data. The rule that decides everything else: there is one file on disk per enclosure URL. Two people subscribed to the same show cost one fetch, one parse and one file.

What is yours, what is everyone's

Yours alone The same for everyone
Read, starred, playback position The feed's URL
Which feeds you see at all Its download folder
Keywords, auto-download, explicit, per-scan cap When it is scanned
The file on disk

The right-hand column describes the feed and the file rather than a preference — two people wanting different folders would mean two copies. Those three are admin-only, and the API returns 403 for anyone else rather than merely hiding the controls.

How the scanner merges everyone's wants

One fetch serves every subscriber, so the policy is a union:

  • an item is downloaded if anyone wants it — one person's keyword set matching is enough, and one person with no keywords removes the filter for that feed entirely
  • auto-download is on if anyone has it on
  • the per-scan cap is the largest anyone asked for

So "auto-download off" means I don't cause downloads, not I never see them. If someone else's subscription pulls an item, you see it listed as downloaded and can play it, because the enclosure is shared.

Deleting

Deleting a file deletes everyone's copy. A feed with other subscribers labels the button Delete for everyone and names them in the confirmation, and the server has the last word: if anyone else has starred the item or not played it yet, DELETE /api/enclosures/{id} answers 409 with the reason, and only ?force=true goes through.

Retention follows the same rule: starred by anyone keeps a file, and it counts as read only once every subscriber has read it.

Signing in

Three ways, tried in order of how specific the claim is:

  1. A proxy header naming the user — Cloudflare Zero Trust or Authentik. Honoured only from an address in trusted_proxies. See sso.md.
  2. A session cookie from signing in at /login. Argon2id hashes, sessions in the database, idle timeout session_days.
  3. The shared [web] token, which signs in as the admin — this is what the Docker healthcheck and any scripts use.

A database with no accounts creates admin / ipodderx on the next daemon start and says so in the log. Change it:

echo -n 'a good password' | ipx user passwd admin

Adding someone

echo -n 'their password' | ipx user add sam

They sign in at /login and start with no feeds: subscriptions are per person. Adding a feed someone else already has costs nothing — no second fetch, no second copy — it just appears on their list with their own read state. Unsubscribing removes it from their list alone; only when the last subscriber leaves does the feed stop being scanned, and even then its files and history stay, so re-subscribing does not pull the back catalogue again.

Accounts are managed from the command line only; there is no user administration in the web UI yet.

Admin

The first account is an admin. An admin can change global settings (scanning interval, quota, retention, media types, download folder) and a feed's URL, folder and schedule. Everyone else gets the Settings button hidden and a 403 if they ask anyway.

ipx user list      # the admin column says who