Petal Pro 4.4.0

Describe the feature. Get one that belongs.

Petal Pro is a Phoenix SaaS codebase with tenancy, billing, auth, notifications and admin built in, and its conventions written down where your agent reads them.

One purchase, a year of updates included. Prefer to read first? Read the docs

//res.cloudinary.com/wickedsites/image/upload/c_fill,g_face,h_64,w_64/petal_marketing/prod/avatars/21000 //res.cloudinary.com/wickedsites/image/upload/c_fill,g_face,h_64,w_64/petal_marketing/prod/avatars/21006 //res.cloudinary.com/wickedsites/image/upload/c_fill,g_face,h_64,w_64/petal_marketing/prod/avatars/21074 //res.cloudinary.com/wickedsites/image/upload/c_fill,g_face,h_64,w_64/petal_marketing/prod/avatars/21127 //res.cloudinary.com/wickedsites/image/upload/c_fill,g_face,h_64,w_64/petal_marketing/prod/avatars/21264

588 Petal Pro licences since 2022

claude petal_pro

Build a transaction tracker. Users log incomeand expenses, each with a description, anamount, a type (income or expense) and adate. Transactions belong to the current userand are visible only to them. Use the datatable generator for the index.

  1. Edit(lib/petal_pro/finance/transaction.ex) belongs_to :user, validations
  2. Edit(lib/petal_pro/accounts/user.ex) has_many :transactions
  3. Edit(.../transaction_live/index.ex) scoped to current_user
  4. Edit(.../transaction_live/form_component.ex) user_id injected, never cast
  5. Done. Navigate to /app/transactions.
/app/transactions signed in as admin
The /app/transactions page in Petal Pro after the prompt: a Transactions item in the sidebar, and a data table of income and expense rows scoped to the signed-in user
mix petal.gen.live --data-tableEcto.assoc(current_user, :transactions)

The loop

The next feature reuses the last one's plumbing.

The hero showed one feature land in the app. This is what happens on the second one: the agent registers a notification type and the settings page grows a row for it, because the page reads the registry rather than being rebuilt. Then it reviews its own work and commits.

lib/petal_pro/notifications/preferences.ex
allow_disable_email: true
},
spending_exceeds_income: %{
label: "Spending alert",
description: "When your expenses exceed your income for the month",
category: :product,
channels: [:in_app, :email],
allow_disable_in_app: true,
allow_disable_email: true
}
}
1 file changed +8 −0

One registry, no settings work

The type is registered once. Delivery preferences, the bell and the email path read it from there.

Settings, Notification preferences: the Product group with the new Spending alert row beside Changelog updates, each with an in-app and an email box

The row appears by itself

Settings, then Notification preferences, with the new type in the list. Nobody built a settings page.

Read the notifications docs
claude one feature, four commands
  1. /task:plan writes the task file
  2. /task:do implements it, sub-agents review on the way
  3. /ci runs the pipeline locally
  4. /git:commit commits when green

Plan it. Build it. Commit it.

What you still decide: the feature, the name, the price.

Read the Claude Code docs
.claude/agents/ 5 sub-agents
  1. schema-architect UUID v7 keys, indexes, on_delete
  2. elixir-reviewer correctness and conventions
  3. heex-reviewer interpolation, components, a11y
  4. ui-ux-reviewer consistency with the design system
  5. test-runner runs the suite, reads the failures

Reviewed before it lands

They activate on their own during step two. A review pass is a call, not a prompt you rewrite.

In the box

The context ships with the code.

Every boilerplate says it is ready for agents. Open the zip and count. These files are versioned with the product, so the first prompt on day one already knows how tenancy, billing and the admin are done, and how to take any of them out.

petal_pro/
  • CLAUDE.md x6, scoped per directory
  • AGENTS.md
  • COMPONENTS.md
  • .claude/
  • generated/architecture.md
  • generated/db-schema.md
  • agents/ 5 sub-agents
  • skills/ 14 skills
  • commands/recipes/ 23 recipes
  • commands/task/ plan.md do.md

What your agent finds

CLAUDE.md scoped per directory, AGENTS.md as its cross-tool twin for Codex, Cursor and the rest, and the commands, sub-agents and skills Claude Code runs.

Read the Claude Code docs
.claude/commands/recipes/ 23 recipes
  • /recipes:remove-billing free or externally billed apps
  • /recipes:remove-organisations single-user apps, no teams
  • /recipes:remove-2fa simpler auth requirements
  • /recipes:remove-oauth email and password only
  • /recipes:remove-api LiveView-only apps
  • /recipes:remove-admin-chat no AI in the admin panel
  • /recipes:switch-to-single-tenant one org per user, like Notion or Linear
  • /recipes:switch-to-user-billing bill people, not teams

Remove what you do not need

Each one edits the files, drops the migrations and runs the tests. The answer to "I only need half of it".

See all the recipes

What you get

The parts that have to agree already do.

The decisions that are hard to retrofit, made once and made the same way: how a query is scoped, whether billing hangs off the user or the org, what deleting an account cascades to, where the admin sees it. Twelve systems, each linking to its docs page.

Accounts

Sign-in and 2FA

Password, Google, GitHub, passwordless PIN, passkeys and TOTP, with rate limiting on the auth routes.

Read the docs

Orgs and roles

Owner, admin and member roles, invitations that expire, and ownership transfer.

Read the docs

Stripe billing

Per user or per org on one config key, with the customer portal and metered usage.

Read the docs

Notifications

In-app and email delivery set per type, and forced on for the security types.

Read the docs
Operate

Admin panel

Dashboard charts, user search, suspend and impersonate.

Read the docs

Live logs and jobs

Activity logs over PubSub, Oban for background and cron work, Oban Web and LiveDashboard behind admin.

Read the docs

Admin chat and MCP

One action registry serves both, with the tokens and cost of every call logged.

Read the docs

GDPR

A JSON export of everything you hold on a person, and a deletion cascade that runs on Oban.

Read the docs
Ship

Changelog with banner

Public release notes, and a banner that puts the latest entry in front of people already signed in.

Read the docs

Feedback with admin board

A form in the app, filed against the page it came from, and a board with filters behind it.

Read the docs

REST API with OpenAPI

Bearer auth, JSON views and generated docs.

Read the docs

Uploads and deploy

S3, R2, Tigris, Cloudinary or Bunny for files. A Dockerfile, a Fly workflow and Sentry for the rest.

Read the docs

After launch

Ask your app a question.

The admin chat and the MCP server share one registry of actions, so the same question answers in the admin panel or from your agent over MCP, against the running app. Every call is logged with its tokens and cost.

/admin/chat signed in as admin
The Petal Pro admin chat at /admin/chat answering "How many users signed up this week?": the admin sidebar, the recent chats list, the answer with a badge naming the tool it called, and the tools rail
.mcp.json tools/list
{
"mcpServers": {
"petal-pro-dev": {
"type": "http",
"url": "http://localhost:4000/api/mcp",
"headers": {
"Authorization": "Bearer dev-mcp-token"
}
}
}
}
  • get_site_stats
  • list_recent_users
  • search_users
  • manage_user
  • list_orgs
  • manage_org
  • get_ai_call_stats
  • list_changelog_updates
  • create_changelog_update
  • manage_changelog
POST /api/mcp JSON-RPC 2.0 10 tools

The admin chat, mid-task

A real answer and the tool it called to get it. Conversations persist, with a sidebar of recent chats.

Read the admin chat docs

The same tools over MCP

One Jido action registered once serves both clients. Destructive actions are audit-logged.

Read the MCP docs

The boilerplate is done. Describe what comes next.

Auth, orgs, billing, notifications and admin, with the conventions your agent reads, in one download.

  • A year of releases, with upgrade notes when a release needs them
  • The live demo, reseeded every hour
  • The recipes to remove what you will not use

Full refund within 7 days if you're not satisfied. Questions? Read the docs

//res.cloudinary.com/wickedsites/image/upload/c_fill,g_face,h_64,w_64/petal_marketing/prod/avatars/21000 //res.cloudinary.com/wickedsites/image/upload/c_fill,g_face,h_64,w_64/petal_marketing/prod/avatars/21006 //res.cloudinary.com/wickedsites/image/upload/c_fill,g_face,h_64,w_64/petal_marketing/prod/avatars/21074 //res.cloudinary.com/wickedsites/image/upload/c_fill,g_face,h_64,w_64/petal_marketing/prod/avatars/21127 //res.cloudinary.com/wickedsites/image/upload/c_fill,g_face,h_64,w_64/petal_marketing/prod/avatars/21264

588 Petal Pro licences since 2022