A production-ready Phoenix application demonstrating best practices for CI/CD pipelines, comprehensive testing, code quality, and deployment strategies.
- RESTful API: Full CRUD operations for task management
- Comprehensive Testing: Unit and integration tests with >90% coverage
- CI/CD Pipeline: Automated testing, code quality checks, and deployment with GitHub Actions
- Code Quality: Credo for style, Dialyzer for types, Sobelow for security
- Docker Ready: Containerized deployment with docker-compose
- Production Config: Proper releases and secrets management
- Test Coverage: ExCoveralls integration with coverage reporting
- Database Migrations: Ecto migrations for schema management
- LiveDashboard: Real-time metrics and debugging in development
- Elixir 1.15
- Phoenix Framework 1.7
- PostgreSQL 15
- Ecto (Database wrapper)
- ExUnit (Testing)
- ExCoveralls (Coverage reporting)
- Credo (Code quality)
- Dialyzer (Static analysis)
- Sobelow (Security scanning)
- Elixir 1.14 or later
- Erlang/OTP 26 or later
- PostgreSQL 15 or later
- Node.js 18 or later (for asset compilation)
git clone https://github.com/codeforgood-org/elixir-ci-pipeline-demo.git
cd elixir-ci-pipeline-demo# Install Elixir dependencies
mix deps.get
# Install Node.js dependencies for assets
cd assets && npm install && cd ..Create a .env file in the root directory:
cp .env.example .envEdit the .env file with your database credentials.
# Create and migrate the database
mix ecto.setup
# This runs:
# - ecto.create (creates the database)
# - ecto.migrate (runs migrations)
# - run priv/repo/seeds.exs (seeds sample data)# Start Phoenix server
mix phx.server
# Or start in interactive mode
iex -S mix phx.serverVisit http://localhost:4000 to see the application.
API endpoints are available at http://localhost:4000/api.
# Run all tests
mix test
# Run tests with coverage
mix coveralls
# Run tests with HTML coverage report
mix coveralls.html
# Run tests in watch mode
mix test.watch# Run Credo for code quality checks
mix credo --strict
# Check code formatting
mix format --check-formatted
# Fix code formatting
mix format
# Run Dialyzer for static analysis
mix dialyzer
# Run Sobelow for security scanning
mix sobelow --config# Create a new migration
mix ecto.gen.migration migration_name
# Run migrations
mix ecto.migrate
# Rollback last migration
mix ecto.rollback
# Reset database (drop, create, migrate, seed)
mix ecto.reset
# Check migration status
mix ecto.migrations# Start IEx with your application
iex -S mix
# Reload modules after changes
recompile()
# Access LiveDashboard (when server is running)
# Visit http://localhost:4000/dev/dashboardSee API.md for detailed API documentation.
List all tasks:
curl http://localhost:4000/api/tasksCreate a task:
curl -X POST http://localhost:4000/api/tasks \
-H "Content-Type: application/json" \
-d '{"task": {"title": "My Task", "priority": "high"}}'Update a task:
curl -X PUT http://localhost:4000/api/tasks/1 \
-H "Content-Type: application/json" \
-d '{"task": {"status": "done"}}'Delete a task:
curl -X DELETE http://localhost:4000/api/tasks/1# Build and start all services
docker-compose up --build
# Run in detached mode
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
# Stop and remove volumes
docker-compose down -v# Build the Docker image
docker build -t task-manager:latest .
# Run the container
docker run -p 4000:4000 \
-e DATABASE_URL=ecto://user:pass@host/db \
-e SECRET_KEY_BASE=your_secret_key \
task-manager:latestThis project uses GitHub Actions for continuous integration and deployment.
- Setup: Cache dependencies for faster builds
- Test: Run full test suite with PostgreSQL
- Coverage: Generate and upload coverage reports
- Code Quality: Run Credo for style checks
- Formatting: Verify code formatting
- Security: Run Sobelow security scans
- Dialyzer: Perform static type analysis
- Build Docker: Build and cache Docker image
# Install act (GitHub Actions local runner)
# https://github.com/nektos/act
# Run all workflows
act
# Run specific job
act -j test.
├── .github/
│ └── workflows/ # GitHub Actions CI/CD pipelines
├── assets/ # Frontend assets (JS, CSS)
├── config/ # Application configuration
├── lib/
│ ├── task_manager/ # Business logic and contexts
│ │ ├── tasks/ # Tasks domain
│ │ └── repo.ex # Database repository
│ └── task_manager_web/
│ ├── controllers/ # API controllers
│ ├── components/ # Reusable components
│ └── router.ex # Route definitions
├── priv/
│ ├── repo/
│ │ └── migrations/ # Database migrations
│ └── static/ # Static files
├── test/ # Test files
├── docker-compose.yml # Docker composition
├── Dockerfile # Production Dockerfile
└── mix.exs # Project dependencies
Create a .env file for local development:
# Database
DATABASE_URL=ecto://postgres:postgres@localhost/task_manager_dev
POOL_SIZE=10
# Phoenix
SECRET_KEY_BASE=your_secret_key_base_here
PHX_HOST=localhost
PORT=4000
# Optional
ECTO_IPV6=false# Generate a secret key base
mix phx.gen.secret
# Generate a secure random string
openssl rand -base64 48# Set environment
export MIX_ENV=prod
# Install dependencies
mix deps.get --only prod
# Compile assets
mix assets.deploy
# Build release
mix release
# Run release
_build/prod/rel/task_manager/bin/serverRequired environment variables for production:
DATABASE_URL=ecto://user:pass@host:5432/database
SECRET_KEY_BASE=your_very_long_secret_key_base
PHX_HOST=your-domain.com
PORT=4000Access the Phoenix LiveDashboard at:
- Development: http://localhost:4000/dev/dashboard
- Production: Configure authentication before exposing
The application includes:
- Telemetry metrics for Phoenix, Ecto, and VM
- Request logging with request IDs
- Health check endpoint (Docker)
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow the Elixir style guide
- Run
mix formatbefore committing - Ensure all tests pass:
mix test - Maintain test coverage above 90%
- Pass all Credo checks:
mix credo --strict
test/
├── support/ # Test helpers and fixtures
│ ├── conn_case.ex # Controller test setup
│ ├── data_case.ex # Database test setup
│ └── fixtures/ # Test data fixtures
├── task_manager/ # Context tests
└── task_manager_web/ # Controller tests
# Example test
defmodule TaskManager.TasksTest do
use TaskManager.DataCase
alias TaskManager.Tasks
test "create_task/1 creates a task with valid data" do
attrs = %{title: "Test Task", priority: "high"}
assert {:ok, task} = Tasks.create_task(attrs)
assert task.title == "Test Task"
end
endDatabase connection error:
# Check PostgreSQL is running
pg_isready
# Verify credentials in config/dev.exsPort already in use:
# Change port in config/dev.exs or use:
PORT=4001 mix phx.serverAsset compilation fails:
# Reinstall node dependencies
cd assets && rm -rf node_modules && npm install && cd ..Dialyzer warnings:
# Clean and rebuild PLT
mix dialyzer --clean
mix dialyzer --plt- Database queries use proper indexing
- Ecto preloading to avoid N+1 queries
- Connection pooling for database
- Static asset compression in production
- CSRF protection enabled
- SQL injection prevention via Ecto
- XSS protection in templates
- Security headers configured
- Regular dependency updates
- Sobelow security scanning in CI
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with Phoenix Framework
- Inspired by Phoenix best practices and real-world production applications
- Community contributions and feedback
For issues and questions:
- Open an issue on GitHub
- Check existing documentation
- Review the API documentation in API.md
- Add authentication and authorization
- Implement WebSocket support for real-time updates
- Add pagination for task lists
- Implement task filtering and search
- Add GraphQL API alongside REST
- Deploy to production (Fly.io, Render, etc.)
- Add monitoring with AppSignal or New Relic
- Implement rate limiting
- Add API versioning
- Create admin dashboard
Built with ❤️ using Elixir and Phoenix