Caravela

Caravela

Declare your domain. Sail with the generated code.

A schema-driven, composable full-stack framework for Phoenix projects. You describe a domain (entities, fields, relations) as an Elixir DSL; Caravela generates Ecto schemas, migrations, Phoenix contexts, controllers, LiveViews, and typed Svelte components.

Status — Phase 1. The DSL, the compiler, and the Ecto-schema + migration generators are in place. Contexts, LiveView, Svelte, and Flow orchestration land in later phases.

Installation

Add caravela to your deps in mix.exs:

def deps do
  [
    {:caravela, "~> 0.1.0"}
  ]
end

Phoenix and ecto_sql are assumed to already be present in the host app; Caravela generates code against them.

Quick start

1. Declare a domain

# lib/my_app/domains/library.ex
defmodule MyApp.Domains.Library do
  use Caravela.Domain

  entity :authors do
    field :name, :string, required: true
    field :bio, :text
    field :born, :date
  end

  entity :books do
    field :title, :string, required: true, min_length: 3
    field :isbn, :string, format: ~r/^\d{13}$/
    field :published, :boolean, default: false
    field :price, :decimal, precision: 10, scale: 2
  end

  entity :publishers do
    field :name, :string, required: true
    field :country, :string
  end

  relation :authors, :books, type: :has_many
  relation :books, :publishers, type: :belongs_to
end

2. Generate schemas and a migration

mix caravela.gen.schema MyApp.Domains.Library
# * created priv/repo/migrations/20260417120000_create_library_tables.exs
# * created lib/my_app/library/author.ex
# * created lib/my_app/library/book.ex
# * created lib/my_app/library/publisher.ex

The generator drops files where a standard Phoenix app expects them. Every file is plain Phoenix / Ecto code — no runtime magic.

Pass --dry-run to preview, or --force to overwrite existing files without prompting.

3. Migrate

mix ecto.migrate

The generated migration creates tables in dependency order and adds foreign-key indexes. Required fields get null: false; required belongs_to relations become on_delete: :delete_all (non-required become :nilify_all).

DSL reference

entity :<name> do ... end

Declares one entity (one table). The name is plural (:books); the generator derives a singular module name (Book), a plural table name (library_books), and a path (lib/<app>/library/book.ex).

field :<name>, <type>, opts

option applies to effect
required any null: false + validate_required
default any column default
min, max numeric validate_number
min_length, max_length string-like validate_length
format string-like validate_format (regex)
precision, scale numeric decimal precision/scale

Recognised types: :string, :text, :integer, :bigint, :float, :decimal, :boolean, :date, :time, :naive_datetime, :utc_datetime, :binary, :binary_id, :uuid, :map, :json, :jsonb.

relation :<from>, :<to>, type: <t>

t is one of :has_many, :has_one, :belongs_to, :many_to_many. Declare either side of a relationship — Caravela infers the other.

Compile-time validations

The DSL is validated before any code is generated. Each rule raises a CompileError with a file/line pointing at the declaration:

  1. Unknown field types (:widget etc.)
  2. Numeric constraints on non-numeric fields (and vice versa)
  3. Duplicate entity names
  4. Relations referencing undeclared entities
  5. Incompatible cardinality (e.g. both sides :has_many)
  6. Circular chains of required belongs_to (unsatisfiable inserts)

Primary keys and ids

Every generated schema uses :binary_id (UUID) primary and foreign keys. No enumeration attacks, no sequence exhaustion, and Ecto-native.

What's in Phase 1

Roadmap

Later phases add Phoenix contexts, JSON controllers, LiveView modules that mount Svelte components via LiveSvelte, typed Svelte component generation, Absinthe/GraphQL schema generation, and a GenServer-backed flow runtime for composable async workflows.

License

Caravela is licensed under the Mozilla Public License 2.0 (MPL-2.0). In short:

See NOTICE for the full attribution and anti-plagiarism statement.

Supporting the project

Caravela is built in the open and free to use. If it saves you time or ships something you're proud of, please consider sponsoring its development — donation channels (GitHub Sponsors, Open Collective, etc.) will be linked here once set up.

Every contribution, from a PR to a coffee, helps keep the sails full.