services: # =========================================== # Infrastructure # =========================================== postgres: image: postgres:16-alpine environment: POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5 restart: unless-stopped rabbitmq: image: rabbitmq:3-management-alpine environment: RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-guest} RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-guest} volumes: - rabbitmq_data:/var/lib/rabbitmq healthcheck: test: ["CMD", "rabbitmq-diagnostics", "check_running"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped # =========================================== # Backend Services # =========================================== novel-service: image: git.orfl.xyz/conco/fictionarchive-novel-service:latest environment: ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_NovelService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq Novelpia__Username: ${NOVELPIA_USERNAME} Novelpia__Password: ${NOVELPIA_PASSWORD} NovelUpdateService__PendingImageUrl: https://files.fictionarchive.orfl.xyz/api/pendingupload.png healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy restart: unless-stopped translation-service: image: git.orfl.xyz/conco/fictionarchive-translation-service:latest environment: ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_TranslationService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq DeepL__ApiKey: ${DEEPL_API_KEY} healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy restart: unless-stopped scheduler-service: image: git.orfl.xyz/conco/fictionarchive-scheduler-service:latest environment: ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_SchedulerService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy restart: unless-stopped user-service: image: git.orfl.xyz/conco/fictionarchive-user-service:latest environment: ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_UserService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy restart: unless-stopped authentication-service: image: git.orfl.xyz/conco/fictionarchive-authentication-service:latest environment: ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 depends_on: rabbitmq: condition: service_healthy restart: unless-stopped file-service: image: git.orfl.xyz/conco/fictionarchive-file-service:latest environment: ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq S3__Endpoint: ${S3_ENDPOINT:-https://s3.orfl.xyz} S3__Bucket: ${S3_BUCKET:-fictionarchive} S3__AccessKey: ${S3_ACCESS_KEY} S3__SecretKey: ${S3_SECRET_KEY} Proxy__BaseUrl: https://files.orfl.xyz/api healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 labels: - "traefik.enable=true" - "traefik.http.routers.file-service.rule=Host(`files.orfl.xyz`)" - "traefik.http.routers.file-service.entrypoints=websecure" - "traefik.http.routers.file-service.tls.certresolver=letsencrypt" - "traefik.http.services.file-service.loadbalancer.server.port=8080" depends_on: rabbitmq: condition: service_healthy restart: unless-stopped # =========================================== # API Gateway # =========================================== api-gateway: image: git.orfl.xyz/conco/fictionarchive-api:latest environment: ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 labels: - "traefik.enable=true" - "traefik.http.routers.api-gateway.rule=Host(`api.fictionarchive.orfl.xyz`)" - "traefik.http.routers.api-gateway.entrypoints=websecure" - "traefik.http.routers.api-gateway.tls.certresolver=letsencrypt" - "traefik.http.services.api-gateway.loadbalancer.server.port=8080" depends_on: - novel-service - translation-service - scheduler-service - user-service - authentication-service - file-service restart: unless-stopped # =========================================== # Frontend # =========================================== frontend: image: git.orfl.xyz/conco/fictionarchive-frontend:latest healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost/"] interval: 30s timeout: 10s retries: 3 labels: - "traefik.enable=true" - "traefik.http.routers.frontend.rule=Host(`fictionarchive.orfl.xyz`)" - "traefik.http.routers.frontend.entrypoints=websecure" - "traefik.http.routers.frontend.tls.certresolver=letsencrypt" - "traefik.http.services.frontend.loadbalancer.server.port=80" restart: unless-stopped volumes: postgres_data: rabbitmq_data: letsencrypt: