§0 item 8 (Phase-4 item 1 pulled forward, user directive: maintenance
tooling ships WITH the features it maintains):
- /admin/podcasts (AdminMiddleware): every feed from EVERY user via the
RLS admin escape (first-admin identity, poller/fetcher contract) —
feed + host, library, subscriber count/names, downloaded/total, DISK
USAGE, last fetch. Sorted disk DESC ('what's eating the disk'),
totals header (feeds · episodes · bytes on disk).
- Per-feed actions: Refresh · Delete files (rows → pending, disk freed;
confirms spell out the re-materialization contract) · Remove feed
(rows + files for everyone — the same admin delete as the detail
page). All confirms ride the global confirm modal.
- New sqlc: ListAllPodcastFeedsAdmin (correlated aggregates),
ResetPodcastEpisodeFileDeleted / ResetPodcastFeedFilesDeleted —
downloaded rows reset to pending with download-derived facts cleared
(audio_metadata, chapter_count, cover, size, mime); file_path KEPT
(fetch-maintained layout — a re-download lands on the same path).
file deletion via the existing DeleteFeedFiles file-removal pattern
(episode files + .cover.jpg siblings).
- Poll upsert never touches download_state, so deleted files STAY
deleted — a feed refresh re-lists metadata but re-materializes
nothing (pinned by TestAdminDeleteEpisodeFiles).
- Per-episode admin delete-file: POST /feeds/:id/episodes/:eid/
delete-file (admin) — one episode's file gone, row pending, siblings
untouched; HX swaps the episode list. (Found while testing: the
handler first read c.Param("id") — the FEED's uuid — instead of
:eid; the 404 'episode not found' trail led straight to it.)
- Tests: admin sees other users' feeds + subscriber names; regular
users 403 on page AND actions; single + feed-level deletion reset
rows/clear facts/delete files; refresh leaves pending rows pending.
- Admin nav gains 'Podcasts' under Administration.
Wrong-gotcha note for future agents: parseUUID on c.Param('id') inside
a /feeds/:id/episodes/:eid route resolves the FEED, not the episode.