PgFlow Dashboard
February 18, 2026 · View on GitHub
A Phoenix LiveView dashboard for monitoring PgFlow workflows, jobs, and cron schedules.
Installation
1. Generate the Migration
mix pgflow_dashboard.gen.migration
mix ecto.migrate
This installs the pgflow_dashboard PostgreSQL schema with read-only views and query functions.
2. Add to Supervision Tree
In lib/my_app/application.ex:
children = [
MyApp.Repo,
MyAppWeb.Endpoint,
PgFlowDashboard
]
3. Add Routes
In lib/my_app_web/router.ex:
import PgFlowDashboard.Router
scope "/" do
pipe_through [:browser]
pgflow_dashboard "/pgflow",
repo: MyApp.Repo,
pubsub: MyApp.PubSub
end
4. Add LiveFilter Dependency
The dashboard's Runs page uses LiveFilter for filtering and pagination. Since it's an optional dependency of pgflow, you must add it explicitly:
# mix.exs
def deps do
[
{:pgflow, "~> 0.1.0"},
{:live_filter, github: "agoodway/livefilter"}
]
end
Then fetch:
mix deps.get
5. Configure Assets
JavaScript hooks — Add both PgFlow Dashboard and LiveFilter hooks to your LiveSocket in assets/js/app.js:
import { DarkMode, KeyboardShortcuts, ShortcutsModal, MobileMenu } from "../../deps/pgflow/priv/static/pgflow_dashboard/hooks"
import { hooks as liveFilterHooks } from "live_filter"
let liveSocket = new LiveSocket("/live", Socket, {
hooks: { ...liveFilterHooks, DarkMode, KeyboardShortcuts, ShortcutsModal, MobileMenu, ...yourOtherHooks }
})
esbuild — LiveFilter's JS import requires NODE_PATH to resolve deps/. In config/config.exs:
config :esbuild,
version: "0.25.4",
my_app: [
args: ~w(js/app.js --bundle --target=es2022 --outdir=../priv/static/assets/js),
cd: Path.expand("../assets", __DIR__),
env: %{
"NODE_PATH" => Path.expand("../deps", __DIR__)
}
]
Tailwind — Add LiveFilter and DaisyUI component paths so Tailwind generates their classes. In your CSS file (e.g. assets/css/app.css):
@source "../../deps/daisy_ui_components";
@source "../../deps/live_filter";
Or if using tailwind.config.js:
module.exports = {
content: [
// ... existing paths ...
"../deps/daisy_ui_components/**/*.*ex",
"../deps/live_filter/**/*.*ex",
],
}
6. Visit the Dashboard
Start your server and navigate to /pgflow.
Authentication
Protect the dashboard in production. Use pipe_through to guard the routes:
scope "/" do
pipe_through [:browser, :require_authenticated_admin]
pgflow_dashboard "/pgflow",
repo: MyApp.Repo,
pubsub: MyApp.PubSub
end
Or use the :on_mount option for LiveView-level auth:
pgflow_dashboard "/pgflow",
repo: MyApp.Repo,
pubsub: MyApp.PubSub,
on_mount: [{MyAppWeb.AdminAuth, :ensure_admin}]
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
repo | atom | required | Ecto repository module |
pubsub | atom | required | Phoenix.PubSub module |
refresh_interval | integer | 5_000 | Auto-refresh interval in ms |
time_zone | string | "UTC" | Time zone for timestamps |
default_time_range | atom | :last_24h | Default filter (:last_hour, :last_24h, :last_7d, :last_30d) |
max_grid_runs | integer | 50 | Max runs shown in the activity grid |
query_timeout | integer | 10_000 | Database query timeout in ms |
enable_pubsub | boolean | true | Enable real-time PubSub updates |
cache_ttl | integer | 5_000 | Cache TTL for aggregation queries in ms |
Pages
Overview (/pgflow)
Active workers, running count, 24h completions/failures, average duration. Lists recent runs and worker status.
Flows (/pgflow/flows)
All registered flow definitions with 24h statistics (runs, success rate, avg duration).
Flow Detail (/pgflow/flows/:slug)
Flow configuration, run history, and GitHub-style activity grid.
Jobs (/pgflow/jobs)
Background job definitions with 24h statistics. Card view for 12 or fewer jobs, paginated table for more.
Job Detail (/pgflow/jobs/:id)
Job configuration and run history.
Crons (/pgflow/crons)
Scheduled recurring jobs showing cron expression, human-readable schedule, next run time, and active/inactive status.
Cron Detail (/pgflow/crons/:id)
Schedule details and run history for a cron.
Runs (/pgflow/runs)
Filterable list of all workflow and job runs with status, progress, and duration.
Run Detail (/pgflow/runs/:id)
Interactive SVG dependency graph, step execution timeline, and input/output data inspection.
Workers (/pgflow/workers)
Worker processes with health status (healthy, stale, dead) and active task counts.
Worker Detail (/pgflow/workers/:id)
Worker metadata and task throughput.
Keyboard Shortcuts
Press ? to see all shortcuts.
| Shortcut | Action |
|---|---|
g o | Go to Overview |
g w | Go to Workers |
g r | Go to Runs |
g f | Go to Flows |
g j | Go to Jobs |
g c | Go to Crons |
d | Toggle dark mode |
? | Show shortcuts |
Esc | Close modal |
Performance Indexes
For high-traffic dashboards:
mix pgflow_dashboard.gen.indexes
mix ecto.migrate
Troubleshooting
No data showing -- Verify the migration ran: SELECT * FROM pgflow_dashboard.get_overview_metrics();
Real-time updates not working -- Check that PubSub is configured and the PgFlowDashboard supervisor is running.
Hooks not working -- Verify all four hooks (DarkMode, KeyboardShortcuts, ShortcutsModal, MobileMenu) and liveFilterHooks are registered with your LiveSocket.
Runs page filters not rendering -- Ensure live_filter is in your deps, esbuild NODE_PATH includes deps/, and Tailwind scans daisy_ui_components and live_filter paths.