Skip to main content

CHANGELOG.md

# Changelog

All notable changes to this project are documented here. 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.7.0] - 2026-06-09

### Changed

- **Published to Hex.pm.** Lantern and its LiveCode dependency are now
  available as Hex packages. The `livecode` path dependency in `mix.exs` is
  replaced by `{:livecode, "~> 0.1"}`.

### Added

- **Hosted demo.** `examples/demo` now ships with an ephemeral sandbox flow:
  visitors get a read-only view of the shared database; clicking "Get sandbox"
  triggers a Cloudflare Turnstile challenge and, on success, spins up a fresh
  private Postgres database seeded with the demo data. The sandbox auto-expires
  after 5 minutes and is destroyed on disconnect.

## [0.6.0] - 2026-06-08

### Changed

- **Honest, struct-free error copy.** Database and query errors now route
  through a single `Lantern.Errors.humanize/1` chokepoint instead of being
  `inspect/1`-dumped into the UI. An unreachable/asleep database (a
  `%DBConnection.ConnectionError{}`, e.g. pool `:queue_timeout`) now reads
  "Couldn't connect to this database. It may be starting up or unreachable; try
  again in a moment." rather than a raw struct. The table browser, SQL
  workspace, row editors, and connection setup all share this path.

### Added

- Query errors carry a short plain-language **hint** under the Postgres message —
  the server's own `HINT:` when present, otherwise one derived from the SQLSTATE
  (undefined table/column, syntax error, insufficient privilege, unique/foreign
  key/not-null/check violations). `.lt-error` now honors newlines so the hint
  sits on its own line.

## [0.5.0] - 2026-06-08

### Added

- **Guarded SQL workspace mode** (`sql_mode: :guarded`). A write-enabled middle
  ground between `:trusted` and `:read_only`: ordinary statements run, but a
  destructive one — `DROP`, `TRUNCATE`, or a `DELETE`/`UPDATE` with no `WHERE`
  clause — is held and surfaces a confirmation dialog (an `alertdialog` portal
  showing the exact statement) before it runs. `confirm_sql` / `cancel_sql`
  events drive it; `destructive_sql?/1` is the (heuristic, word-boundary-aware)
  detector and is unit-tested. The Run button's client `data-confirm` is
  suppressed in guarded mode so the server dialog is the single prompt.

## [0.4.0] - 2026-06-08

### Changed

- Reworked `Lantern.Explorer` into a single window frame. A top bar now carries
  the sidebar toggle, a `schema / table` breadcrumb, the Data/SQL view toggle,
  settings, and fullscreen, and the sidebar, grid, and footer share the frame's
  borders instead of floating as separate panels. The Data/SQL toggle no longer
  takes its own row, and Settings moved from the sidebar into the top bar.
- Minimum `phoenix_live_view` is now `~> 1.1` (dialogs use
  `Phoenix.Component.portal/1`).

### Added

- `:read_only` option on `Lantern.Explorer` — a browse-only mode that hides
  every write affordance (inline edit, row insert, bulk delete, and all DDL)
  *and* refuses the matching events server-side, and restricts the SQL
  workspace to `SELECT`/`EXPLAIN`. Intended for public or untrusted-viewer
  deployments.
- Themeable per-type cell tints (`--lt-cell-number`, `--lt-cell-temporal`,
  `--lt-cell-boolean`, `--lt-cell-json`) so a column's type reads at a glance,
  plus `--lt-bg-code` and `--lt-shadow` variables.
- **Row detail drawer** — a row's expand button opens a side panel with the full
  record: every column labeled with its type, full (un-truncated) values,
  pretty-printed JSON, and clickable foreign keys.
- **Cell context menu** — right-click a cell to copy its value, filter the grid
  by that value, or open a foreign-key reference. All three are reads, so they
  work in `:read_only` mode.
- Grid browsing niceties: a type label under each data-grid column header,
  right-aligned tabular numerics, booleans as distinct `true`/`false` text, and
  a click-to-peek popover that pretty-prints JSON and expands truncated values.
- Quick-chart **Bar / Line / Pie** selector. The SQL workspace chart (and a new
  "chart this column" affordance on numeric data-grid headers) can render as a
  horizontal bar chart, an inline-SVG line chart, or an inline-SVG pie chart
  with a legend — all dependency-free (no chart library) and fully available in
  `:read_only` mode. Pie slices cycle through the existing `--lt-cell-*` /
  `--lt-accent` tokens, so charts stay themed in light and dark.

### Fixed

- Dialogs render through a portal onto `<body>`, so a modal can no longer be
  clipped by a host page's `overflow` or `transform`.
- The settings popover is no longer clipped by the sidebar's overflow.
- Fullscreen fills the viewport even when the host page constrains the
  component's width (for example, a centered `max-width` container).

## [0.3.0] - 2026-05-30

### Changed

- A table **without a primary key is now insert-only** rather than fully
  read-only. The "New row" affordance stays available so rows can be added,
  while inline edit and delete — which need a primary key to address an
  existing row — remain disabled. `Lantern.Explorer` now derives `insertable`
  (a table is loaded with columns) separately from `editable` (the table has a
  primary key), and the empty-state note reflects the new behavior.

## [0.2.0] - 2026-05-29

### Added

- Table-level DDL on the `Lantern` facade: `create_table/3`, `drop_table/2`,
  `add_column/3`, `drop_column/3`, `rename_column/4`, and `rename_table/3`.
  Each validates names and builds (and type-checks) its statement before
  opening a connection, so a bad request never spends one.
- `Lantern.SQL` DDL builders and a `validate_type/1` allowlist. Since DDL
  can't parameterize identifiers or types, the safety boundary is
  `quote_ident/1` for every identifier plus a curated type allowlist
  (simple + parameterized `(n)`/`(n,m)` types); injection attempts such as
  `"text; drop table users"` are rejected.
- `Lantern.Explorer` table editor UI: a "New table" dialog (named columns,
  per-column type/nullable/primary-key, add/remove rows), and a per-table
  menu to edit columns (add/rename/drop), rename the table, or drop it.
  Destructive actions are guarded by confirmations.

## [0.1.0] - 2026-05-28

Initial release.

### Added

- `Lantern` data layer: introspection (`list_tables/1`, `columns/2`,
  `primary_keys/2`, `schema/2`), reads with filter/sort/pagination
  (`query/3`), safe primary-key-scoped writes (`insert/3`, `update/4`,
  `delete/3`), and FK lookup options (`reference_options/4`). Values are
  always sent as cast text parameters; nothing is interpolated into SQL.
- `Lantern.Explorer` LiveComponent: table sidebar, sortable/filterable grid,
  inline editing, row insertion, bulk delete, fixed-height shell with
  internal scroll, fullscreen mode (Esc to exit), and an inline filter help
  popover with click-to-apply examples.
- Type-aware editors: dropdowns for booleans, enums, and single-column
  foreign keys; native date/time/datetime pickers; number inputs; a JSON
  textarea with live validation; a `∅` "set NULL" control on nullable
  fields. Arrays render as Postgres array literals and round-trip through
  the editor.
- Connection-agnostic `Lantern.Source`: parses `postgres://` URLs, keyword
  lists, maps, or any struct exposing host/port/username/password/database.
- One-shot connections with `Process.unlink` + `search_path` pinned to
  `public`, so a Postgres disconnect can't kill the host LiveView and DML
  hits the same schema the introspection scanned.
- `:allow_raw_filter` attribute (default `false`). The raw WHERE-fragment
  filter input is hidden unless explicitly opted in for trusted operators.
- Composite-foreign-key safety: detected and excluded from FK dropdowns so
  a mis-paired option can't write the wrong column.
- Standalone `lantern.css` (themeable via `--lt-*` variables, light + dark),
  an optional `lantern.tailwind.css` preset, and a `LanternGrid` JS hook
  (column resize with persistence, set-NULL, JSON validation; cleans up
  window listeners on `destroyed()` and supports touch via `pointercancel`).
- Test suite: pure SQL/Source/Coercion unit tests, real-Postgres integration
  tests (introspection, read/write round-trips, UUID/bytea, enum, FK),
  and event-handler tests that exercise `update/2` + `handle_event/3` on a
  constructed socket. 80 tests + 6 doctests.