services: backend: image: "${HARBOR_REGISTRY:-114.55.99.6:10081}/wordcloud/wordcloud-backend:${IMAGE_TAG:-latest}" build: context: ./backend dockerfile: Dockerfile container_name: wordcloud-backend ports: - "8000:8000" environment: AI_CONVERTER_URL: http://ai-converter:8090 volumes: - wordcloud_workspace:/app/service_workspace - wordcloud_assets:/app/service_assets - wordcloud_projects:/app/service_projects - wordcloud_design_templates:/app/service_design_templates - wordcloud_fonts:/app/service_fonts restart: unless-stopped depends_on: ai-converter: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"] interval: 30s timeout: 10s retries: 3 start_period: 60s # Private SVG -> AI5 converter. It deliberately has no published host port; # browser traffic must go through the backend's /api/exports/ai endpoint. ai-converter: image: "${HARBOR_REGISTRY:-114.55.99.6:10081}/wordcloud/wordcloud-ai-converter:${IMAGE_TAG:-latest}" build: context: ./ai-converter dockerfile: Dockerfile container_name: wordcloud-ai-converter restart: unless-stopped read_only: true tmpfs: - /tmp security_opt: - no-new-privileges:true healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8090/health', timeout=3).read()"] interval: 30s timeout: 5s retries: 3 start_period: 15s frontend: image: "${HARBOR_REGISTRY:-114.55.99.6:10081}/wordcloud/wordcloud-frontend:${IMAGE_TAG:-latest}" build: context: ./frontend dockerfile: Dockerfile container_name: wordcloud-frontend ports: - "3000:80" depends_on: backend: condition: service_healthy restart: unless-stopped volumes: wordcloud_workspace: wordcloud_assets: wordcloud_projects: wordcloud_design_templates: wordcloud_fonts: