Enkiro is an Elixir + Phoenix application. This guide helps you get the app running locally using Docker and Docker Compose.
- Install Docker Desktop
- Create a persistent volume for PostgreSQL:
docker volume create --name=pg-dataThis ensures your local database retains data between container restarts.
-
Set up Local Development Configuration
For local development, you need to create a docker-compose.override.yml file. This file adds settings like port mapping and volume mounts for live code reloading. A template is provided for you.
Copy the example docker compose override file:
cp docker-compose.override.yml.example docker-compose.override.yml
Copy the
.envfile:cp .env.example .env
Generate the token for the
SECRET_KEY_BASEenvironment variable usingmix phx.gen.secret. Add it to the key in your.envfile.Generate the token for the
GUARDIAN_SECRET_KEYenvironment variable usingmix guardian.gen.secret. Add it to the key in your.envfile. -
Start the Application
Start the Enkiro app in the background with:
docker compose up -d
-
Creating Your User
To create a user run the following:
docker compose run --rm app iex> Enkiro.Accounts.register_user(%{email: "[email protected]", password: "password123password123"})
Once running, visit http://localhost:4000 in your browser to verify it’s working.
To run code or debug interactively via the Elixir IEx shell:
-
Stop the background app if it's running:
docker compose stop app # or docker compose down -
Start an interactive IEx session:
docker compose run --rm app
This launches the app in the foreground and opens an interactive terminal session.
To run the automated test suite:
docker compose run --rm app /bin/bash -c "MIX_ENV=test mix test"The CI pipeline is built on GitHub Actions and is designed to be efficient, secure, and reliable. The configuration is split between two workflow files, .github/workflows/test.yaml and .github/workflows/build.yaml, which are powered by a highly optimized Dockerfile.
Several key decisions were made to ensure the pipeline is as fast and efficient as possible:
-
Multi-Stage Docker Builds: The
Dockerfileis split into multiple stages (base,deps,development,release,final). This allows us to build dependencies and application code in temporary stages that can be discarded, ensuring the final production image is minimal. -
Dependency Caching: A dedicated
depsstage fetches and compiles all project dependencies. Docker caches this layer, so dependencies are only re-compiled when themix.lockfile changes, dramatically speeding up most CI runs. -
Efficient Test Execution: To minimize CI runtime costs, the test workflow combines database creation, migration, and the test run into a single
docker compose runcommand. This avoids the overhead of starting the Elixir application multiple times. -
Secure Test File Handling: The
test/directory is intentionally included in the build context so that the CI pipeline can run automated tests against thedevelopmentimage. However, these files are automatically excluded from the final production image. This is because themix releasecommand intelligently packages only production-necessary code, and ourfinalDocker stage only copies this lean, pre-packaged release artifact, ensuring no test code ever ships to production. -
Lean Production Images: The
finalstage of theDockerfilestarts with a fresh, minimal base image and copies only the compiled release artifact from thereleasestage. This practice ensures the production image is as small and secure as possible, containing no build tools, source code, or test files.
-
Test Workflow (
test.yaml)-
Trigger: Runs on every push to any branch that is not
main. -
Goal: To validate that the code is correct and all tests pass.
-
Process:
-
Builds the
developmentimage from theDockerfile. -
Runs database migrations and the full
mix testsuite within that image.
-
-
-
Build Workflow (
build.yaml)-
Trigger: Runs only on pushes to the
mainbranch. -
Goal: To build the final, production-ready Docker image.
-
Process:
-
Builds the
finalimage from theDockerfile. -
This image is ready to be pushed to a container registry (like Docker Hub or GHCR) for deployment.
-
-
Image Pushing and Tagging:
-
The workflow pushes two versions of the image to ensure both ease of use and the ability to perform precise rollbacks:
-
:latest: A rolling tag that always points to the most recent successful build from themainbranch. -
Git SHA Tag: A unique, immutable tag based on the commit hash (e.g.,
:a1b2c3d4). This allows you to deploy or roll back to a specific version of the code with confidence.
-
-
-