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 confignginx/conf.d/local.conf– server blocks with proxy rulesssl/– 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 tolocalhostnginx.key– 2048-bit RSA private key (permissions set to600)
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
- Author or edit a
.tsxtemplate inemails/. - Preview it with
npm run email:dev. - Export/compile the template to HTML and place it in
emails/html/. - 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.jsonswagger/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
- Create a new route handler file in
services/{name}/src/modules/routes/{feature}/{action}.ts. - If a middleware for this feature domain already exists, the route will be picked up automatically through the existing middleware’s route registration.
- If this is a new feature domain, create a new middleware class in
services/{name}/src/middleware/{Feature}Middleware.tsthat extendsBasicMiddleware. - Register the new middleware path in the service’s
server.config.dev.tsandserver.config.prod.ts.
Adding a New Database Model
- Define the TypeScript interface in
services/store/src/dto/I{Entity}.ts. - Create the Mongoose schema in
services/store/src/schema/{Entity}Schema.ts. - Create a model class in
services/store/src/model/{Entity}Model.tsthat extendsBaseModel<T>. - (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
.envis present and has the correctMONGODB_URLpointing tolocalhost: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(not27017). - 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 returnPONG).
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=truein your.env. - Ensure
OTEL_EXPORTER_OTLP_ENDPOINTpoints to a running OTLP collector. - Tracing is initialised in
instrumentation.tsat the project root and inlibs/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