Comprehensive technical reference for Docker containerization of the Markdown Ticket Board.
This document contains detailed technical specifications, configurations, and troubleshooting information. For getting started, see README.docker.md. For implementation patterns, see DOCKER_GUIDE.md.
- Frontend (dev): Container 5173 → Host 5174
- Frontend (prod): Container 80 → Host 5174
- Backend: Container 3001 → Not exposed (internal only)
- MCP Server: Container 3002 → Host 3012
- Backend is internal only: Runs on Docker network, accessible via frontend proxy at
/api/* - Frontend proxy: All
/api/*requests are proxied to backend on port 3001 - MCP HTTP: Exposed on host port 3012 for LLM client connections
Development Mode:
- Runtime: Vite dev server with Hot Module Replacement (HMR)
- Port: 5173 (container) → 5174 (host)
- Watch:
src/directory for instant updates - Proxy:
/api/*→ backend:3001
Production Mode:
- Runtime: Nginx alpine
- Port: 80 (container) → 80 (host)
- Build: Optimized static files from
bun run build - Proxy:
/api/*→ backend:3001 - User: Non-root
nginxuser
Runtime: Node.js with tsx (TypeScript executor)
Services:
- Express.js API server on port 3001
- Chokidar file watcher (polling mode for Docker)
- Server-Sent Events (SSE) for real-time updates
Watch Paths:
server/- Backend code (auto-restart)/projects- Mounted ticket files (SSE broadcast)
Health Check: GET /api/health
Runtime: Node.js with tsx (TypeScript executor)
Transports:
- HTTP: Enabled on port 3002 (host: 3012)
- Endpoint:
http://localhost:3012/mcp - SSE streaming supported
- Session management via headers
- Endpoint:
Tools Implemented:
list_projects- List all discovered projectsget_project_info- Get project metadatalist_crs- List CRs with filteringget_cr- Get CR by keycreate_cr- Create new CRupdate_cr_status- Update CR statusupdate_cr_attrs- Update CR attributesdelete_cr- Delete CRmanage_cr_sections- CRUD operations on CR sectionssuggest_cr_improvements- Analyze CR completeness
Health Check: GET /health
http://localhost:3012/mcp
| Endpoint | Method | Purpose | Request Format |
|---|---|---|---|
/mcp |
POST | JSON-RPC requests | {"jsonrpc":"2.0","method":"...","params":{...},"id":1} |
/mcp |
GET | SSE streaming | N/A (event stream) |
/health |
GET | Health check | N/A (returns {"status":"ok"}) |
# Standard JSON-RPC
Content-Type: application/json
# Session Management (optional)
Mcp-Session-Id: <session-uuid>The MCP server supports session persistence via the Mcp-Session-Id header:
- First request: Server creates new session, returns
Mcp-Session-Idheader - Subsequent requests: Include the header to maintain session context
- Session scope: Project discovery state, configuration caches
- Session lifecycle: Valid for container lifetime
curl -X POST http://localhost:3012/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "list_projects",
"arguments": {}
},
"id": 1
}'Note: These are optional advanced features for production deployments.
environment:
- MCP_SECURITY_ORIGIN_VALIDATION=true
- MCP_ALLOWED_ORIGINS=https://yourdomain.com,https://app.yourdomain.comValidates Origin header on incoming requests to prevent CSRF attacks.
environment:
- MCP_SECURITY_RATE_LIMITING=true
- MCP_RATE_LIMIT_WINDOW=60000 # 1 minute in ms
- MCP_RATE_LIMIT_MAX=100 # Max requests per windowLimits request rate per IP address to prevent abuse.
environment:
- MCP_SECURITY_AUTH=true
- MCP_AUTH_TOKEN=${MCP_AUTH_TOKEN} # From .env fileRequires Bearer token authentication:
curl -H "Authorization: Bearer ${MCP_AUTH_TOKEN}" \
http://localhost:3012/mcpResource limits are configured in docker-compose.prod.yml. To customize, edit the deploy.resources section for each service.
# Live stats
docker stats
# Per-container stats
docker stats mdt-frontend
docker stats mdt-backend
docker stats mdt-mcp| Aspect | Value | Notes |
|---|---|---|
| RAM usage | ~2GB | All services combined |
| Build size | ~500MB each | Includes dev dependencies |
| Startup time | 10-15s | Node.js + watch mode |
| File watching | Polling mode | Required for Docker volumes |
| Hot reload | <1s | Vite HMR for frontend |
Overhead sources:
- Volume mounting (bind mounts vs layers)
- Polling file watchers (
CHOKIDAR_USEPOLLING=true) - TypeScript compilation (tsx)
| Aspect | Value | Notes |
|---|---|---|
| RAM usage | ~500MB | All services combined |
| Image size | 100-200MB each | Multi-stage builds, no dev deps |
| Startup time | 2-5s | Optimized images |
| Hot reload | None | Static files |
Optimizations:
- Multi-stage Dockerfiles
- Production-only dependencies
- Nginx for static files
- Non-root users
- No volume mounts (code baked into images)
# Check image sizes
docker images
# Check container disk usage
docker system df
# Clean up unused resources
docker system prune -aFrontend (Vite HMR):
- watches:
src/directory - trigger: File save
- latency: <1 second
- preserves: Component state, CSS, console
Backend (tsx watch):
- watches:
server/directory - trigger: File save
- latency: 2-3 seconds (TypeScript compilation)
- effect: Full server restart
MCP (tsx watch):
- watches:
mcp-server/src/directory - trigger: File save
- latency: 2-3 seconds (TypeScript compilation)
- effect: Full server restart, reconnect required
# View container status
docker-compose ps
docker-compose top
# Inspect container
./bin/dc exec backend env # Environment variables
./bin/dc exec backend ls -la /projects # Mounted volumes
./bin/dc exec mcp ps aux # Running processes
# Network issues
./bin/dc exec frontend ping backend # Test internal network
# Check file watching
./bin/dc exec backend ls -la /projects # Verify mounts
./bin/dc logs -f backend | grep watch # Watch events
# MCP debugging
curl http://localhost:3012/health
curl -X POST http://localhost:3012/mcp -d '{"jsonrpc":"2.0","method":"ping","id":1}'| Week | Activity | Goal |
|---|---|---|
| 1 | Parallel setup | Run Docker alongside native, compare performance |
| 2 | Primary Docker | Use Docker for all development work |
| 3 | Feedback | Report issues, performance concerns |
| 4 | Optimization | Adjust based on feedback |
If you need to revert to native Node.js:
# Stop Docker containers
./bin/dc down
# Use native development
bun run dev:fullAll projects and configuration remain unchanged (they're in mounted volumes).
| Aspect | Docker | Native |
|---|---|---|
| Startup | ./bin/dc up |
bun run dev:full |
| Ports | Frontend: 5174, MCP: 3012 | Frontend: 5173, MCP: 3002 |
| File watching | Polling mode (slower) | Native events (faster) |
| Isolation | Containerized | Shared system |
| Build cache | Per-container | Shared npm cache |
Symptom: EACCES or EPERM errors when accessing mounted volumes.
Diagnosis:
./bin/dc exec backend ls -la /projects
./bin/dc exec backend whoamiSolution (development):
# Fix ownership on host
sudo chown -R $(whoami):$(whoami) /path/to/projects
# Or run container as current user (add to docker-compose.dev.yml):
user: "${UID}:${GID}"Symptom: curl: (7) Failed to connect to localhost port 3012
Diagnosis:
./bin/dc ps mcp # Check running
./bin/dc logs -f mcp | tail -20 # Check logs
docker network inspect mdt_default # Check networkCommon causes:
- Container not running:
./bin/dc up -d - Port conflict:
lsof -i :3012 - HTTP transport disabled: Check
MCP_HTTP_ENABLED=true - Wrong port: Verify
MCP_HTTP_PORT=3002(container), mapped to 3012 (host)
Symptom: Frontend shows "Backend disconnected"
Diagnosis:
./bin/dc logs -f backend
./bin/dc exec backend ps aux
./bin/dc exec frontend ping backendCommon causes:
- Backend crashed: Check logs for errors
- Network issue:
docker network inspect mdt_default - No projects mounted: Check volume configuration
Symptom: Changes to files not reflected in UI
Diagnosis:
./bin/dc logs -f backend | grep -i watch
./bin/dc exec backend printenv | grep CHOKIDARVerification:
CHOKIDAR_USEPOLLING=truemust be set- Volumes must be mounted correctly
- Files must be in watched paths (
/projects)
Solution:
# Restart with polling enabled
./bin/dc restart backendSymptom: bun install fails during build
Diagnosis:
./bin/dc logs frontend | grep -i error
./bin/dc exec frontend npm --versionCommon causes:
- Network issues (can't reach npm registry)
- Corrupted cache:
./bin/dc build --no-cache - Platform incompatibility: Check Docker platform (
docker info)
Solution:
# Clean rebuild
./bin/dc down -v
./bin/dc build --no-cache
./bin/dc up -dSymptom: Projects not discovered, "no projects found"
Diagnosis:
./bin/dc exec backend ls -la /projectsCommon causes:
- Wrong volume mount path in
docker-compose.*.yml - Path not mounted in
docker-compose.*.yml - Permission issues (see above)
- Missing global config:
~/.config/markdown-ticket/
Solution:
# Verify mount point
./bin/dc exec backend ls -la /projects
# Check global config
./bin/dc exec backend ls -la /root/.config/markdown-ticket/- README.docker.md - Quick start guide
- DOCKER_GUIDE.md - Implementation patterns and configuration
- MDT-055 - Docker Architecture CR
- MDT-074 - MCP HTTP Transport CR
- MDT-073 - Configuration Management CR