The Wisp admin is a Phoenix LiveView write surface at /admin. Here is what each area
does. Items marked (manager-only) are visible to owners and admins, hidden from
authors and contributors — and the page mounts also re-check authorization server-side, so
a direct URL is blocked too.
Visible to all staff
- Dashboard (
/admin) — post/page/comment/member counts, an activity sparkline, top posts, recent comments, and a quick-draft form. - Posts (
/admin/posts) — the post list and CRUD. This is where scheduling, revisions, trash, and bulk actions surface (see below). - Pages (
/admin/pages) — static-page CRUD. - Categories (
/admin/categories) — category CRUD, with a post-count column. - Menu (
/admin/menu) — the navigation menu builder (custom links + page/category items, reorderable). - Members (
/admin/members) — the member/subscriber list: email, tier, newsletter status, join date. (This view is read-only — there is no upgrade/cancel UI yet.) - Comments (
/admin/comments) — the moderation queue. Moderation is a state machine (auto_approve/hold/spam); spam (blocklist match) is never auto-approved or notified. - Media (
/admin/media) — file upload + library, with search/filter and conservative orphan cleanup (only unreferenced assets are deleted). - Trash (
/admin/trash) — soft-deleted posts/pages/comments, with restore and permanent delete. - Settings (
/admin/settings) — site config (see the configuration guide). - Pulse (
/admin/pulse) — analytics/pageview trends, plus the live MRR + subscriber ticker and newsletter send progress. - Editor (
/admin/editor) — the post/page body authoring surface: rich text + Markdown with a live preview, plus the visibility selector (public/members/paid), scheduling, the feature/sticky toggle, password protection, SEO overrides, and co-author picker.
Manager-only
- Users (
/admin/users) — staff management: invite, change role, deactivate. Roles are owner, admin, author, and contributor. A contributor is the least-privileged role: they may create, edit, and submit for review their own posts, but can never publish or manage staff. Owner is bootstrap-only and never invitable, and the last owner can't be demoted. - Series (
/admin/series) — ordered post collections ("Part N of M"). Series nav is gating-safe: members/paid/password-protected/draft/trashed posts are excluded. - Redirects (
/admin/redirects) — 301/302 rules, loop-safe and trailing-slash tolerant. - Audit Log (
/admin/audit-log) — an append-only trail of sensitive actions (settings changes, staff role changes, publish/trash, redirect CRUD). It stores action metadata and changed keys only — never secrets or field values. - Appearance (
/admin/appearance) — accent color, heading font, custom CSS. - Import / Export (
/admin/import-export) — transactional backup/restore of full site state (members are not exported — that's PII).
Post lifecycle tools
These live around the Posts list and Editor:
- Scheduling — set a future publish time; status becomes
:scheduledand theScheduledPublishOban cron publishes it when the time passes. - Revisions — every save snapshots a revision (last 25 per post), with reversible restore and diffs.
- Trash / soft-delete —
trash_postsetsdeleted_at; the row vanishes from every public + gating-safe surface but can be restored. Permanent delete is manager-only. - Bulk actions — trash or set-status across many posts in one transaction, each item re-checked per role (bulk publish/draft is reviewer-only).
- Duplicate — clone a post into a fresh draft owned by the acting staff; the source is untouched.
- Pending review — a contributor submits their own post for review; a reviewer (owner/admin/author) publishes it.
The contributor workflow
Worth calling out because of the role gate: a contributor creates and edits their own
posts and submits them for review (:pending_review, treated exactly like a draft on every
public surface). They cannot publish — even crafting the publish event directly is rejected
server-side. A reviewer approves and publishes.
That's the whole admin. For deployment see the Fly.io guide, for knobs see the configuration guide, and for the membership story see the paid-memberships post.