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 scaffolding —
bb scaffold ai "product module with name, price, stock" -
Error explainer —
bb ai explain(or(ai/explain *e)in the REPL) -
Test generator —
bb ai gen-tests <file>(detects unit/contract/integration from the source path) -
SQL copilot —
bb ai sql "find active users with orders in the last 7 days"(returns HoneySQL + SQL preview) -
Docs wizard —
bb 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"butui/checkboxsubmitted"true". Remember-me is now activated on any truthy form value. -
Session validation after login redirect crashed because
string→instantdid not handlejava.time.OffsetDateTime, which H2 returns forTIMESTAMP WITH TIME ZONEcolumns. 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 onGET/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-realtimegained a Ring 1.15 WebSocket upgrade handler (boundary.realtime.shell.handlers.ring-websocket) that bridges Ring’s map-based listener response to the existingIRealtimeServicelifecycle. JWT auth viatokenquery parameter. -
boundary-searchadded:filterssupport onSearchDefinition— keyword dimensions stored as compact JSON in a newfilterscolumn, with PostgreSQLjsonband H2/SQLiteINSTRfallbacks at query time. -
platformremoved 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:dbalias 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-paymentsto your module wiring if you want the new library active:{:boundary/payment-provider {:provider :mock}}is enough for development. -
bb doctoris 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.