Thesis

A tour of the Wisp admin

3 min read
Guides

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 :scheduled and the ScheduledPublish Oban cron publishes it when the time passes.
  • Revisions — every save snapshots a revision (last 25 per post), with reversible restore and diffs.
  • Trash / soft-deletetrash_post sets deleted_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.