Skip to main content

Overview

SushiGo uses Docker Compose to orchestrate multiple services for development and testing. There are two main compose files:
  • docker-compose.yml - Main development stack
  • docker-compose.e2e.yml - End-to-end testing stack

Development Stack

The main development stack includes six services:

Services Overview

ServiceContainerPurposePorts
devdev_containerMain development environment (API + Webapp)5173
devtestdevtest_containerIsolated testing environment8081, 5174
nginxnginx_proxyReverse proxy with SSL80, 443
pgsqlpostgres_containerPostgreSQL 15 database5432
pgadminpgadmin_containerDatabase management UI5050
mailhogmailhog_containerEmail testing server8025

Service Details

dev (Development Container)

Primary development environment running both Laravel API and React webapp.
service: dev
image: sushigo/dev:local
working_dir: /app/code
ports:
  - "5173:5173"  # Vite dev server
expose:
  - "80"         # Apache (API)
  - "443"        # Apache SSL
Key Environment Variables:
VariableDefaultDescription
VITE_PORT5173Vite dev server port
VITE_HMR_HOSTsushigo.localHot Module Replacement host
VITE_API_URLhttps://api.sushigo.local/api/v1API endpoint for webapp
DB_HOSTpgsqlDatabase host
POSTGRES_DBmydbDatabase name
Health Check:
curl -f http://localhost:80/api/v1/health
Volumes:
  • Host / → Container /app (entire project)
  • Docker socket mounted for Docker-in-Docker operations
  • Apache config mounted for custom SSL/proxy settings

devtest (Testing Container)

Isolated environment for running tests without affecting the main dev database.
service: devtest
image: sushigo/dev:local
ports:
  - "8081:80"     # API
  - "5174:5173"   # Vite
environment:
  - POSTGRES_DB=mydb_devtest
Use Cases:
  • Running integration tests in isolation
  • Testing migrations before applying to dev
  • Parallel development workflows

nginx (Reverse Proxy)

Handles SSL termination and routing for all web services.
service: nginx
image: nginx:alpine
ports:
  - "80:80"
  - "443:443"
Routing Configuration:
DomainBackendPurpose
sushigo.localdev:5173Webapp (Vite)
api.sushigo.localdev:80API (Apache)
devtest.sushigo.localdevtest:5173Webapp (test)
devtest.api.sushigo.localdevtest:80API (test)
SSL Certificates: Self-signed certificates located in:
docker/app/config/dev/cert/
├── rootCA.pem            # Root CA certificate
├── sushigo.local.crt     # Site certificate
└── sushigo.local-key.pem # Private key
Install rootCA.pem in your system’s trust store to avoid browser warnings.

pgsql (PostgreSQL)

PostgreSQL 15 database server with automatic initialization.
service: pgsql
image: postgres:15
ports:
  - "5432:5432"
environment:
  POSTGRES_USER: admin
  POSTGRES_PASSWORD: admin
  POSTGRES_DB: mydb
Databases:
DatabasePurposeCreated by
mydbMain development databaseDocker compose
mydb_testPHPUnit testing databaseInit script
mydb_devtestIsolated testing environmentInit script
mydb_e2eE2E testing databaseE2E compose
Initialization Script: docker/pgsql/init-test-db.sh automatically creates test databases on first run. Persistent Storage: Data is stored in the pg_data Docker volume to persist across container restarts.

pgadmin (Database UI)

Web-based PostgreSQL administration tool.
service: pgadmin
image: dpage/pgadmin4:7.6
ports:
  - "5050:80"
credentials:
  email: [email protected]
  password: admin
Pre-configured Server: Connection details are automatically loaded from docker/pgadmin/servers.json.

mailhog (Email Testing)

SMTP server for capturing outgoing emails during development.
service: mailhog
image: mailhog/mailhog
ports:
  - "8025:8025"  # Web UI
Configuration: Laravel .env should use:
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
All emails sent by the API will appear in the Mailhog UI at http://localhost:8025.

E2E Testing Stack

The E2E stack extends the main stack with Cypress testing services.

test_e2e (E2E Environment)

service: test_e2e
container: e2e_container
environment:
  - POSTGRES_DB=mydb_e2e
  - CYPRESS_baseUrl=https://sushigo.e2e.local
Uses a separate database (mydb_e2e) to avoid interfering with development data.

cypress (Headless Runner)

service: cypress
image: cypress/included:13.17.0
working_dir: /app/code/webapp
command: ["npm install && npx cypress run"]
Runs Cypress tests in headless mode (CI/CD compatible).

cypress-ui (Interactive Mode)

service: cypress-ui
ports:
  - "6080:6080"  # noVNC web interface
  - "5900:5900"  # VNC direct
environment:
  DISPLAY: :99
Provides a browser UI via VNC for interactive test development. Access at http://localhost:6080.

Docker Commands

Starting Services

# Start all development services
docker compose up --build

# Start in background
docker compose up -d

Stopping Services

# Stop all services
docker compose down

# Stop and remove volumes (⚠️ deletes database data)
docker compose down -v

# Stop specific service
docker compose stop dev

Viewing Logs

docker compose logs -f

Restarting Services

# Restart all
docker compose restart

# Restart specific service
docker compose restart dev
docker compose restart nginx

Executing Commands

# Enter dev container shell
docker exec -it dev_container bash

# Run artisan command
docker exec -it dev_container bash -c "cd /app/code/api && php artisan migrate"

# Run npm command
docker exec -it dev_container bash -c "cd /app/code/webapp && npm run build"

# Database commands
docker exec -it postgres_container psql -U admin -d mydb

Makefile Shortcuts

The project includes a Makefile with convenient shortcuts:
CommandDescription
make helpShow all available commands
make e2e-upStart E2E container
make e2e-downStop E2E container
make e2e-restartRestart E2E container
make e2e-logsView E2E logs
make cypress-uiOpen Cypress interactive UI (VNC)
make cypress-runRun Cypress tests headless
make db-seedRun database seeders
make ssl-infoShow SSL certificate information
make hosts-setupDisplay hosts file configuration instructions
make chrome-clear-hstsInstructions for clearing Chrome HSTS cache
Run make help to see all available commands with descriptions.

Network Architecture

All services communicate over a shared Docker bridge network: Service Discovery: Services reference each other by service name:
  • API connects to pgsql:5432 (not localhost:5432)
  • Webapp proxies API requests through nginx
  • Mailhog is accessible as mailhog:1025 for SMTP

Health Checks

All critical services define health checks to ensure proper startup order:
# PostgreSQL must be ready before API starts
pgsql:
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U admin -d mydb"]
    interval: 5s
    retries: 5

# API must respond before nginx starts
dev:
  healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:80/api/v1/health"]
    interval: 10s
    start_period: 40s
Use depends_on with condition: service_healthy to control startup order.

Volumes

Named Volumes

VolumePurposeData
pg_dataPostgreSQL dataDatabases, tables, indexes
cypress-cacheCypress binariesShared across E2E containers

Bind Mounts

Host PathContainer PathPurpose
.//appEntire project (live reload)
./docker/nginx/nginx.conf/etc/nginx/nginx.confNginx configuration
./docker/app/config/dev/cert/etc/nginx/certsSSL certificates
/var/run/docker.sock/var/run/docker.sockDocker-in-Docker access
Bind mounts enable live code reload but can cause performance issues on macOS/Windows. Consider using named volumes for node_modules if needed.

Troubleshooting

# Check for port conflicts
docker compose ps
lsof -i :80
lsof -i :443
lsof -i :5432

# View detailed logs
docker compose logs dev
docker compose logs pgsql

# Rebuild from scratch
docker compose down -v
docker compose build --no-cache
docker compose up
# Wait for PostgreSQL to be healthy
docker compose ps pgsql

# Check database exists
docker exec -it postgres_container psql -U admin -l

# Create test database manually
docker exec -it postgres_container psql -U admin -d mydb \
  -c "CREATE DATABASE mydb_test;"
# Verify certificates exist
ls -la docker/app/config/dev/cert/

# Rebuild dev container to regenerate certs
docker compose build dev
docker compose up -d dev

# Check nginx configuration
docker exec -it nginx_proxy nginx -t
docker compose logs nginx
# Force recreate containers
docker compose up -d --force-recreate

# Remove all containers and volumes
docker compose down -v
docker volume prune

# Clean rebuild
docker compose build --no-cache
docker compose up

Next Steps

Environment Setup

Initial setup and VS Code configuration

Testing

Run tests across all environments

Build docs developers (and LLMs) love