Back to blog
2026-04-06 Thijs Creemers

Release: v1.0.1-alpha-12

We just tagged v1.0.1-alpha-12. This release is dense — four new libraries, an admin UI redesign, a new developer tooling layer, and a wave of auth and infrastructure fixes. Here is a tour of the highlights.

Four new libraries

boundary-payments

A PSP abstraction with a single IPaymentProvider protocol. Adapters for Mollie, Stripe, and a Mock provider for development and tests. Scope is the checkout-session flow: create → redirect → webhook → status, with normalized event types (:payment.paid, :payment.authorized, :payment.failed, :payment.cancelled).

Stripe uses HMAC-SHA256 webhook verification with constant-time comparison and a 300s timestamp tolerance. Mollie uses form-POST webhooks with fetch-back verification. Swap between providers by changing the :provider key in :boundary/payment-provider — no application code changes.

:boundary/payment-provider
{:provider         :mollie
 :api-key          #env PSP_API_KEY
 :webhook-base-url #env APP_BASE_URL}

19 tests, 111 assertions. See the payments library docs.

boundary-ai

Framework-aware AI tooling. Unlike a generic assistant, it knows Boundary’s conventions (FC/IS, ports, kebab↔snake naming, Malli schemas, HoneySQL). Five features, all available as bb subcommands:

  • NL scaffoldingbb scaffold ai "product module with name, price, stock"

  • Error explainerbb ai explain (or (ai/explain *e) in the REPL)

  • Test generatorbb ai gen-tests <file> (detects unit/contract/integration from the source path)

  • SQL copilotbb ai sql "find active users with orders in the last 7 days" (returns HoneySQL + SQL preview)

  • Docs wizardbb ai docs --module libs/user --type agents|openapi|readme

Offline-first: defaults to Ollama (no API key needed). Anthropic and OpenAI are supported with automatic fallback — configure a :fallback on :boundary/ai-service and the framework transparently fails over if the primary provider is down.

boundary-calendar

Recurring events with DST-aware RRULE expansion via ical4j 4.x, iCal export/import, and pairwise conflict detection. A defevent macro registers event type schemas at load time. Pure Hiccup calendar views (month-view, week-view, mini-calendar) ship out of the box.

boundary-workflow

Declarative state machines. defworkflow declares states, transitions, guards, and permissions as data. The engine validates, persists, and fires audit entries on every transition. Lifecycle hooks (:on-enter-<state>, :on-exit-<state>, :on-any-transition) and :auto? true transitions for system-initiated moves. REST API exposes availableTransitions with per-transition :enabled? and :reason, so UIs can render correct action buttons without duplicating permission logic.

Admin UI

The admin got a significant UX pass.

Refined Editorial redesign

Compact toolbar replaces the large gradient hero (saves ~120px of vertical space). Sticky pagination footer stays visible when scrolling long tables. Action buttons right-aligned.

Single- and double-click coexistence

Single-click on any data cell navigates to the edit form. Double-click triggers inline field editing. A 250ms debounce lets the two coexist without conflict, and the redundant per-row edit icon is gone.

Collapsible sidebar

Sidebar collapses to 64px icon-only mode via toggle button or Ctrl+B. Hover to temporarily expand, pin to lock open. State persists to localStorage. The Alpine.js store initialization moved from inline script to external admin-ux.js to satisfy Content Security Policy.

New developer tools

Four new bb tools, all built during this cycle:

bb doctor — Config Doctor

Rule-based validation of config.edn and project files, no AI required. Six checks: env-refs, providers, jwt-secret, admin-parity, prod-placeholders, wiring-requires. CI mode: bb doctor --env all --ci exits non-zero on any error.

bb setup — Config Setup Wizard

Interactive wizard with three modes: guided prompts, CLI flags (--database postgresql --payment stripe), or AI-powered natural language (bb setup ai "PostgreSQL with Stripe"). Generates dev/ and test/ configs plus .env.example from component templates. Test config always uses H2 in-memory + mock providers for fast, isolated tests.

bb scaffold integrate

After bb scaffold generate, this patches deps.edn, tests.edn, and wiring.clj so the new module is fully wired. Idempotent, with --dry-run preview.

bb ai admin-entity

AI-powered admin entity EDN generation from natural language:

bb ai admin-entity "products with name, price, status"

Discovers existing entities as in-prompt style examples, writes to both dev/admin/ and test/admin/, prints the allowlist-registration instructions.

End-to-end testing with Spel

Two e2e test suites landed, both built on Spel (a Playwright Java wrapper) — no Node.js, npm, or TypeScript introduced into the stack.

  • BOU-9 — 33 tests covering /web/login, /web/register, and /api/v1/auth/*.

  • BOU-10 — 19 tests for the admin Users and Tenants UI: list overviews, detail/edit forms, HTMX search fragment updates, access control, and soft-delete.

Helpers in boundary.e2e.helpers.admin provide login-as-admin! / login-as-user!, two-phase HTMX settle waiting, and table/form query utilities. The :e2e test suite is isolated behind an opt-in Clojure alias — normal clojure -M:test runs are unaffected. A test-only POST /test/reset endpoint (behind a config flag and a bb doctor check) truncates H2 and re-seeds baseline tenant/users between tests.

Auth and session fixes

Five bugs surfaced by the BOU-9 e2e suite are now fixed in boundary-user:

  • MFA handlers read session user ID from the wrong request path — all four MFA endpoints returned 500. Fixed.

  • Remember-me checkbox compared against "on" but ui/checkbox submitted "true". Remember-me is now activated on any truthy form value.

  • Session validation after login redirect crashed because string→instant did not handle java.time.OffsetDateTime, which H2 returns for TIMESTAMP WITH TIME ZONE columns. The NPE bounced users back to login after successful auth. Fixed.

  • Account lockout existed in the core layer but was never called from the service layer. There is now a service-level lockout gate that short-circuits on true lockout only — deactivated/deleted accounts still fall through to the normal auth flow.

  • Session tokens in URLs: standard base64 produced +, /, = characters that caused Jetty 400 errors on GET/DELETE /api/v1/sessions/:token. Fixed by switching to URL-safe base64. Breaking change: existing sessions with old-format tokens will fail validation — users must re-login after deploy.

Realtime, search, platform

  • boundary-realtime gained a Ring 1.15 WebSocket upgrade handler (boundary.realtime.shell.handlers.ring-websocket) that bridges Ring’s map-based listener response to the existing IRealtimeService lifecycle. JWT auth via token query parameter.

  • boundary-search added :filters support on SearchDefinition — keyword dimensions stored as compact JSON in a new filters column, with PostgreSQL jsonb and H2/SQLite INSTR fallbacks at query time.

  • platform removed compile-time (:import [org.postgresql.util PGobject]) and (instance? org.postgresql.util.PSQLException …​) from user and tenant persistence. Replaced with runtime class name checks — the REPL now starts without the :db alias on the classpath.

Upgrade notes

  • Re-login required after deploy: existing session tokens encoded with standard base64 will fail validation on GET/DELETE /api/v1/sessions/:token.

  • Add boundary-payments to your module wiring if you want the new library active: {:boundary/payment-provider {:provider :mock}} is enough for development.

  • bb doctor is a good first step after upgrading — it will flag any stale placeholders or missing env references in your configs.

What’s next

I will keep bug hunting, finish wiring up the remaining alpha-12 libraries into the example applications, and prepare for a proper beta. Feedback and issues welcome on GitHub.