Local Development Setup

This page covers the local development infrastructure in depth, including Docker Compose services, SSL configuration, running services individually, working with email templates, and common debugging workflows.

Docker Compose Local Configuration

The file docker-compose.local.yml defines three infrastructure services that run as Docker containers while the application microservices run natively on your host machine.

Services

MongoDB

Property Value
Image mongo:7-jammy
Container name eteamups-mongodb-local
Host port 27018
Container port 27017
Volume mongodb_local_data:/data/db

The MongoDB instance is initialised with root credentials and a default database via environment variables (MONGO_INITDB_ROOT_USERNAME, MONGO_INITDB_ROOT_PASSWORD, MONGO_INITDB_DATABASE). An initialisation script at scripts/mongo-init.js is mounted into the container’s /docker-entrypoint-initdb.d/ directory and runs on first start.

The host port is 27018 (not the default 27017) to avoid conflicts with any locally installed MongoDB instance. Your .env file should use the connection string:

MONGODB_URL=mongodb://admin:password123@localhost:27018/eteamups?authSource=admin

Redis

Property Value
Image redis:7-alpine
Container name eteamups-redis-local
Host port 6379
Container port 6379
Volume redis_local_data:/data

Redis runs with append-only persistence enabled (redis-server --appendonly yes). It is used by BullMQ for the message queue.

Nginx

Property Value
Image nginx:alpine
Container name eteamups-nginx-local
HTTP port 8080 (maps to container port 80)
HTTPS port 18443 (maps to container port 443)

Nginx acts as an API gateway and TLS termination point. Configuration files are mounted read-only from the repository:

  • nginx/nginx.local.conf – main Nginx config
  • nginx/conf.d/local.conf – server blocks with proxy rules
  • ssl/ – self-signed certificates

The Nginx container uses extra_hosts to map service names to host-gateway, allowing it to proxy requests to microservices running on the host machine via host.docker.internal.

Routing table:

Gateway URL Target
https://localhost:18443/auth/* http://host.docker.internal:9000
https://localhost:18443/profile/* http://host.docker.internal:9100
https://localhost:18443/organisation/* http://host.docker.internal:9107
https://localhost:18443/media/* http://host.docker.internal:9102

HTTP requests on port 8080 are automatically redirected to HTTPS on port 18443.

Managing Docker Containers

# Start all containers
npm run deps:start

# Stop all containers
npm run deps:stop

# Check container status
npm run deps:check

# Restart Docker Desktop and containers (macOS)
npm run docker:restart

Data Persistence

Both MongoDB and Redis use named Docker volumes (mongodb_local_data and redis_local_data). Data survives container restarts. To completely reset your local data, remove the volumes:

docker volume rm eteamups-platform_mongodb_local_data eteamups-platform_redis_local_data

Then re-seed:

npm run deps:start
npm run seed

Self-Signed SSL Certificates

The Nginx container requires SSL certificates at /etc/nginx/ssl/nginx.crt and /etc/nginx/ssl/nginx.key. Generate them using the provided script:

bash scripts/generate-ssl.sh

This creates a ssl/ directory at the project root with:

  • nginx.crt – self-signed certificate valid for 365 days, issued to localhost
  • nginx.key – 2048-bit RSA private key (permissions set to 600)

The certificate is generated with the following subject:

/C=US/ST=California/L=San Francisco/O=eTeamups/OU=Development/CN=localhost

Since this is a self-signed certificate, browsers will display a security warning. You can proceed past it, or add the certificate to your system trust store for a smoother experience.

Running Individual Services

For focused development or debugging, you can run a single service instead of the entire stack:

# Start only the Auth service
npm run auth

# Start only the Profile service
npm run profile

# Start only the Organisation service
npm run organisation

# Start only the Media service
npm run media

# Start only the Message Queue worker
npm run message-queue

Each command uses ts-node to run libs/server/src/run.ts with the service-specific development config file as an argument. For example, npm run auth executes:

ts-node --require ./instrumentation.ts --require dotenv/config \
  --project ./tsconfig.json \
  ./libs/server/src/run.ts ./services/auth/src/config/server.config.dev.ts

Make sure the Docker containers (MongoDB, Redis) are running before starting any service, since all services depend on these infrastructure components.

Email Template Development

The platform uses React Email for authoring email templates. A dedicated development server provides a live preview of your templates.

Starting the Email Dev Server

npm run email:dev

This starts the React Email preview server on port 3010. Open http://localhost:3010 in your browser to view and iterate on email templates.

Email Template Structure

emails/
  admin_otp.tsx       # React Email component (OTP email)
  html/               # Compiled HTML templates used at runtime
  mjml/               # MJML source templates

The runtime email sending flow uses compiled HTML templates from emails/html/. The EmailUtility.compile() method loads an HTML file and replaces {{variable}} placeholders with values from a context object.

Workflow

  1. Author or edit a .tsx template in emails/.
  2. Preview it with npm run email:dev.
  3. Export/compile the template to HTML and place it in emails/html/.
  4. The application uses EmailUtility.compile('template_name', { key: 'value' }) to render the final HTML at send time.

Generating and Viewing OpenAPI Specs

Generate the OpenAPI specification from your service routes:

npm run swagger:generate

This produces both JSON and YAML files in the swagger/ directory:

  • swagger/zeswa-hub-open-api.json
  • swagger/zeswa-hub-open-api.yaml

You can view the spec using any OpenAPI viewer, such as Swagger Editor or a VS Code extension.

Common Development Workflows

Adding a New Route to an Existing Service

  1. Create a new route handler file in services/{name}/src/modules/routes/{feature}/{action}.ts.
  2. If a middleware for this feature domain already exists, the route will be picked up automatically through the existing middleware’s route registration.
  3. If this is a new feature domain, create a new middleware class in services/{name}/src/middleware/{Feature}Middleware.ts that extends BasicMiddleware.
  4. Register the new middleware path in the service’s server.config.dev.ts and server.config.prod.ts.

Adding a New Database Model

  1. Define the TypeScript interface in services/store/src/dto/I{Entity}.ts.
  2. Create the Mongoose schema in services/store/src/schema/{Entity}Schema.ts.
  3. Create a model class in services/store/src/model/{Entity}Model.ts that extends BaseModel<T>.
  4. (Optional) Add seed data in services/store/src/seed/{collection}.js.

Running Tests

npm test

Tests use Jest with dotenv/config loaded automatically. The --runInBand flag ensures tests run sequentially, and --detectOpenHandles and --forceExit handle any lingering async operations. For testing individual services, the libs/server/src/testRunner.ts helper can spin up an Express app with the test configuration.

Building for Production

npm run build

This runs tsc -p tsconfig.json and outputs compiled JavaScript to the dist/ directory. Production scripts (e.g., npm run auth:prod) reference files from dist/.

Debugging Tips

Service will not start

  • Verify Docker containers are running: npm run deps:check.
  • Check that .env is present and has the correct MONGODB_URL pointing to localhost:27018.
  • Look for port conflicts: lsof -i :9000 (replace with the relevant port).
  • Kill stale processes: npm run kill.

Cannot connect to MongoDB

  • Confirm the container is healthy: docker logs eteamups-mongodb-local.
  • Verify the connection string uses port 27018 (not 27017).
  • Test connectivity: mongosh "mongodb://admin:password123@localhost:27018/eteamups?authSource=admin".

Cannot connect to Redis

  • Confirm the container is up: docker logs eteamups-redis-local.
  • Test connectivity: redis-cli -h localhost -p 6379 ping (should return PONG).

Nginx returns 502/503

  • The target service is not running on the host. Start it with the corresponding npm run {service} command.
  • Nginx logs are written to the logs/ directory at the project root.

OpenTelemetry / tracing not working

  • Set OPEN_TELEMENTRY=true in your .env.
  • Ensure OTEL_EXPORTER_OTLP_ENDPOINT points to a running OTLP collector.
  • Tracing is initialised in instrumentation.ts at the project root and in libs/server/src/tracer.ts.

Clearing all local data

npm run deps:stop
docker volume rm eteamups-platform_mongodb_local_data eteamups-platform_redis_local_data
npm run deps:start
npm run seed