# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.0.2] - 2026-11-11

- DOM-level JS tests for `loader.js` and `panel.js` wiring and postMessage origin gate (ADR 06)
- EXPLAIN tests on Postgres, a Postgres service in CI (ADR 08)
- `allowed_origins:` for proxies and tunnels that rewrite the Host header (ADR 04)
- `PhoenixDevToolbar.Report`: read API over captured sessions for IEx and agents (ADR 13)
- Shipped `usage-rules.md` and the `phoenix-dev-toolbar-report` agent skill (ADR 13)
- Standalone panel URL: `<path>/panel?path=...` or the newest page, standalone mode (ADR 14)
- Documented `data-pdt-*` row attributes with raw values, for browser-driving agents (ADR 14)
- MCP endpoint at `<path>/mcp`, this machine only, read-only Report tools, `mcp: false` (ADR 15)
- MCP `clients:` option: own LAN addresses count as local, IP/CIDR allowlist, `:any` (ADR 15)
- MCP client setup for Claude Code, Codex, Cursor and VS Code in README and usage rules (ADR 15)
- Panel sid check anchored with `\A...\z` (ADR 14)
- Standalone panel `?path=` and newest page limited to MCP's clients rule (ADR 14)
- One "this machine" rule: `actions:` and Eval `clients:` take `:local` (ADR 10, ADR 12)
- Eval default `clients:` widened to `:local`, own LAN address included (ADR 12)
- Agent setup guide; README `usage_rules` config made skills-only, block rewrite warned (ADR 13)
- MCP refusals name the peer and the option; clearer "No captured page" errors (ADR 15)

## [0.0.1] - 2026-11-10

First public release. A dev-only toolbar for Phoenix LiveView apps: a summary bar and panel
overlaid on the page you are working on, installed with one plug in the endpoint.
Tabs: Request, Ecto (queries, N+1 detection, EXPLAIN, JSON export), LiveView (lifecycle timings,
assigns, events, component tree), Process and System (any process, supervision trees, opt-in actions).
Opt-in Cluster and Eval plugins. Plugin API with a guide. Off outside `MIX_ENV=dev`.

- Project conventions: AGENTS.md, ADRs, roadmap, `mix precommit`, CI matrix (ADR 00, ADR 06)
- `PhoenixDevToolbar.enabled?/0` runtime guard (ADR 01)
- Bounded ETS event store: caps, flood guard, TTL sweep, LiveView DOWN cleanup (ADR 03)
- Payload truncation and key redaction helpers (ADR 03)
- Telemetry collector: plugin fan-out, crash quarantine, `$callers` attribution (ADR 02)
- LiveView session tracking: dead render link, reconnect, live navigation, nested (ADR 02)
- Registry based live notifications for panel subscribers (ADR 03)
- Built-in Request and Ecto collectors, default plugins (ADR 02)
- `PhoenixDevToolbar.Plug`: page tracking, loader injection, asset serving (ADR 04)
- Live panel served by the plug, no router changes: summary, Ecto and Request tabs (ADR 01, ADR 04)
- Loader (shadow DOM iframe, collapse state), panel JS and CSS, esbuild bundles (ADR 04)
- `mix dev` harness: SQLite demo app with N+1, events, Task.async and dead pages (ADR 06)
- Prod compile check of a fixture host app installing the toolbar (ADR 01)
- Panel keeps following a tab after older sessions expire; no missed or out of order events (ADR 04)
- Bounded exception banners and plug options; panel asset URLs from the plug path (ADR 03, ADR 04)
- Toolbar disables itself, with a warning, in releases unless explicitly enabled (ADR 01)
- Panel UX: hide to a corner pill, HTTP/live query tags, timings, dropped badge, ARIA tabs (ADR 04)
- CI tests the minimum stack with LiveView 1.1 (ADR 06)
- Panel loads the host's own Phoenix and LiveView JS clients: no version skew (ADR 04)
- LiveView collector: callback and render timings, bounded assigns diff, push_event names (ADR 02)
- Bounded, budgeted redaction preview for assigns and LiveView params (ADR 03)
- LiveView tab: lifecycle profiler, callbacks badge and server event log (ADR 07)
- Assigns inspector: redacted snapshot through LiveView Debug, throttled refresh (ADR 07)
- Component tree, polled only while the panel is open and visible (ADR 07)
- Client event log: LiveView window events forwarded by the loader (ADR 04, ADR 07)
- JS unit tests for the loader helpers: `mix test.js`, in precommit and CI (ADR 06)
- `mix dev` pages: Components and Assigns (ADR 06)
- Trimmed events badge in the summary bar; client event validation module (ADR 03, ADR 07)
- Public plugin behaviour, `use` macro, plugin options and config validation (ADR 05)
- Per plugin event caps and a per session ceiling, limits documented in the README (ADR 03)
- `max_events` now caps each plugin per session, not the session (ADR 03)
- Plugin panel shell: LiveComponent tabs, per plugin badges and trimmed notes (ADR 05)
- LiveView tab on the public panel API; PanelLive is generic glue (ADR 05, ADR 07)
- Plugin errors shown in their tab with Re-enable; panel side boundary for plugin code (ADR 05)
- Plugin guide in ExDoc, Oban example plugin, harness pages for jobs and plugin errors (ADR 05, ADR 06)
- Plugin boundary covers all of render/1; event plugin ids stamped by the collector (ADR 05)
- Panel seen seqs bounded per session; Config checks id and name; update/2 rejected (ADR 03, ADR 05)
- Ecto badge DOM id is `pdt-badge-ecto-queries` (ADR 05)
- Summary bar: badges that do not fit are counted in a "+N" chip that opens the panel (ADR 04)
- Callback spans: `Context.span` and `Event.span`, the LiveView callback an event ran in (ADR 02)
- N+1 detector: Ecto badge, groups and row tags, `n_plus_one:` plugin option (ADR 08)
- EXPLAIN capture: raw params of SELECTs kept in the event, bounded, never rendered (ADR 03, ADR 08)
- EXPLAIN button in the Ecto tab: rolled back, single SELECT, page scoped; SQLite test repo (ADR 08)
- N+1 groups merged by SQL and origin, Clear button, advice; EXPLAIN focus, names, Hide (ADR 08)
- Process tab: vital signs, sparklines, links and monitors, nested LiveViews; in `:defaults` (ADR 09)
- Process tab: GC now button, rate limited; `/memory` harness page (ADR 06, ADR 09)
- Panel reload breaker: stops after 3 refused loads in 10 s, with a notice and Retry (ADR 04)
- Panel socket at `<path>/live`: no host CSRF token or session needed; fixes the reload loop (ADR 04)
- the plug's `:live_socket_path` option is gone (ADR 04)
- Panel socket review fixes: decoded join check, stale on unknown panels, host socket options (ADR 04)
- Panel: disconnected state, shorter cannot connect notice, inert tabs; Process tab wording (ADR 04, ADR 09)
- Docs: per-run disable recipe through `DEV_TOOLBAR=0` (ADR 01)
- `limits:` overrides validated at boot; panel `frame-ancestors` and `nosniff` headers (ADR 03, ADR 04)
- Public repo: renamed to `phoenix_dev_toolbar`, GitHub install, CI badge, SECURITY.md
- Stricter lint: Credo opt-in checks, Dialyzer unmatched returns; shared test page helpers (ADR 06)
- Ecto tab JSON export: short or full with EXPLAIN, download or copy (ADR 08)
- Ecto export fix: a Copy built before the LiveView joined is dropped; request path fallback (ADR 08)
- Toolbar reserves its page space so the page scrolls above it; draggable panel height (ADR 04)
- Toolbar docks: bottom, top, left, right; dock picker, sideways collapsed strip (ADR 04)
- Dock picker menu no longer clipped on side docks (ADR 04)
- Page space opt out: `reserve_space` config and a dock menu toggle (ADR 04)
- Ecto Copy never hangs: busy and crash answers, disabled during EXPLAIN (ADR 08)
- Ecto Download checks `root` is one of the page's sids (ADR 08)
- Process addressing, protected set, `actions:` loopback policy (ADR 10)
- `Panel.navigate/3`: switch to another tab with params (ADR 10)
- System tab, now in `:defaults`: any process by pid or name, crumbs, ancestors, state (ADR 11)
- Process tab: every process is a link to the System tab (ADR 09)
- Process actions: kill (with reason), suspend 10 s with auto resume, watch, message peek (ADR 10)
- Redaction walks tuples, so queued messages and results are redacted too (ADR 10)
- System tab trees: a supervisor's children, the application list with top supervisors (ADR 11)
- System tab top: the 50 processes with the most memory, reductions or queue (ADR 11)
- System tab message trace: one process, 100 messages or 10 s, OTP 27 sessions (ADR 11)
- Cluster plugin (opt-in): connected nodes with round trip, processes, memory (ADR 12)
- Eval plugin (opt-in): read queries, code with allow: :eval, loopback by default (ADR 12)
- panel refuses host names that could be rebound; list yours in `allowed_hosts` (ADR 04)
- unset `enabled` means on only in Mix `:dev`; prod under Mix is off (ADR 01)
- panel socket requires a same-origin `Origin`, whatever the host `check_origin` (ADR 04)
- `access-control-*` headers stripped from panel and export responses (ADR 04)
- `actions:` defaults to `false`; `:loopback` opts in; Eval refused only on explicit false (ADR 10, ADR 12)
- Ecto params through the budgeted preview, 2 KB cap; `redact/2` node budget (ADR 02, ADR 03)
- Response hook catches throws and exits; injection drops a preset `content-length` (ADR 04)
- Collector failure path tests; hot path wording matches the code (ADR 02)
- `redact:` adds to the defaults instead of replacing them (ADR 03)
- Ecto repos default to the apps' `:ecto_repos`, one warning when none (ADR 02, ADR 05)
- Integer list params shown as lists, not charlists; `redact:` entries validated (ADR 03)
- Public moduledocs for the built-in plugins, ADR links, Setup and plugin groups in the docs (ADR 05)
- Experimental markers on the plugin API; `Truncate.changes/2` and `snapshot/1` are internal (ADR 05)
- `Truncate.redact/2` cuts what it does not walk instead of returning it; scalar structs redacted (ADR 03)
