All notable changes to Caravela are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
[0.5.2] — 2026-04-18
Changed
- Generated Svelte components and doc examples now use Svelte 5's
$props()rune for prop declarations instead of the deprecatedexport letsyntax. LiveSvelte 0.19 ships with Svelte 5 runtime;export letstill worked but produced compile-time warnings.
[0.5.1] — 2026-04-18
Fixed
- Generated
--with-domainform LiveView no longer crashes withKeyError :errorson mount. The template now seeds the domain's default state (viaCaravela.Live.Template.__assign_defaults__/2) before the firstapply_updater(:load, ...)call. Caravela.Flow.Runner—raceadvances as soon as the first task resolves instead of waiting the full timeout (was relying onTask.yield_many/2's "wait for all, take first").Caravela.Gen.Contextemits simplifiedauthorize_*/run_delete_hookfunctions when no correspondingcan_*/on_deleterule is declared, eliminating the "clause will never match" warnings that appeared on every compile of a fresh CRUD generation.Caravela.Gen.SvelteFormandCaravela.Gen.Sveltenow emit Svelte 5 event attribute syntax (onchange={...},oninput={...},onclick={...},onsubmit={...}) instead of the deprecatedon:eventdirective form.
Added
Caravela.Flow—:tagstart option. When set, every notification is delivered wrapped as{:caravela_flow, tag, original_msg}, letting a single listener driving many flows demultiplex without forwarder processes.
Changed
Caravela.Live.Domain/Caravela.Live.Form— when theupdater/on_event/visiblemacros reject a value they can't arity-check at compile time, the error message now points the reader at the accepted shapes (fn ... endor&Module.fun/N) and the wrap-it-in-fnworkaround for bound function variables.Caravela.Gen.Migrationmoduledoc now documents the:timestampoption for deterministic output (snapshot tests / demo pages). Behavior unchanged; only documentation.
[0.5.0] — 2026-04-18
Phase 5 — dynamic Svelte forms with server-driven visibility and
async validation, plus the Caravela.Flow GenServer runtime for
composable async workflows.
Added
Caravela.Live.Form— DSL layered onCaravela.Live.Domainfor form-visibility predicates (visible/2) and async field validators (validate_async/3). Each form-domain module exposes__caravela_form__/0,__caravela_form_visibility__/1,__caravela_form_visible__/2, and__caravela_form_validate_async__/3for introspection and runtime dispatch.Caravela.Gen.SvelteForm— generator that reads a form-domain module plus its owningCaravela.Schema.Domainand emits<Entity>FormDynamic.svelte. The component declaresfield_visibility/async_errorsprops, wraps guarded fields in{#if field_visibility.*}, and debounces async-validationpushEventcalls client-side.Caravela.Flow/Caravela.Flow.DSL—use Caravela.Flowplusflow/3,sequence,repeat,wait,wait_until,debounce,set_state,run,parallel,race, andeachmacros. Compiles to nested step-tree structs inCaravela.Flow.Steps.Caravela.Flow.Runner— GenServer interpreting step trees. Supports retry/backoff (linear + exponential),wait_untilthat unblocks onsignal/2,debouncethat resets on state change during the pause, parallel/race task orchestration, and per-itemeachiteration with{:ok|:skip|:error, _}returns.Caravela.Flow.Supervisor— optional DynamicSupervisor for flow runners.Caravela.Flow.start/3attaches runners when the supervisor is running, falls back to unsupervisedstart_linkotherwise (useful in tests and tooling).- Top-level API:
Caravela.Flow.start/3,Caravela.Flow.signal/2,Caravela.Flow.get_state/1,Caravela.Flow.stop/1,2. Flows deliver{:flow_state, _},{:flow_done, _}, and{:flow_error, _}messages to the:notifypid. docs/flows.md— new guide covering the flow DSL, primitives, the real-time loop through LiveView + LiveSvelte, and the scope boundary (no event sourcing).docs/live_runtime.md— extended withCaravela.Live.FormandCaravela.Gen.SvelteFormsections.
Scope
- Flows are strictly ephemeral: in-memory state, no persistence, no event sourcing. Teams needing durable event streams should use Commanded.
0.4.0 — 2026-04-17
Phase 4 — LiveView + typed Svelte component generation,
Caravela.Live.* runtime for composable state, and a docs restructure.
Added
mix caravela.gen.live— generates three LiveView modules per entity (index / show / form) plus matching typed Svelte components and a TypeScript interfaces file. LiveViews mount components via<LiveSvelte.render>and delegate CRUD to the generated context, so authorization, hooks, and multi-tenant scoping apply for free.Caravela.Gen.LiveView+Caravela.Gen.Svelte— EEx-backed generators that emit index/show/form templates. Both respect the# --- CUSTOM ---marker (TypeScript uses// --- CUSTOM ---, Svelte uses<!-- --- CUSTOM --- -->).Caravela.Gen.LiveRoute— prints aliverouter scope snippet with four routes per entity (index,:new,:show,:edit), analogous toCaravela.Gen.RouterScopefor the JSON API.--with-domainflag onmix caravela.gen.live— also emits aCaravela.Live.Domaincompanion module per entity and regeneratesform.exfrom a Template-backed variant. Index and show stay plain. Useful as an onramp to theCaravela.Live.*runtime.Caravela.Live.Updater— composable assigns-transformer helpers:run/2,3,compose/2,embed/2, and the~>pipe operator.Caravela.Live.Domain—usemacro withstate,updater,on_event, andon_infoDSL for server-side state machines. Compile-time checks enforce updater arity (1or2) and require string event names. Theuseblock sets@caravela_live_domain __MODULE__soapply_updater/2,3resolves inside domain bodies without an explicit module argument.Caravela.Live.Template—use Caravela.Live.Template, domain: Modbinds a LiveView to aLive.Domainmodule, injectingmount/3,handle_event/3,handle_info/2, andapply_updater/2,3. Unknown events log a warning instead of crashing; all callbacks aredefoverridable.- Naming helpers:
live_module/3,live_file_path/3,svelte_component_name/2,svelte_component_ref/3,svelte_file_path/3,svelte_types_file_path/1— all version-aware. - Documentation split into topic guides under
docs/(getting_started, dsl, generators, multi_tenancy, versioning, graphql, livesvelte, live_runtime, regeneration), wired intomix docsas ex_doc extras. README trimmed to a minimal entry point. - GitHub Actions workflow (
docs.yml) that deploysmix docsoutput to GitHub Pages on every push tomain. HexDocs continues to publish on tag release.
Changed
- BC-preserving rename.
Caravela.Live.Updater.apply/2,3→run/2,3to avoid shadowingKernel.apply/2,3.apply/2,3remains as an undocumented alias. - Generated Svelte
BookShow.sveltenow renders fields with the same null-safe expression as the index, so a missing field prints—instead ofundefined. - Generated Svelte
BookIndex.sveltenow includes a "New book" button that dispatchespushEvent('new', {}); the matchinghandle_eventnavigates to the form route.
Fixed
Caravela.Live.Domaindocstring previously showed an example that wouldn't compile:apply_updater/2,3was invoked insideon_eventbodies but the macro required@caravela_live_domain, which was only set byuse Caravela.Live.Template. Now set byCaravela.Live.Domaintoo.- Removed an unused
dirtylocal from the generated Svelte form.
0.3.0 — 2026-04-17
Phase 3 — multi-tenancy, API versioning, Absinthe/GraphQL generation.
Added
use Caravela.Domain, multi_tenant: true— opts into row-level multi-tenancy.Caravela.Tenantauto-injects a:tenant_id(:binary_id,null: false) field into every entity, and the generated context gainsscope_tenant/2+inject_tenant_id/2helpers driven bycontext.tenant.id.- Migrations in multi-tenant domains add the
tenant_idcolumn and composite[:tenant_id, :<fk>]indexes alongside each FK index, plus a standalone[:tenant_id]index on tables with no FKs. version "v1"DSL directive — all generated Elixir modules and file paths are namespaced under the version segment (MyApp.Library.V1.Book,MyAppWeb.V1.BookController,lib/my_app/library/v1/book.ex). The router snippet is emitted atscope "/api/v1", MyAppWeb.V1. Table names stay version-free so rows are shared across versions.- Two new compile-time validations: invalid version format (must match
~r/^v\d+$/) and manual:tenant_iddeclarations colliding with auto-injection. Caravela.Gen.GraphQL— renders Absinthe object types, query object, and mutation object (with typed input objects) for the domain. Every resolver delegates to the generated context, so authorization, hooks, and tenant scoping apply to GraphQL for free. Tenant-injected fields are hidden from both object and input types.mix caravela.gen.graphqltask — checks for Absinthe at runtime and prints an actionable error if the optional dependencies are missing.- Generated controllers read
conn.assigns[:tenant]into the context when the domain is multi-tenant.
0.2.0 — 2026-04-17
Phase 2 — hooks, permissions, Phoenix context + JSON API generators.
Added
- Hook DSL:
on_create/2,on_update/2,on_delete/2on any entity. Hooks run between authorization and the finalRepocall in the generated context.on_deletemay return{:error, reason}to abort the delete. - Permission DSL:
can_read/2,can_create/2,can_update/2,can_delete/2.can_readis applied as an Ecto query filter; the other three return booleans and afalseshort-circuits the context function with{:error, :unauthorized}. - Compiled domain modules expose
__caravela_hook__/4and__caravela_permission__dispatch functions with safe fallbacks. - Three new compile-time validations: hook / permission arity, unknown entity references, duplicate (action, entity) declarations.
Caravela.Gen.Context— Phoenix context generator with CRUD functions per entity (list_,get_,get_!,change_,create_,update_,delete_).Caravela.Gen.Controller— JSON controller generator (REST actions, standard status codes, changeset → 422 translation).Caravela.Gen.RouterScope— prints thescope "/api", MyAppWeb do … endsnippet to paste into the host app's router.Caravela.Gen.Custom— preserves user code below the# --- CUSTOM ---marker across regenerations. Schemas, contexts, and controllers all ship with the marker.- Mix tasks:
caravela.gen.context,caravela.gen.api, and the all-in-onecaravela.gen.
0.1.0 — 2026-04-17
Initial public release. Phase 1 — DSL, compiler, and schema/migration generators.
Added
Caravela.DomainDSL:entity,field,relation.Caravela.Compilerwith six compile-time validations: unknown field types, numeric-constraint/type mismatches, duplicate entities, dangling relation targets, incompatible cardinality, circular requiredbelongs_tochains.Caravela.Gen.EctoSchema— Ecto schema generator (with changeset, required/format/length/numeric validations).Caravela.Gen.Migration— Ecto migration generator, topologically sorted, with foreign-key indexes and appropriateon_deleterules derived fromrequired:.mix caravela.gen.schema MyApp.Domains.<Module>task with--dry-runand--forceoptions.:binary_idprimary and foreign keys by default.