Skip to content

Repository files navigation

Caravela Command Center

caravela_demo

A Phoenix + LiveView + Svelte Command Center built on Caravela, driving the Library domain (authors, books, publishers) end-to-end — from domain declaration to generated CRUD to live flows.


Files created by hand

These were written directly to scaffold the app:

Path Purpose
mix.exs Project definition; depends on caravela from Hex (override via CARAVELA_PATH for local hacking), plus phoenix, live_svelte, ecto_sql, postgrex. Adds ecto.* / assets.* aliases and a Mix release config.
.formatter.exs Imports formatter rules from :ecto, :ecto_sql, and :caravela (so entity / field / relation stay unparenthesised).
.gitignore Standard Elixir ignores plus .env / secrets/ rules.
.dockerignore Keeps _build/, deps/, node_modules/, secrets and markdown out of the Docker build context.
config/config.exs Registers CaravelaDemo.Repo; sets migration primary/foreign keys to :binary_id to match Caravela's generated schemas.
config/dev.exs Local Postgres connection (user postgres, db caravela_demo_dev, port 5432) plus LiveReload and the Vite watcher.
config/test.exs Test Repo config with Ecto.Adapters.SQL.Sandbox.
config/prod.exs Prod compile-time config — static manifest, request-id logger metadata.
config/runtime.exs Reads DATABASE_URL / SECRET_KEY_BASE (plus *_FILE variants for Docker secrets) and forces PHX_HOST at boot.
lib/caravela_demo.ex Top-level module with a short moduledoc.
lib/caravela_demo/application.ex OTP application; supervises Repo, PubSub, FlowRegistry, Caravela.Flow.Supervisor, FlowController, and the Endpoint.
lib/caravela_demo/repo.ex Ecto.Repo for Postgres.
lib/caravela_demo/release.ex Release.migrate/0 called from bin/migrate inside the compiled release.
lib/caravela_demo/domains/library.ex The Caravela domain declaration — entities authors, books, publishers and their relations.
lib/caravela_demo_web/controllers/health_controller.ex /health/live (VM only) and /health/ready (VM + Repo ping).
Dockerfile Multi-stage build: Elixir + Node assets → mix release → slim Debian runtime as non-root app user.
rel/env.sh.eex, rel/overlays/bin/server, rel/overlays/bin/migrate Release overlays — starts the endpoint and runs migrations from inside the release.
docker-compose.yaml Local Postgres 16-alpine for development.
docker-stack.yaml Production stack for Docker Swarm — app + migration one-shot + postgres, with Docker secrets and healthchecks.

Files generated by Caravela

Produced by mix caravela.gen.schema CaravelaDemo.Domains.Library — do not edit by hand, regenerate instead:

Commands run to bootstrap

# 1. Fetch deps (caravela from Hex, plus phoenix/ecto_sql/postgrex/…)
mix deps.get

# 2. Compile the bare app to make sure the scaffold is valid
mix compile

# 3. Preview what Caravela would generate from the domain
mix caravela.gen.schema CaravelaDemo.Domains.Library --dry-run

# 4. Generate Ecto schemas and the migration for real
mix caravela.gen.schema CaravelaDemo.Domains.Library --force

# 5. Recompile with the generated schemas in place
mix compile

Hacking on Caravela itself? Point the dep back at a local checkout with CARAVELA_PATH=../caravela mix deps.get (the mix.exs helper respects the env var). Unset it to return to the Hex version.

Running the demo end-to-end

docker compose up -d        # start Postgres
mix ecto.setup              # create DB + run the generated migration
mix assets.setup            # install the Vite/Svelte JS deps
iex -S mix phx.server       # http://localhost:4000

To rewrite schemas after editing lib/caravela_demo/domains/library.ex:

mix caravela.gen.schema CaravelaDemo.Domains.Library --force
mix ecto.reset

Production deployment

This repo ships two production artefacts: a Dockerfile that builds a self-contained Mix release, and a docker-stack.yaml targeting Docker Swarm. Both are intentionally minimal so they're easy to adapt to Kamal, Fly, k8s, or plain docker run.

1. Build the image

docker build -t ghcr.io/rsousacode/caravela-demo:latest .
docker push ghcr.io/rsousacode/caravela-demo:latest

The build fetches caravela from Hex, compiles assets with Vite, runs mix release, and copies the release into a slim debian:bookworm-slim runtime. The final image runs as a non-root user, exposes port 4000, and boots via tini → /app/bin/server.

2. Runtime configuration

config/runtime.exs reads the following at boot:

Variable Required Notes
DATABASE_URL / DATABASE_URL_FILE ecto://USER:PASS@HOST/DB. _FILE form reads from a path (Docker secret).
SECRET_KEY_BASE / SECRET_KEY_BASE_FILE 64+ bytes — mix phx.gen.secret.
PHX_HOST Public hostname, e.g. demo.example.com. Used for URL generation and check_origin.
PHX_SCHEME https (default) or http.
PHX_URL_PORT External port the browser sees — defaults to 443 / 80.
PORT Port the BEAM binds to (default 4000).
POOL_SIZE DB pool size (default 10).
DATABASE_SSL true to require TLS to Postgres.
ECTO_IPV6 true when the DB host only resolves via IPv6.
LOG_LEVEL debug / info (default) / warning / error.

3. Deploy to Docker Swarm

# 1. Create swarm secrets (once, per node group)
printf '%s' "$(mix phx.gen.secret)"                         | docker secret create caravela_demo_secret_key_base -
printf '%s' 'ecto://app:APP_PASSWORD@postgres/caravela_demo_prod' | docker secret create caravela_demo_database_url -
printf '%s' 'APP_PASSWORD'                                  | docker secret create caravela_demo_postgres_password -

# 2. Point the stack at your image + hostname
export IMAGE=ghcr.io/rsousacode/caravela-demo:latest
export PHX_HOST=demo.example.com

# 3. Deploy
docker stack deploy -c docker-stack.yaml caravela-demo

# 4. Watch the one-shot migration service run to completion
docker service logs -f caravela-demo_migrate

# 5. Tail the app
docker service logs -f caravela-demo_app

The stack exposes the app on ${APP_PORT:-4000} so you can terminate TLS with Traefik / Caddy / Nginx in front. Uncomment the Traefik labels in docker-stack.yaml if you're running Traefik inside the same swarm.

4. Healthchecks

Path Checks Use for
GET /health/live BEAM + Endpoint respond Liveness probe. Don't couple to the DB — you want to keep the container up while you fix the DB.
GET /health/ready Liveness + SELECT 1 against the Repo Readiness probe. Gate traffic until the Repo is reachable.

5. Is docker-stack.yaml safe to commit?

Yes. It contains no secret values — only references to three external Docker secrets (caravela_demo_secret_key_base, caravela_demo_database_url, caravela_demo_postgres_password) that you create on the swarm out of band. Hostnames and image tags come from env vars (PHX_HOST, IMAGE) at deploy time, so nothing site-specific is baked into the file either. If you ever inline a password or a real hostname, move it to a secret or a .env first — .gitignore already blocks .env*, *.pem, *.key, and secrets/.

License

MIT — see LICENSE. Builds on Caravela, which is licensed under MPL-2.0.

About

Command Center demo for Caravela: a live tour of its domain DSL, generators, flows, forms, and CRUD.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages