A production-ready starter template for building full-stack, real-time, offline-first applications.
Backend:
Frontend:
DevOps:
git clone <your-repo-url> my-app
cd my-app
# Install git hooks (optional but recommended)
./.githooks/setup.sh
# Backend setup
cd backend
mix deps.get
mix ash_postgres.create
mix ash_postgres.migrate
mix run priv/repo/seeds.exs
# Frontend setup
cd ../frontend
npm install
# Start development servers
cd ..
docker-compose -f docker-compose.dev.yml up -d # PostgreSQL + ElectricSQL
cd backend && mix phx.server & # Backend on :4000
cd frontend && npm run dev # Frontend on :5173
starter-app/
├── backend/ # Phoenix + Ash backend
│ ├── lib/
│ │ ├── starter_app/
│ │ │ ├── auth/ # User & Organization resources
│ │ │ ├── api.ex # Ash Domain
│ │ │ ├── repo.ex # Ecto Repo
│ │ │ └── application.ex # OTP Application
│ │ ├── starter_app_web/
│ │ │ ├── controllers/
│ │ │ ├── endpoint.ex
│ │ │ └── router.ex
│ │ └── starter_app.ex
│ ├── priv/
│ │ └── repo/
│ │ ├── migrations/ # Ash-generated migrations
│ │ └── seeds.exs # Seed data (add your own)
│ ├── config/ # Configuration files
│ └── mix.exs
│
├── frontend/ # SvelteKit frontend
│ ├── src/
│ │ ├── routes/ # SvelteKit routes
│ │ │ ├── +layout.svelte
│ │ │ └── +page.svelte
│ │ └── lib/ # Shared utilities
│ ├── static/
│ ├── package.json
│ └── vite.config.ts
│
├── .github/
│ └── workflows/
│ └── ci.yml # GitHub Actions CI/CD
│
└── docker-compose.dev.yml # Local development setup
Use find & replace across the project:
Backend:
StarterApp → YourApp:starter_app → :your_appstarter_app_dev → your_app_devFrontend:
starter-app-frontend → your-app-frontendFiles to rename:
backend/lib/starter_app/ → backend/lib/your_app/backend/lib/starter_app_web/ → backend/lib/your_app_web/The starter includes base Auth resources (User, Organization). Add your own:
backend/lib/starter_app/your_domain/backend/lib/starter_app/api.exmix ash_postgres.generate_migrations --name add_your_resourcesmix ash_postgres.migratebackend/priv/repo/seeds.exsThis template is designed to integrate with a centralized auth service or implement local authentication:
For centralized auth (recommended for microservices):
lib/starter_app_web/endpoint.exSHARED_TOKEN_SECRET to .envFor local auth:
# Backend
cd backend
mix deps.get # Install dependencies
mix ash_postgres.create # Create database
mix ash_postgres.migrate # Run migrations
mix run priv/repo/seeds.exs # Seed database
mix phx.server # Start server
mix test # Run tests
mix credo # Static analysis
mix dialyzer # Type checking
mix sobelow # Security analysis
# Frontend
cd frontend
npm install # Install dependencies
npm run dev # Start dev server
npm run build # Production build
npm run test # Unit tests
npm run lint # ESLint
npm run check # TypeScript check
Backend (backend/.env):
DATABASE_URL=postgresql://postgres:postgres@localhost:5435/starter_app_dev
SECRET_KEY_BASE=your-secret-key-here
FRONTEND_URL=http://localhost:5173
Frontend (frontend/.env):
VITE_API_URL=http://localhost:4000
PUBLIC_ELECTRIC_URL=http://localhost:3000
cd backend
mix test # All tests
mix test --cover # With coverage
mix dialyzer # Type checking
mix credo # Static analysis
mix sobelow # Security analysis
cd frontend
npm run test # Unit tests (Vitest)
npm run test:coverage # With coverage
npm run lint # ESLint
npm run check # TypeScript
npm run build # Production build
PostgreSQL (source of truth)
↓ (logical replication)
ElectricSQL (sync service)
↓ (HTTP Shape API)
TanStack DB (client store)
↓ (reactive queries)
Svelte UI (components)
All data is scoped by organization_id. ElectricSQL shapes can be filtered by organization for secure multi-tenant sync.
This template follows a centralized infrastructure pattern where PostgreSQL, Redis, Nginx, and SSL are provided by your infrastructure setup.
# 1. Build Docker images
./scripts/deployment/build-backend.sh
./scripts/deployment/build-frontend.sh
# 2. Push to GitHub Container Registry
./scripts/deployment/push-backend.sh
./scripts/deployment/push-frontend.sh
# 3. Deploy via your infrastructure
# See scripts/deployment/README.md for complete guide
Backend (Phoenix + Ash):
backend/Dockerfile/healthDATABASE_URLFrontend (SvelteKit):
frontend/Dockerfileserve/ (root)Your infrastructure should provide:
See scripts/deployment/README.md for complete deployment documentation.
Backend:
See backend/.env.example for complete list. Key variables:
DATABASE_URL - PostgreSQL connection (host: postgres in Docker network)SECRET_KEY_BASE - Generate with mix phx.gen.secretPHX_HOST - Your API domainFRONTEND_URL - Your frontend domain (for CORS)Frontend:
See frontend/.env.example for complete list. Key variables (must be prefixed with PUBLIC_):
PUBLIC_API_URL - Your backend API URLPUBLIC_ELECTRIC_URL - Your ElectricSQL URLMigrations run automatically on backend startup in production via StarterApp.Release.migrate/0.
Or run manually:
# Development
mix ash_postgres.migrate
# Production (in container)
docker exec -it your-backend-container /app/bin/starter_app eval "StarterApp.Release.migrate()"
Both Docker images include health checks for monitoring:
Backend:
curl http://localhost:4000/health
# {"status": "ok", "service": "starter-app", "timestamp": "..."}
curl http://localhost:4000/health/detailed
# Includes database connectivity check
Frontend:
curl http://localhost:3000/
# Returns HTML (200 OK)
All deployment scripts are in scripts/deployment/:
| Script | Purpose |
|---|---|
build-backend.sh |
Build backend Docker image |
build-frontend.sh |
Build frontend Docker image |
push-backend.sh |
Push backend to GHCR |
push-frontend.sh |
Push frontend to GHCR |
See scripts/deployment/README.md for detailed usage and workflows.
This is a starter template - fork it and make it your own!
If you find issues or have improvements for the template itself, please open an issue or PR.