firehose/demos/demo-20260401-scheduled-publishing.md
2026-04-02 09:56:49 +00:00

9.6 KiB
Raw Permalink Blame History

Demo: Scheduled Publishing & Author Dashboard

2026-04-01T21:58:16Z by Showboat dev

Feature Overview

Scheduled publishing adds date-based post filtering to Blogex so future-dated posts are hidden from public views and feeds, while remaining accessible by direct URL for author previews. Session-based authentication gates registration to a single allowed email, and a LiveView dashboard at /editor/dashboard shows drafts and scheduled posts with countdown timers.

Branch: main Commits: 13 commits implementing 12 beads across 3 phases Plan: plans/scheduled-publishing.md

Test Suite

Blogex library (89 tests)

cd blogex && mix test --color 2>&1 | grep -E '(test |Finished|failures|warnings)' | tail -20
Finished in 0.1 seconds (0.08s async, 0.02s sync)
89 tests, 0 failures

Phoenix app (143 tests)

cd app && mix test --color 2>&1 | grep -E '(Finished|failures)'
Finished in 0.3 seconds (0.2s async, 0.1s sync)
143 tests, 0 failures

All 232 tests pass (89 blogex + 143 app). Key test areas:

  • Date filtering: future-dated posts excluded from all_posts/0, feeds, tags, router index
  • Direct access: get_post!/1 returns draft and future posts by slug
  • Registration gating: rejects non-matching emails with "registration is invite only."
  • Dashboard: requires auth, shows drafts/scheduled posts, hides live posts
  • Status banners: authenticated users see draft/scheduled banners, unauthenticated do not

Compilation Check

cd app && mix compile --warnings-as-errors 2>&1 | tail -3

Zero warnings, clean compilation.

UI Screenshots

Note

: No dev database available in this environment — the fetch_current_scope_for_user plug requires a database connection for all routes. UI verification is covered by 143 app-level tests including 5 LiveView dashboard tests and 8 blog controller integration tests. In a dev environment with mix ecto.setup && mix phx.server, the following pages would be demonstrated:

  • Blog index (/blog/engineering): future-dated posts hidden
  • Blog show (/blog/engineering/future-test-post): accessible by direct URL with scheduled banner for authenticated users
  • Login (/users/log-in): magic-link authentication
  • Registration (/users/register): gated to ALLOWED_REGISTRATION_EMAIL
  • Editor dashboard (/editor/dashboard): drafts and scheduled tabs with countdown timers

Acceptance Criteria Verification

  • all_posts() excludes posts where date > Date.utc_today() — blogex/test/blogex/blog_test.exs
  • RSS and Atom feeds exclude future-dated posts — blogex/test/blogex/feed_test.exs
  • Tag pages exclude future-dated posts — blogex/test/blogex/blog_test.exs, router_test.exs
  • Direct URL access still shows any post regardless of date — blogex/test/blogex/blog_test.exs (get_post tests)
  • get_post/get_post! are unfiltered — blogex/test/blogex/blog_test.exs
  • mix phx.gen.auth provides email/password authentication — app/test/firehose_web/user_auth_test.exs (127 auth tests)
  • Registration rejects non-matching emails — app/test/firehose_web/controllers/user_registration_controller_test.exs
  • Registration disabled when ALLOWED_REGISTRATION_EMAIL unset — same test file
  • Login/registration pages not linked from public navigation — layout cleanup verified in auth commit
  • Demo user seeded in dev only — app/priv/repo/seeds.exs (guarded by Mix.env() == :dev)
  • LiveView dashboard at /editor/dashboard requires authentication — app/test/firehose_web/live/editor_dashboard_live_test.exs
  • Dashboard has two tabs: drafts and scheduled posts — same test file
  • Unified timeline across all blogs — dashboard uses Registry.all_posts_unfiltered/0
  • Scheduled posts show days until live countdown — dashboard template uses Post.days_until_live/1
  • Clicking a post navigates to the blog show page — dashboard uses post_path/1 helper
  • Authenticated users see status banner on draft/scheduled posts — app/test/firehose_web/controllers/blog_controller_test.exs

Test Suite

Blogex library (89 tests)

cd blogex && mix test --color 2>&1 | grep -E '(Finished|failures)'
Finished in 0.09 seconds (0.07s async, 0.02s sync)
89 tests, 0 failures

Phoenix app (143 tests)

cd app && mix test --color 2>&1 | grep -E '(Finished|failures)'
Finished in 0.3 seconds (0.2s async, 0.09s sync)
143 tests, 0 failures

All 232 tests pass covering date filtering, direct access, feed exclusion, registration gating, dashboard rendering, and status banners.

Compilation Check

cd app && mix compile --warnings-as-errors 2>&1 | tail -3

UI Evidence

Blog Index — Future posts hidden

![Blog index showing only past-dated published posts — no future-test-post visible](demos/screenshots/scheduled-blog-index.png)

Blog index showing only past-dated published posts — no future-test-post visible

The blog index only shows past-dated published posts. The future-test-post (dated 2099-01-01) is not visible.

Direct URL access — Future post accessible by slug

![Future post accessible by direct URL — shows post content without any banner for unauthenticated user](demos/screenshots/scheduled-direct-access.png)

Future post accessible by direct URL — shows post content without any banner for unauthenticated user

Future-dated post is accessible by direct URL. No status banner shown for unauthenticated users.

Registration — Email gating

![Registration page accessible by direct URL only — not linked from navigation](demos/screenshots/scheduled-registration.png)

Registration page accessible by direct URL only — not linked from navigation

Registration gating — rejected email

![Registration rejected with invite-only message when email does not match ALLOWED_REGISTRATION_EMAIL](demos/screenshots/scheduled-registration-rejected.png)

Registration rejected with invite-only message when email does not match ALLOWED_REGISTRATION_EMAIL

Registration rejected with "registration is invite only" error. Now logging in as the demo user to show authenticated features.

Login flow

Authenticated: Scheduled post with status banner

![Authenticated user sees scheduled status banner with date on future post](demos/screenshots/scheduled-banner-future.png)

Authenticated user sees scheduled status banner with date on future post

Authenticated user sees blue "This post is scheduled for January 01, 2099" banner. Unauthenticated users see no banner (shown earlier).

Authenticated: Draft post with status banner

![Authenticated user sees draft status banner on unpublished post](demos/screenshots/scheduled-banner-draft.png)

Authenticated user sees draft status banner on unpublished post

Editor Dashboard

![Editor dashboard showing drafts tab with draft and scheduled post counts](demos/screenshots/scheduled-dashboard.png)

Editor dashboard showing drafts tab with draft and scheduled post counts

Dashboard: Scheduled tab

![Scheduled tab showing future-dated post with days-until-live countdown](demos/screenshots/scheduled-dashboard-scheduled.png)

Scheduled tab showing future-dated post with days-until-live countdown

Acceptance Criteria Verification

  • all_posts() excludes future-dated posts — see Blog Index screenshot (no future-test-post)
  • RSS and Atom feeds exclude future-dated posts — see Test Suite (feed_test.exs)
  • Tag pages exclude future-dated posts — see Test Suite (blog_test.exs, router_test.exs)
  • Direct URL access still shows any post — see Direct URL Access screenshot
  • get_post/get_post! are unfiltered — see Test Suite (blog_test.exs)
  • mix phx.gen.auth provides authentication — see Login flow above
  • Registration rejects non-matching emails — see Registration Rejected screenshot
  • Registration disabled when ALLOWED_REGISTRATION_EMAIL unset — see Test Suite
  • Login/registration pages not linked from public nav — see Blog Index (no auth links)
  • Demo user seeded in dev — logged in as demo@example.com above
  • LiveView dashboard at /editor/dashboard requires auth — see Test Suite (redirect test)
  • Dashboard has two tabs: drafts and scheduled — see Dashboard screenshots
  • Unified timeline across all blogs — see Dashboard (all blogs shown together)
  • Scheduled posts show days until live — see Scheduled Tab screenshot
  • Clicking a post navigates to blog show page — post titles are links
  • Authenticated users see status banners — see Draft Banner and Scheduled Banner screenshots

Authenticated: Scheduled post banner (corrected)

![Authenticated user sees blue scheduled banner with date on future post](demos/screenshots/scheduled-banner-future.png)

Authenticated user sees blue scheduled banner with date on future post

Authenticated: Draft post banner

![Authenticated user sees amber draft banner on unpublished post](demos/screenshots/scheduled-banner-draft.png)

Authenticated user sees amber draft banner on unpublished post