DSL entry point. use Caravela.Domain in a module to declare a domain:
defmodule MyApp.Domains.Library do
use Caravela.Domain
entity :authors do
field :name, :string, required: true
field :bio, :text
end
entity :books do
field :title, :string, required: true, min_length: 3
field :isbn, :string, format: ~r/^\d{13}$/
end
relation :authors, :books, type: :has_many
on_create :books, fn changeset, _context ->
Ecto.Changeset.validate_required(changeset, [:title])
end
can_create :books, fn context ->
context.current_user.role in [:admin, :editor]
end
endAfter compilation the module exposes __caravela_domain__/0, returning
the validated Caravela.Schema.Domain IR, plus __caravela_hook__/4
and __caravela_permission__ clauses for every declared hook and
permission.
Summary
Functions
Declare the authenticatable trait on the enclosing entity.
Authorize creation of an entity. Receives only the context and must
return a boolean.
Authorize deletion of an entity. Same shape as can_update/2.
Filter a read query by authorization context. Must return an
Ecto.Query.
Authorize updating an entity. Receives the loaded entity and the
context. Must return a boolean.
Enable email confirmation inside an authenticatable block.
Declare an entity (a table/schema) with a do block of fields.
Declare a field inside an entity block.
Declare a create-time hook for an entity. The hook receives the
Ecto.Changeset and the caller's context map, and must return an
Ecto.Changeset.
Declare a delete-time hook. The hook receives the loaded entity and
the context, and must return :ok or {:error, reason}.
Custom post-login logic. Receives the loaded user and the caller's
context, returns :ok or {:error, reason}.
Custom registration logic. Receives the changeset and the caller's context map, returns the changeset.
Declare an update-time hook. Same shape as on_create/2.
Declare a triple-target policy for entity.
Declare a relation between two entities.
Enable password reset inside an authenticatable block.
Configure session management inside an authenticatable block.
Declare a credential strategy inside an authenticatable block.
Declare the API version for this domain. Must match ~r/^v\d+$/.
Functions
Declare the authenticatable trait on the enclosing entity.
entity :users do
field :email, :string, required: true, unique: true
field :name, :string, required: true
authenticatable do
strategy :password
strategy :api_token, scopes: [:read, :write], ttl: {90, :days}
session :token, ttl: {30, :days}, remember_me: {365, :days}
confirm :email, token_ttl: {24, :hours}
reset :password, token_ttl: {1, :hour}
on_register fn changeset, _ctx -> changeset end
on_login fn user, _ctx ->
if user.suspended, do: {:error, :suspended}, else: :ok
end
end
endSee Caravela.Schema.AuthConfig for the parsed IR.
Authorize creation of an entity. Receives only the context and must
return a boolean.
can_create :books, fn context ->
context.current_user.role in [:admin, :editor]
end
Authorize deletion of an entity. Same shape as can_update/2.
Filter a read query by authorization context. Must return an
Ecto.Query.
can_read :books, fn query, context ->
case context.current_user.role do
:admin -> query
_ -> where(query, [b], b.published == true)
end
end
Authorize updating an entity. Receives the loaded entity and the
context. Must return a boolean.
can_update :books, fn book, context ->
context.current_user.role == :admin or book.author_id == context.current_user.author_id
end
Enable email confirmation inside an authenticatable block.
Declare an entity (a table/schema) with a do block of fields.
entity :books do
field :title, :string, required: true
end
Declare a field inside an entity block.
field :title, :string, required: true, min_length: 3
Declare a create-time hook for an entity. The hook receives the
Ecto.Changeset and the caller's context map, and must return an
Ecto.Changeset.
on_create :books, fn changeset, _context ->
Ecto.Changeset.validate_required(changeset, [:title])
end
Declare a delete-time hook. The hook receives the loaded entity and
the context, and must return :ok or {:error, reason}.
on_delete :authors, fn author, _context ->
if author.published?, do: {:error, :has_published_books}, else: :ok
end
Custom post-login logic. Receives the loaded user and the caller's
context, returns :ok or {:error, reason}.
Custom registration logic. Receives the changeset and the caller's context map, returns the changeset.
Declare an update-time hook. Same shape as on_create/2.
on_update :books, fn changeset, _context ->
changeset
end
Declare a triple-target policy for entity.
policy :books do
scope fn query, actor ->
case actor.role do
:admin -> query
_ -> where(query, [b], b.published == true)
end
end
field :internal_notes, visible: fn actor -> actor.role == :admin end
field :author_email, visible: fn actor, record ->
actor.role == :admin or actor.id == record.author_id
end
allow :create, fn actor -> actor.role in [:admin, :editor] end
allow :update, fn actor, record ->
actor.role == :admin or actor.id == record.author_id
end
allow :delete, fn actor -> actor.role == :admin end
endEach declared rule compiles into a clause of one of three dispatch functions on the domain module:
__caravela_policy_scope__/3—(entity, query, actor)__caravela_policy_field_visible__/3—(entity, field, actor)__caravela_policy_field_visible__/4—(entity, field, actor, record)__caravela_policy_allow__/3—(entity, action, actor)__caravela_policy_allow__/4—(entity, action, actor, record)
The generated context, controller, GraphQL resolvers, and LiveView
modules then invoke these to produce (1) Ecto WHERE clauses, (2)
projected JSON responses with invisible fields removed, and (3) a
typed field_access prop flowing to Svelte components.
Declare a relation between two entities.
relation :authors, :books, type: :has_many
relation :books, :publishers, type: :belongs_to
Enable password reset inside an authenticatable block.
Configure session management inside an authenticatable block.
Declare a credential strategy inside an authenticatable block.
Declare the API version for this domain. Must match ~r/^v\d+$/.
version "v1"When set, all generated modules are namespaced under the version
(MyApp.Library.V1.Book) and controller routes are prefixed with
/api/v1/.