Pro Changelog System
Viewing latest docs.
Switch version: v3

Changelog System

The changelog system gives your app a public-facing update feed. Users can browse releases, like entries, and track what they’ve read. Admins manage entries through the admin DataTable UI or directly via Claude Code using the built-in MCP tools.

v4 note: The context was renamed from ChangelogUpdates (v3) to PetalPro.Changelog in v4. The primary schema is now PetalPro.Changelog.Update.

What’s included

  • Public changelog page at /changelog (also accessible from the sidebar)
  • Per-entry slug URLs (/changelog/:slug) with SEO meta descriptions
  • Like/unlike on individual entries (authenticated users)
  • Read tracking — the sidebar notification bell shows unread count
  • Optional site-wide banner that can be attached to any published entry
  • Notification and email dispatch on publish (opt-in per entry)
  • Admin DataTable at /admin/changelog with full Flop pagination, sorting, and filtering
  • MCP tools for managing entries via Claude Code

Schemas

PetalPro.Changelog.Update

The primary content record:

Field Type Notes
title string Required. Auto-generates slug.
slug string URL-safe, unique, auto-derived from title.
summary string Short teaser shown in lists and meta descriptions.
content string Full content as EditorJS JSON.
status enum :draft, :published, :archived
category enum :new, :improve, :fix
published_at utc_datetime Set automatically on publish.
show_banner boolean Promotes this entry to the site-wide banner.
banner_style enum :info, :success, :warning, :error
banner_cta_text string Button label for the banner.
banner_cta_url string Button destination for the banner.
banner_expires_at utc_datetime Auto-hides banner after this time.
send_notification boolean Send in-app notification to all users on publish.
send_email boolean Send email to all users on publish.

PetalPro.Changelog.Like

Tracks which users liked which updates. Unique constraint on [:changelog_update_id, :user_id].

PetalPro.Changelog.Read

Tracks whether a user has read an update and how (read_via: :changelog_page or :banner). Used to power the unread count in the notification bell.

Context module

PetalPro.Changelog is the public interface. Key functions:

elixir
# Admin: list all updates (optional status filter)
Changelog.list_changelog_updates()
Changelog.list_changelog_updates(%{status: :draft})

# Public: list published updates with like counts and user like status
Changelog.list_public_changelog_updates(%{}, current_user)

# Fetch by slug (raises if not found or not published)
Changelog.get_published_changelog_update_by_slug!("my-update-slug")

# CRUD
Changelog.create_changelog_update(attrs)
Changelog.update_changelog_update(update, attrs)
Changelog.publish_changelog_update(update, published_by_user)
Changelog.unpublish_changelog_update(update)
Changelog.archive_changelog_update(update)
Changelog.delete_changelog_update(update)

# Read tracking
Changelog.mark_as_read(update, user, :changelog_page)
Changelog.get_unread_count(user)

# Likes
Changelog.toggle_like(update, user)
Changelog.get_like_count(update)

# Banner
Changelog.get_active_banner()

Publishing dispatches an Oban job (ChangelogNotificationWorker) if send_notification or send_email is set on the entry. Only one banner can be active at a time — publishing a second banner-enabled entry returns a validation error.

Admin DataTable

PetalProWeb.AdminChangelogLive at /admin/changelog uses the DataTable component backed by Flop. Features:

  • Sort by title, category, status, published date
  • Filter by status
  • Inline publish/unpublish/archive/delete actions
  • Per-entry read count and like count stats
  • Link to the public entry

Public page and SEO

The public changelog lives at /changelog. Individual entries are at /changelog/:slug. The summary field populates the <meta name="description"> tag for each entry page, so write it like you mean it — search engines and unfurl previews both use it.

MCP tools (Claude Code integration)

Petal Pro exposes three changelog tools via its admin MCP server at POST /api/mcp. These are available to Claude Code and Claude Desktop when connected with a bearer token.

list_changelog_updates

Lists updates with optional status filter and limit.

list_changelog_updates(status: "draft", limit: 10)

Returns: id, title, slug, status, category, show_banner, published_at, author.

manage_changelog

Performs a single action on an existing update identified by slug or UUID.

manage_changelog(identifier: "my-update-slug", action: "get")
manage_changelog(identifier: "my-update-slug", action: "publish", publisher_email: "admin@example.com")
manage_changelog(identifier: "my-update-slug", action: "unpublish")
manage_changelog(identifier: "my-update-slug", action: "archive")
manage_changelog(identifier: "my-update-slug", action: "delete")
manage_changelog(identifier: "my-update-slug", action: "update", title: "New title", category: "fix")

The get action returns full details including read count, read percentage, and like count. The publish action requires publisher_email — it must belong to an admin user.

create_changelog_update

Creates a new entry in :draft status.

create_changelog_update(
  title: "Better dark mode",
  content: "{\"blocks\":[{\"type\":\"paragraph\",\"data\":{\"text\":\"We overhauled dark mode...\"}}]}",
  category: "improve",
  summary: "Dark mode now respects system preference on first visit.",
  send_notification: true
)

Content must be an EditorJS JSON string. category defaults to "new". author_email defaults to the first admin user if omitted.

Creating a changelog entry from Claude Code

> Use the create_changelog_update tool to draft a changelog entry titled "Faster search"
  in the "improve" category. Summary: "Search results now load 3x faster."
  Then publish it using my email: matt@example.com

Claude will call create_changelog_update to draft the entry, then manage_changelog with action: "publish" to go live. The whole flow takes seconds without touching the admin UI.