Skip to main content

Docker Development Environment

This document explains how to use the Docker setup for Rainfall-Learning development.

Quick Start

# Build all containers
npm run docker:build

# Start services
npm run docker:start

Option 2: Rebuild and Start (if you have changes)

# Rebuild everything from scratch
npm run docker:rebuild

Services

The Docker Development setup includes three main services:

1. Database (PostgreSQL)

  • Port: localhost:5432
  • Database: rainfall_dev
  • Credentials: postgres/postgres
  • Health Check: Automatically waits for database to be ready

2. Backend (Node.js API)

  • Port: localhost:3000
  • Features:
    • Automatic dependency installation
    • Prisma client generation
    • Database schema reset and migration
    • Hot reloading for development
  • Independent: Handles all setup automatically

3. Frontend (React/Vite)

  • Port: localhost:5173
  • Features:
    • Automatic dependency installation
    • Shared package building
    • Hot reloading for development
    • Connected to backend API

Container Independence

Each container is designed to be completely independent:

Database Container

  • Self-contained: Includes all PostgreSQL dependencies
  • Persistent storage: Data persists between container restarts
  • Health monitoring: Uses pg_isready to verify database readiness
  • Robust checks: 10 retries with 5s intervals, 10s start period

Backend Container

  • Autonomous initialization:
    • Installs its own dependencies
    • Generates Prisma client during build
    • Waits for database health check before starting
    • Resets database schema on startup
    • Applies migrations automatically
  • Robust database connection: Retries until database is ready
  • No manual intervention required: Everything happens automatically

Frontend Container

  • Independent startup: Can start without backend (though API calls will fail)
  • Self-contained: Installs its own dependencies
  • Hot reloading: Changes reflect immediately
  • Shared package building: Automatically builds shared dependencies

Available Commands

# Build all containers
npm run docker:build

# Start services in background
npm run docker:start

# Stop all services
npm run docker:stop

# View logs
npm run docker:logs

# Restart services
npm run docker:restart

# Clean up (removes volumes too)
npm run docker:clean

# Rebuild everything from scratch
npm run docker:rebuild

Health Checks & Reliability

Database Health Monitoring

  • pg_isready: Verifies PostgreSQL is accepting connections
  • Smart retries: 10 attempts with 5-second intervals
  • Start period: 10-second grace period for initial startup
  • Dependency management: Backend waits for healthy database

Backend Connection Logic

  • No arbitrary sleeps: Uses actual database connectivity tests
  • Retry mechanism: Continuously attempts connection until successful
  • Graceful handling: Clear logging of connection attempts
  • Fail-fast: Immediate feedback if database is unreachable

Database Management

Schema Changes

The backend container automatically handles schema changes:

  • Uses prisma migrate reset --force on startup
  • Resets database to clean state
  • Applies all migrations automatically
  • Regenerates Prisma client during build

Adding Migrations (Production)

For production, you should use proper migrations:

# Inside backend container
docker-compose exec backend npx prisma migrate dev --name your_migration_name

Database Reset

To reset the database:

npm run docker:restart

Development Workflow

  1. Start development: npm run docker:start
  2. Make changes: Edit files in packages/backend or packages/frontend
  3. See changes: Hot reloading will automatically reflect changes
  4. Run tests: npm run test (runs inside Docker containers)
  5. Database changes: Edit packages/backend/prisma/schema.prisma, restart backend container
  6. Stop development: npm run docker:stop

Testing in Docker

Test Execution

All tests run inside Docker containers for consistency:

# Run all tests (backend + frontend)
npm run test

# Run specific test suites
npm run test:backend # Backend tests only
npm run test:frontend # Frontend tests only
npm run test:shared # Shared package tests

# Run tests with coverage
npm run test:coverage

# Watch mode for development
npm run test:watch

Test Environment

  • Backend Tests: Run inside backend container with database access
  • Frontend Tests: Run inside frontend container with jsdom environment
  • Shared Imports: All @rainfall/shared imports work correctly
  • Database: Automatically set up when Docker starts

Test Configuration

  • Backend: Uses packages/backend/vitest.config.ts with Node.js environment
  • Frontend: Uses packages/frontend/vitest.config.ts with jsdom environment
  • Path Mapping: TypeScript paths configured for shared package imports
  • Test Location:
    • Frontend tests: packages/frontend/tests/
    • Backend tests: packages/backend/tests/
  • Test Setup: Frontend uses packages/frontend/src/test-setup.ts for jest-dom matchers

Troubleshooting

Container Won't Start

  1. Check logs: npm run docker:logs
  2. Ensure Docker is running
  3. Check if ports are available (5432, 3000, 5173)
  4. Try rebuilding: npm run docker:rebuild

Database Connection Issues

  1. Wait for database health check to pass
  2. Check environment variables in docker-compose.yml
  3. Restart containers: npm run docker:restart

Build Issues

  1. Clean everything: npm run docker:clean
  2. Rebuild from scratch: npm run docker:rebuild
  3. Check Dockerfile syntax and paths

Frontend Can't Connect to Backend

  1. Ensure backend is running (check logs)
  2. Verify VITE_API_URL in environment
  3. Check network connectivity between containers

Environment Variables

The setup uses environment variables defined in docker-compose.yml:

  • DATABASE_URL: PostgreSQL connection string
  • NODE_ENV: Development environment
  • VITE_API_URL: Frontend API URL

Architecture Benefits

  • Independent containers: Each service can run independently
  • Automatic setup: No manual intervention required
  • Consistent environment: Same setup across all developers
  • Easy deployment: Can be easily adapted for production