Skip to content

Fully containerized development environment #567

Description

@umxr

Context

Follow-up to #561 which added Docker Compose for infrastructure services (PostgreSQL + Redis). As discussed in the review, a fully containerized setup would lower the barrier for new contributors by removing the need to install Ruby, Node, and system dependencies locally.

Goal

Run the entire development stack with a single docker compose up — Rails server, asset watchers, Sidekiq, PostgreSQL, and Redis — while preserving a fast feedback loop (live code reloading, sub-second asset rebuilds).

High-Level Spec

1. Development Dockerfile (docker/dev/Dockerfile)

A multi-stage Dockerfile targeting development:

  • Base image: Ruby 3.3.3 on Debian slim
  • System dependencies: build-essential, libpq-dev, libvips (for image_processing gem), ffmpeg (for streamio-ffmpeg), Node.js 20, Yarn
  • Ruby layer: bundle install with Bundler cache mounted as a named volume (avoids reinstalling on every rebuild)
  • Node layer: npm install with node_modules as a named volume
  • No asset precompilation at build time — asset watchers handle this at runtime

2. Compose services (docker-compose.yml)

Extend the existing compose file with application services:

Service Image / Build Command Purpose
db postgres:14 (existing) PostgreSQL
redis redis:7 (existing) Redis
web Build from docker/dev/Dockerfile bin/rails server -b 0.0.0.0 -p 3000 Rails server
js Same image as web yarn build --reload esbuild watcher
tailwind Same image as web bin/rails tailwindcss:watch Tailwind CSS watcher
sidekiq Same image as web bundle exec sidekiq Background jobs

All app services should:

  • Depend on db (healthy) and redis
  • Bind-mount the project root to /app for live code reloading
  • Use named volumes for node_modules and bundle to avoid overwriting host dirs
  • Share a common x-app anchor (YAML merge key) to avoid config duplication
  • Set environment variables: DB_HOST=db, DB_USERNAME=postgres, DB_PASSWORD=password, REDIS_URL=redis://redis:6379/0

3. Volume strategy

volumes:
  qul-postgres-data:   # existing
  qul-redis-data:      # existing
  qul-bundle:          # gem cache — survives rebuilds
  qul-node-modules:    # node_modules — avoids platform mismatch with host

The project root is bind-mounted (./:/app) so code edits on the host are reflected immediately. node_modules and bundle are named volumes so native extensions are compiled for the container's Linux arch rather than the host OS.

4. First-run experience

The target developer experience:

git clone git@github.com:TarteelAI/quranic-universal-library.git
cd quranic-universal-library
docker compose up
# wait for build + boot, then visit http://localhost:3000

On first run, the developer needs a single command to set up both databases (create, load the Quranic data dump, and run migrations):

docker compose exec web rails db:setup db:migrate

The db:setup task should handle creating the databases and loading the Quranic data dump (quran_dev), so contributors don't need to manually download and import SQL files as separate steps.

5. Developer workflow commands

Document common workflows:

Task Command
Start everything docker compose up
First-time DB setup (create, load dump, migrate) docker compose exec web rails db:setup db:migrate
Rails console docker compose exec web rails console
Run migrations docker compose exec web rails db:migrate
Install new gem docker compose exec web bundle install
Install npm package docker compose exec web npm install <pkg>
RuboCop docker compose exec web bundle exec rubocop
Rebuild after Gemfile/Dockerfile change docker compose up --build

6. README updates

Add a "Full Docker Setup" section alongside the existing "Quick Start with Docker" and "Manual Setup" sections, covering:

  • Prerequisites (Docker + Docker Compose only)
  • First-run setup steps
  • Common commands reference table above

Acceptance Criteria

  • docker compose build completes successfully
  • docker compose up starts all 6 services (db, redis, web, js, tailwind, sidekiq)
  • rails db:setup db:migrate creates both databases, loads the Quranic data dump, and runs all migrations in one command
  • Editing a Ruby file triggers automatic reload in the web container
  • Editing a JS file triggers esbuild rebuild via the js container
  • Editing a Tailwind class triggers CSS rebuild via the tailwind container
  • docker compose exec web rails console works
  • Existing infrastructure-only workflow (DB_HOST=localhost with local Ruby) still works unchanged
  • README documents the full containerized workflow

Out of scope

  • Production Docker images / Kubernetes manifests
  • CI/CD Docker builds
  • .devcontainer / VS Code Dev Container config (could be a future follow-up)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions