Initial commit
Some checks failed
CI/CD Pipeline / Code Quality & Linting (push) Has been cancelled
CI/CD Pipeline / Policy Validation (push) Has been cancelled
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-firm-connectors) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-forms) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-hmrc) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ingestion) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-normalize-map) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ocr) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-indexer) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-reason) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rpa) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (ui-review) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (ui-review) (push) Has been cancelled
CI/CD Pipeline / Generate SBOM (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Notifications (push) Has been cancelled
Some checks failed
CI/CD Pipeline / Code Quality & Linting (push) Has been cancelled
CI/CD Pipeline / Policy Validation (push) Has been cancelled
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-firm-connectors) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-forms) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-hmrc) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ingestion) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-normalize-map) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ocr) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-indexer) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-reason) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rpa) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (ui-review) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (ui-review) (push) Has been cancelled
CI/CD Pipeline / Generate SBOM (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Notifications (push) Has been cancelled
This commit is contained in:
133
infra/compose/README.md
Normal file
133
infra/compose/README.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# External Services
|
||||
|
||||
This directory contains Docker Compose configurations for external services that run on the production server.
|
||||
|
||||
## Services
|
||||
|
||||
### Traefik
|
||||
- **Location**: `traefik/`
|
||||
- **Purpose**: Reverse proxy and load balancer for all services
|
||||
- **Deploy**: `cd traefik && docker compose up -d`
|
||||
- **Access**: https://traefik.harkon.co.uk
|
||||
|
||||
### Authentik
|
||||
- **Location**: `authentik/`
|
||||
- **Purpose**: SSO and authentication provider
|
||||
- **Deploy**: `cd authentik && docker compose up -d`
|
||||
- **Access**: https://authentik.harkon.co.uk
|
||||
|
||||
### Gitea
|
||||
- **Location**: `gitea/`
|
||||
- **Purpose**: Git repository hosting and container registry
|
||||
- **Deploy**: `cd gitea && docker compose up -d`
|
||||
- **Access**: https://gitea.harkon.co.uk
|
||||
|
||||
### Nextcloud
|
||||
- **Location**: `nextcloud/`
|
||||
- **Purpose**: File storage and collaboration
|
||||
- **Deploy**: `cd nextcloud && docker compose up -d`
|
||||
- **Access**: https://nextcloud.harkon.co.uk
|
||||
|
||||
### Portainer
|
||||
- **Location**: `portainer/`
|
||||
- **Purpose**: Docker management UI
|
||||
- **Deploy**: `cd portainer && docker compose up -d`
|
||||
- **Access**: https://portainer.harkon.co.uk
|
||||
|
||||
## Deployment
|
||||
|
||||
### Production (Remote Server)
|
||||
|
||||
```bash
|
||||
# SSH to server
|
||||
ssh deploy@141.136.35.199
|
||||
|
||||
# Navigate to service directory
|
||||
cd /opt/ai-tax-agent/infra/compose/<service>
|
||||
|
||||
# Deploy service
|
||||
docker compose up -d
|
||||
|
||||
# Check logs
|
||||
docker compose logs -f
|
||||
|
||||
# Check status
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
### Local Development
|
||||
|
||||
For local development, use the all-in-one compose file:
|
||||
|
||||
```bash
|
||||
cd infra/compose
|
||||
docker compose -f docker-compose.local.yml up -d
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Each service has its own `.env` file for environment-specific configuration:
|
||||
|
||||
- `traefik/.provider.env` - GoDaddy API credentials
|
||||
- `authentik/.env` - Authentik secrets
|
||||
- `gitea/.env` - Gitea database credentials
|
||||
|
||||
## Networks
|
||||
|
||||
All services use shared Docker networks:
|
||||
|
||||
- `frontend` - Public-facing services
|
||||
- `backend` - Internal services
|
||||
|
||||
Create networks before deploying:
|
||||
|
||||
```bash
|
||||
docker network create frontend
|
||||
docker network create backend
|
||||
```
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Update Service
|
||||
|
||||
```bash
|
||||
cd /opt/ai-tax-agent/infra/compose/<service>
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Restart Service
|
||||
|
||||
```bash
|
||||
cd /opt/ai-tax-agent/infra/compose/<service>
|
||||
docker compose restart
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
cd /opt/ai-tax-agent/infra/compose/<service>
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
### Backup Data
|
||||
|
||||
```bash
|
||||
# Backup volumes
|
||||
docker run --rm -v <service>_data:/data -v $(pwd):/backup alpine tar czf /backup/<service>-backup.tar.gz /data
|
||||
```
|
||||
|
||||
## Integration with Application
|
||||
|
||||
These external services are used by the application infrastructure:
|
||||
|
||||
- **Traefik** - Routes traffic to application services
|
||||
- **Authentik** - Provides SSO for application UIs
|
||||
- **Gitea** - Hosts Docker images for application services
|
||||
|
||||
The application infrastructure is deployed separately using:
|
||||
|
||||
```bash
|
||||
./infra/scripts/deploy.sh production infrastructure
|
||||
./infra/scripts/deploy.sh production services
|
||||
```
|
||||
127
infra/compose/authentik/compose.yaml
Normal file
127
infra/compose/authentik/compose.yaml
Normal file
@@ -0,0 +1,127 @@
|
||||
---
|
||||
services:
|
||||
authentik-server:
|
||||
image: ghcr.io/goauthentik/server:2025.8.1
|
||||
container_name: authentik-server
|
||||
command: server
|
||||
environment:
|
||||
- AUTHENTIK_REDIS__HOST=authentik-redis
|
||||
- AUTHENTIK_POSTGRESQL__HOST=authentik-postgres
|
||||
- AUTHENTIK_POSTGRESQL__USER=${POSTGRES_USER:-authentik}
|
||||
- AUTHENTIK_POSTGRESQL__NAME=${POSTGRES_DB:-authentik}
|
||||
- AUTHENTIK_POSTGRESQL__PASSWORD=${POSTGRES_PASSWORD:?error}
|
||||
- AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY:?error}
|
||||
- AUTHENTIK_ERROR_REPORTING__ENABLED=${AUTHENTIK_ERROR_REPORTING:-false}
|
||||
|
||||
labels:
|
||||
# (Optional) Enable Traefik integration for the Authentik Web UI. For more information
|
||||
# about integrating other services with Traefik and Authentik, see the
|
||||
# documentation at https://goauthentik.io/docs/outposts/integrations/traefik
|
||||
# and the middleware example files in `docker-compose/traefik/config`.
|
||||
- traefik.enable=true
|
||||
- traefik.http.services.authentik.loadbalancer.server.port=9000
|
||||
- traefik.http.services.authentik.loadbalancer.server.scheme=http
|
||||
- traefik.http.routers.authentik.entrypoints=websecure
|
||||
- traefik.http.routers.authentik.rule=Host(`authentik.harkon.co.uk`)
|
||||
- traefik.http.routers.authentik.tls=true
|
||||
- traefik.http.routers.authentik.tls.certresolver=godaddy
|
||||
- traefik.http.routers.authentik.service=authentik
|
||||
volumes:
|
||||
- ./media:/media
|
||||
- ./custom-templates:/templates
|
||||
depends_on:
|
||||
- authentik-postgres
|
||||
- authentik-redis
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
|
||||
authentik-worker:
|
||||
image: ghcr.io/goauthentik/server:2025.8.1
|
||||
container_name: authentik-worker
|
||||
command: worker
|
||||
environment:
|
||||
- AUTHENTIK_REDIS__HOST=authentik-redis
|
||||
- AUTHENTIK_POSTGRESQL__HOST=authentik-postgres
|
||||
- AUTHENTIK_POSTGRESQL__USER=${POSTGRES_USER:-authentik}
|
||||
- AUTHENTIK_POSTGRESQL__NAME=${POSTGRES_DB:-authentik}
|
||||
- AUTHENTIK_POSTGRESQL__PASSWORD=${POSTGRES_PASSWORD:?error}
|
||||
- AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY:?error}
|
||||
- AUTHENTIK_ERROR_REPORTING__ENABLED=${AUTHENTIK_ERROR_REPORTING:-false}
|
||||
# (Optional) Enable Email Sending
|
||||
# Highly recommended to notify you about alerts and configuration issues.
|
||||
# - AUTHENTIK_EMAIL__HOST=${EMAIL_HOST:?error}
|
||||
# - AUTHENTIK_EMAIL__PORT=${EMAIL_PORT:-25}
|
||||
# - AUTHENTIK_EMAIL__USERNAME=${EMAIL_USERNAME:?error}
|
||||
# - AUTHENTIK_EMAIL__PASSWORD=${EMAIL_PASSWORD:?error}
|
||||
# - AUTHENTIK_EMAIL__USE_TLS=${EMAIL_USE_TLS:-false}
|
||||
# - AUTHENTIK_EMAIL__USE_SSL=${EMAIL_USE_SSL:-false}
|
||||
# - AUTHENTIK_EMAIL__TIMEOUT=${EMAIL_TIMEOUT:-10}
|
||||
# - AUTHENTIK_EMAIL__FROM=${EMAIL_FROM:?error}
|
||||
# (Optional) See more for the docker socket integration here:
|
||||
# https://goauthentik.io/docs/outposts/integrations/docker
|
||||
user: root
|
||||
volumes:
|
||||
- /run/docker.sock:/run/docker.sock
|
||||
- ./media:/media
|
||||
- ./certs:/certs
|
||||
- ./custom-templates:/templates
|
||||
depends_on:
|
||||
- authentik-postgres
|
||||
- authentik-redis
|
||||
networks:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
|
||||
authentik-redis:
|
||||
image: docker.io/library/redis:8.2.1
|
||||
container_name: authentik-redis
|
||||
command: --save 60 1 --loglevel warning
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 3s
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
|
||||
authentik-postgres:
|
||||
# (Optional) Add a PostgreSQL Database for Authentik
|
||||
# Alternatively, you can host your PostgreSQL database externally, and
|
||||
# change the connection settings in the `authentik-server` and
|
||||
# `authentik-worker`.
|
||||
image: docker.io/library/postgres:17.6
|
||||
container_name: authentik-db
|
||||
environment:
|
||||
- POSTGRES_USER=${POSTGRES_USER:-authentik}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?error}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-authentik}
|
||||
- TZ=${TZ:-UTC}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", 'pg_isready -U "${POSTGRES_USER:-authentik}"']
|
||||
start_period: 30s
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
external: true
|
||||
backend:
|
||||
external: true
|
||||
990
infra/compose/docker-compose.backend.yml
Normal file
990
infra/compose/docker-compose.backend.yml
Normal file
@@ -0,0 +1,990 @@
|
||||
# FILE: infra/compose/docker-compose.local.yml
|
||||
# Traefik (with Authentik ForwardAuth), Authentik, Vault, MinIO, Qdrant, Neo4j, Postgres, Redis, Prometheus/Grafana, Loki, Unleash, all services
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
external: true
|
||||
name: ai-tax-agent-frontend
|
||||
|
||||
backend:
|
||||
external: true
|
||||
name: ai-tax-agent-backend
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
neo4j_data:
|
||||
neo4j_logs:
|
||||
qdrant_data:
|
||||
minio_data:
|
||||
vault_data:
|
||||
redis_data:
|
||||
nats_data:
|
||||
prometheus_data:
|
||||
grafana_data:
|
||||
loki_data:
|
||||
authentik_data:
|
||||
portainer-data:
|
||||
|
||||
services:
|
||||
# Identity & SSO
|
||||
authentik-db:
|
||||
image: postgres:15-alpine
|
||||
container_name: authentik-db
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- authentik_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: authentik
|
||||
POSTGRES_USER: authentik
|
||||
POSTGRES_PASSWORD: ${AUTHENTIK_DB_PASSWORD:-authentik}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U authentik"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
authentik-redis:
|
||||
image: redis:7-alpine
|
||||
container_name: authentik-redis
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
command: --save 60 1 --loglevel warning
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
authentik-server:
|
||||
image: ghcr.io/goauthentik/server:2025.8.3
|
||||
container_name: authentik-server
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
command: server
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: authentik-redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: authentik-db
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD:-authentik}
|
||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-changeme}
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED: false
|
||||
# Optional bootstrap for automated setup (create admin and API token)
|
||||
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL:-admin@local.lan}
|
||||
AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD:-admin123}
|
||||
AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN:-}
|
||||
volumes:
|
||||
- ./authentik/media:/media
|
||||
- ./authentik/custom-templates:/templates
|
||||
- ./authentik/bootstrap.yaml:/blueprints/bootstrap.yaml
|
||||
depends_on:
|
||||
- authentik-db
|
||||
- authentik-redis
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.authentik.rule=Host(`auth.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.authentik.entrypoints=websecure"
|
||||
- "traefik.http.routers.authentik.tls=true"
|
||||
- "traefik.docker.network=ai-tax-agent-frontend"
|
||||
- "traefik.http.services.authentik.loadbalancer.server.port=9000"
|
||||
|
||||
authentik-worker:
|
||||
image: ghcr.io/goauthentik/server:2025.8.3
|
||||
container_name: authentik-worker
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
command: worker
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: authentik-redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: authentik-db
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD:-authentik}
|
||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-changeme}
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED: false
|
||||
volumes:
|
||||
- ./authentik/media:/media
|
||||
- ./authentik/custom-templates:/templates
|
||||
depends_on:
|
||||
- authentik-db
|
||||
- authentik-redis
|
||||
|
||||
authentik-outpost:
|
||||
image: ghcr.io/goauthentik/proxy:2025.8.3
|
||||
container_name: authentik-outpost
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
AUTHENTIK_HOST: http://authentik-server:9000
|
||||
AUTHENTIK_INSECURE: true
|
||||
AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN:-changeme}
|
||||
AUTHENTIK_REDIS__HOST: authentik-redis
|
||||
AUTHENTIK_REDIS__PORT: 6379
|
||||
depends_on:
|
||||
- authentik-server
|
||||
- authentik-redis
|
||||
|
||||
# Secrets Management
|
||||
vault:
|
||||
image: hashicorp/vault:1.15
|
||||
container_name: vault
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
ports:
|
||||
- "8200:8200"
|
||||
volumes:
|
||||
- vault_data:/vault/data
|
||||
- ./vault/config:/vault/config:ro
|
||||
environment:
|
||||
VAULT_DEV_ROOT_TOKEN_ID: ${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200
|
||||
command: vault server -dev -dev-listen-address=0.0.0.0:8200
|
||||
cap_add:
|
||||
- IPC_LOCK
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.vault.rule=Host(`vault.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.vault.entrypoints=websecure"
|
||||
- "traefik.http.routers.vault.tls=true"
|
||||
- "traefik.http.routers.vault.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.vault.loadbalancer.server.port=8200"
|
||||
|
||||
# Object Storage
|
||||
minio:
|
||||
image: minio/minio:RELEASE.2025-09-07T16-13-09Z
|
||||
container_name: minio
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
ports:
|
||||
- "9092:9092"
|
||||
- "9093:9093"
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minio}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-miniopass}
|
||||
MINIO_BROWSER_REDIRECT_URL: https://minio.${DOMAIN:-local.lan}
|
||||
command: server /data --address ":9092" --console-address ":9093"
|
||||
healthcheck:
|
||||
test: ["CMD", "mc", "--version"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.minio-api.rule=Host(`minio-api.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.minio-api.entrypoints=websecure"
|
||||
- "traefik.http.routers.minio-api.tls=true"
|
||||
- "traefik.http.routers.minio-api.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.routers.minio-api.service=minio-api"
|
||||
- "traefik.http.services.minio-api.loadbalancer.server.port=9092"
|
||||
- "traefik.http.routers.minio-console.rule=Host(`minio.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.minio-console.entrypoints=websecure"
|
||||
- "traefik.http.routers.minio-console.tls=true"
|
||||
- "traefik.http.routers.minio-console.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.routers.minio-console.service=minio-console"
|
||||
- "traefik.http.services.minio-console.loadbalancer.server.port=9093"
|
||||
|
||||
# Vector Database
|
||||
qdrant:
|
||||
image: qdrant/qdrant:v1.7.4
|
||||
container_name: qdrant
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
ports:
|
||||
- "6333:6333"
|
||||
- "6334:6334"
|
||||
volumes:
|
||||
- qdrant_data:/qdrant/storage
|
||||
environment:
|
||||
QDRANT__SERVICE__GRPC_PORT: ${QDRANT__SERVICE__GRPC_PORT:-6334}
|
||||
QDRANT__SERVICE__HTTP_PORT: 6333
|
||||
QDRANT__LOG_LEVEL: INFO
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.qdrant.rule=Host(`qdrant.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.qdrant.entrypoints=websecure"
|
||||
- "traefik.http.routers.qdrant.tls=true"
|
||||
- "traefik.http.routers.qdrant.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.qdrant.loadbalancer.server.port=6333"
|
||||
|
||||
# Knowledge Graph Database
|
||||
neo4j:
|
||||
image: neo4j:5.15-community
|
||||
container_name: neo4j
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
ports:
|
||||
- "7474:7474"
|
||||
- "7687:7687"
|
||||
volumes:
|
||||
- neo4j_data:/data
|
||||
- neo4j_logs:/logs
|
||||
- ./neo4j/plugins:/plugins
|
||||
environment:
|
||||
NEO4J_AUTH: neo4j/${NEO4J_PASSWORD:-neo4jpass}
|
||||
NEO4J_PLUGINS: '["apoc", "graph-data-science"]'
|
||||
NEO4J_dbms_security_procedures_unrestricted: gds.*,apoc.*
|
||||
NEO4J_dbms_security_procedures_allowlist: gds.*,apoc.*
|
||||
NEO4J_apoc_export_file_enabled: true
|
||||
NEO4J_apoc_import_file_enabled: true
|
||||
NEO4J_apoc_import_file_use__neo4j__config: true
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.neo4j.rule=Host(`neo4j.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.neo4j.entrypoints=websecure"
|
||||
- "traefik.http.routers.neo4j.tls=true"
|
||||
- "traefik.http.routers.neo4j.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.neo4j.loadbalancer.server.port=7474"
|
||||
|
||||
# Secure Client Data Store
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: postgres
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./postgres/init:/docker-entrypoint-initdb.d
|
||||
environment:
|
||||
POSTGRES_DB: tax_system
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||
POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256"
|
||||
command: >
|
||||
postgres
|
||||
-c shared_preload_libraries=pg_stat_statements
|
||||
-c pg_stat_statements.track=all
|
||||
-c max_connections=200
|
||||
-c shared_buffers=256MB
|
||||
-c effective_cache_size=1GB
|
||||
-c maintenance_work_mem=64MB
|
||||
-c checkpoint_completion_target=0.9
|
||||
-c wal_buffers=16MB
|
||||
-c default_statistics_target=100
|
||||
-c random_page_cost=1.1
|
||||
-c effective_io_concurrency=200
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# Cache & Session Store
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: redis
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
command: >
|
||||
redis-server
|
||||
--appendonly yes
|
||||
--appendfsync everysec
|
||||
--maxmemory 512mb
|
||||
--maxmemory-policy allkeys-lru
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# Message Broker & Event Streaming
|
||||
nats:
|
||||
image: nats:2.10-alpine
|
||||
container_name: nats
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
ports:
|
||||
- "4222:4222" # NATS client connections
|
||||
- "8222:8222" # HTTP monitoring
|
||||
- "6222:6222" # Cluster routing (for future clustering)
|
||||
volumes:
|
||||
- nats_data:/data
|
||||
command: >
|
||||
--jetstream
|
||||
--store_dir=/data
|
||||
--http_port=8222
|
||||
environment:
|
||||
NATS_LOG_LEVEL: ${NATS_LOG_LEVEL:-info}
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD",
|
||||
"wget",
|
||||
"--no-verbose",
|
||||
"--tries=1",
|
||||
"--spider",
|
||||
"http://localhost:8222/healthz",
|
||||
]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.nats-monitor.rule=Host(`nats.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.nats-monitor.entrypoints=websecure"
|
||||
- "traefik.http.routers.nats-monitor.tls=true"
|
||||
- "traefik.http.routers.nats-monitor.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.nats-monitor.loadbalancer.server.port=8222"
|
||||
|
||||
# Monitoring & Observability
|
||||
prometheus:
|
||||
image: prom/prometheus:v2.48.1
|
||||
container_name: prometheus
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- prometheus_data:/prometheus
|
||||
command:
|
||||
- "--config.file=/etc/prometheus/prometheus.yml"
|
||||
- "--storage.tsdb.path=/prometheus"
|
||||
- "--web.console.libraries=/etc/prometheus/console_libraries"
|
||||
- "--web.console.templates=/etc/prometheus/consoles"
|
||||
- "--storage.tsdb.retention.time=30d"
|
||||
- "--web.enable-lifecycle"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.prometheus.rule=Host(`prometheus.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.prometheus.entrypoints=websecure"
|
||||
- "traefik.http.routers.prometheus.tls=true"
|
||||
- "traefik.http.routers.prometheus.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:10.2.3
|
||||
container_name: grafana
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- grafana_data:/var/lib/grafana
|
||||
- ./grafana/provisioning:/etc/grafana/provisioning:ro
|
||||
- ./grafana/dashboards:/var/lib/grafana/dashboards:ro
|
||||
environment:
|
||||
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
|
||||
GF_USERS_ALLOW_SIGN_UP: false
|
||||
GF_USERS_AUTO_ASSIGN_ORG: true
|
||||
GF_USERS_AUTO_ASSIGN_ORG_ROLE: Viewer
|
||||
GF_AUTH_GENERIC_OAUTH_ENABLED: true
|
||||
GF_AUTH_GENERIC_OAUTH_NAME: Authentik
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_ID: ${GRAFANA_OAUTH_CLIENT_ID:-grafana}
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: ${GRAFANA_OAUTH_CLIENT_SECRET:-changeme-grafana-secret}
|
||||
GF_AUTH_GENERIC_OAUTH_SCOPES: openid profile email groups
|
||||
GF_AUTH_GENERIC_OAUTH_AUTH_URL: https://auth.${DOMAIN:-local.lan}/application/o/authorize/
|
||||
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: https://auth.${DOMAIN:-local.lan}/application/o/token/
|
||||
GF_AUTH_GENERIC_OAUTH_API_URL: https://auth.${DOMAIN:-local.lan}/application/o/userinfo/
|
||||
GF_AUTH_GENERIC_OAUTH_AUTO_LOGIN: false
|
||||
GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: true
|
||||
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: role
|
||||
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_STRICT: false
|
||||
GF_AUTH_GENERIC_OAUTH_GROUPS_ATTRIBUTE_PATH: groups
|
||||
GF_AUTH_OAUTH_AUTO_LOGIN: false
|
||||
GF_AUTH_DISABLE_LOGIN_FORM: false
|
||||
# Cookie and security settings
|
||||
GF_SERVER_ROOT_URL: https://grafana.${DOMAIN:-local.lan}
|
||||
GF_SERVER_SERVE_FROM_SUB_PATH: false
|
||||
GF_SECURITY_COOKIE_SECURE: false
|
||||
GF_SECURITY_COOKIE_SAMESITE: lax
|
||||
GF_AUTH_GENERIC_OAUTH_USE_PKCE: true
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.grafana.entrypoints=websecure"
|
||||
- "traefik.http.routers.grafana.tls=true"
|
||||
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
|
||||
|
||||
loki:
|
||||
image: grafana/loki:2.9.4
|
||||
container_name: loki
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
ports:
|
||||
- "3100:3100"
|
||||
volumes:
|
||||
- loki_data:/loki
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.loki.rule=Host(`loki.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.loki.entrypoints=websecure"
|
||||
- "traefik.http.routers.loki.tls=true"
|
||||
- "traefik.http.routers.loki.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.loki.loadbalancer.server.port=3100"
|
||||
|
||||
# Feature Flags
|
||||
unleash:
|
||||
image: unleashorg/unleash-server:5.7.3
|
||||
container_name: unleash
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
ports:
|
||||
- "4242:4242"
|
||||
environment:
|
||||
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/unleash
|
||||
DATABASE_SSL: false
|
||||
LOG_LEVEL: info
|
||||
depends_on:
|
||||
- postgres
|
||||
labels:
|
||||
- "traefik.docker.network=ai-tax-agent-frontend"
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.unleash.rule=Host(`unleash.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.unleash.entrypoints=websecure"
|
||||
- "traefik.http.routers.unleash.tls=true"
|
||||
- "traefik.http.routers.unleash.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.unleash.loadbalancer.server.port=4242"
|
||||
|
||||
# Application Services
|
||||
svc-ingestion:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_ingestion/Dockerfile
|
||||
container_name: svc-ingestion
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- vault
|
||||
- minio
|
||||
- postgres
|
||||
- redis
|
||||
- nats
|
||||
- neo4j
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-ingestion.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/ingestion`)"
|
||||
- "traefik.http.routers.svc-ingestion.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-ingestion.tls=true"
|
||||
- "traefik.http.routers.svc-ingestion.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-ingestion.loadbalancer.server.port=8000"
|
||||
|
||||
svc-extract:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_extract/Dockerfile
|
||||
container_name: svc-extract
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- RAG_EMBEDDING_MODEL=${RAG_EMBEDDING_MODEL:-bge-small-en-v1.5}
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- vault
|
||||
- minio
|
||||
- postgres
|
||||
- nats
|
||||
- neo4j
|
||||
- redis
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-extract.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/extract`)"
|
||||
- "traefik.http.routers.svc-extract.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-extract.tls=true"
|
||||
- "traefik.http.routers.svc-extract.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-extract.loadbalancer.server.port=8000"
|
||||
|
||||
svc-kg:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_kg/Dockerfile
|
||||
container_name: svc-kg
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- NEO4J_URI=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4jpass}
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- vault
|
||||
- neo4j
|
||||
- nats
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-kg.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/kg`)"
|
||||
- "traefik.http.routers.svc-kg.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-kg.tls=true"
|
||||
- "traefik.http.routers.svc-kg.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-kg.loadbalancer.server.port=8000"
|
||||
|
||||
svc-rag-retriever:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_rag_retriever/Dockerfile
|
||||
container_name: svc-rag-retriever
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- NEO4J_URI=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4jpass}
|
||||
- RAG_EMBEDDING_MODEL=${RAG_EMBEDDING_MODEL:-bge-small-en-v1.5}
|
||||
- RAG_RERANKER_MODEL=${RAG_RERANKER_MODEL:-cross-encoder/ms-marco-MiniLM-L-6-v2}
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- vault
|
||||
- qdrant
|
||||
- neo4j
|
||||
- nats
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-rag-retriever.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/rag`)"
|
||||
- "traefik.http.routers.svc-rag-retriever.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-rag-retriever.tls=true"
|
||||
- "traefik.http.routers.svc-rag-retriever.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-rag-retriever.loadbalancer.server.port=8000"
|
||||
|
||||
svc-coverage:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_coverage/Dockerfile
|
||||
container_name: svc-coverage
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- ../../config:/app/config:ro
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- NEO4J_URI=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4jpass}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- RAG_SERVICE_URL=http://svc-rag-retriever:8000
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- vault
|
||||
- neo4j
|
||||
- postgres
|
||||
- nats
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-coverage.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/coverage`)"
|
||||
- "traefik.http.routers.svc-coverage.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-coverage.tls=true"
|
||||
- "traefik.http.routers.svc-coverage.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-coverage.loadbalancer.server.port=8000"
|
||||
|
||||
svc-firm-connectors:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_firm_connectors/Dockerfile
|
||||
container_name: svc-firm-connectors
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- ../../config:/app/config:ro
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
|
||||
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- postgres
|
||||
- neo4j
|
||||
- minio
|
||||
- qdrant
|
||||
- nats
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-firm-connectors.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/firm-connectors`)"
|
||||
- "traefik.http.routers.svc-firm-connectors.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-firm-connectors.tls=true"
|
||||
- "traefik.http.routers.svc-firm-connectors.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-firm-connectors.loadbalancer.server.port=8000"
|
||||
|
||||
svc-forms:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_forms/Dockerfile
|
||||
container_name: svc-forms
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- ../../config:/app/config:ro
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
|
||||
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- postgres
|
||||
- neo4j
|
||||
- minio
|
||||
- qdrant
|
||||
- nats
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-forms.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/forms`)"
|
||||
- "traefik.http.routers.svc-forms.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-forms.tls=true"
|
||||
- "traefik.http.routers.svc-forms.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-forms.loadbalancer.server.port=8000"
|
||||
|
||||
svc-hmrc:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_hmrc/Dockerfile
|
||||
container_name: svc-hmrc
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- ../../config:/app/config:ro
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
|
||||
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- postgres
|
||||
- neo4j
|
||||
- minio
|
||||
- qdrant
|
||||
- nats
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-hmrc.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/hmrc`)"
|
||||
- "traefik.http.routers.svc-hmrc.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-hmrc.tls=true"
|
||||
- "traefik.http.routers.svc-hmrc.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-hmrc.loadbalancer.server.port=8000"
|
||||
|
||||
svc-normalize-map:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_normalize_map/Dockerfile
|
||||
container_name: svc-normalize-map
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- ../../config:/app/config:ro
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
|
||||
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- postgres
|
||||
- neo4j
|
||||
- minio
|
||||
- qdrant
|
||||
- nats
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-normalize-map.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/normalize-map`)"
|
||||
- "traefik.http.routers.svc-normalize-map.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-normalize-map.tls=true"
|
||||
- "traefik.http.routers.svc-normalize-map.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-normalize-map.loadbalancer.server.port=8000"
|
||||
|
||||
svc-ocr:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_ocr/Dockerfile
|
||||
container_name: svc-ocr
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- ../../config:/app/config:ro
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
|
||||
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- postgres
|
||||
- neo4j
|
||||
- minio
|
||||
- qdrant
|
||||
- nats
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-ocr.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/ocr`)"
|
||||
- "traefik.http.routers.svc-ocr.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-ocr.tls=true"
|
||||
- "traefik.http.routers.svc-ocr.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-ocr.loadbalancer.server.port=8000"
|
||||
|
||||
svc-rag-indexer:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_rag_indexer/Dockerfile
|
||||
container_name: svc-rag-indexer
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- ../../config:/app/config:ro
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
|
||||
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- postgres
|
||||
- neo4j
|
||||
- minio
|
||||
- qdrant
|
||||
- nats
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-rag-indexer.rule=Host(`api.${DOMAIN:-.lan}`) && PathPrefix(`/rag-indexer`)"
|
||||
- "traefik.http.routers.svc-rag-indexer.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-rag-indexer.tls=true"
|
||||
- "traefik.http.routers.svc-rag-indexer.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-rag-indexer.loadbalancer.server.port=8000"
|
||||
|
||||
svc-reason:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_reason/Dockerfile
|
||||
container_name: svc-reason
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- ../../config:/app/config:ro
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
|
||||
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
|
||||
depends_on:
|
||||
- postgres
|
||||
- neo4j
|
||||
- minio
|
||||
- qdrant
|
||||
- nats
|
||||
- traefik
|
||||
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-reason.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/reason`)"
|
||||
- "traefik.http.routers.svc-reason.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-reason.tls=true"
|
||||
- "traefik.http.routers.svc-reason.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-reason.loadbalancer.server.port=8000"
|
||||
|
||||
svc-rpa:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: apps/svc_rpa/Dockerfile
|
||||
container_name: svc-rpa
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- ../../config:/app/config:ro
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
|
||||
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
|
||||
- KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
|
||||
- NATS_SERVERS=${NATS_SERVERS:-nats://nats:4222}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
|
||||
depends_on:
|
||||
- postgres
|
||||
- neo4j
|
||||
- minio
|
||||
- qdrant
|
||||
- nats
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-rpa.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/rpa`)"
|
||||
- "traefik.http.routers.svc-rpa.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-rpa.tls=true"
|
||||
- "traefik.http.routers.svc-rpa.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-rpa.loadbalancer.server.port=8000"
|
||||
|
||||
ui-review:
|
||||
build:
|
||||
context: ../../ui-review
|
||||
dockerfile: Dockerfile
|
||||
container_name: ui-review
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- frontend
|
||||
environment:
|
||||
- NEXTAUTH_URL=https://review.${DOMAIN:-local.lan}
|
||||
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-changeme}
|
||||
- API_BASE_URL=https://api.${DOMAIN:-local.lan}
|
||||
depends_on:
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.docker.network=ai-tax-agent-frontend"
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.ui-review.rule=Host(`review.${DOMAIN:-local.lan}`)"
|
||||
- "traefik.http.routers.ui-review.entrypoints=websecure"
|
||||
- "traefik.http.routers.ui-review.tls=true"
|
||||
- "traefik.http.routers.ui-review.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.ui-review.loadbalancer.server.port=3030"
|
||||
1012
infra/compose/docker-compose.local.yml
Normal file
1012
infra/compose/docker-compose.local.yml
Normal file
File diff suppressed because it is too large
Load Diff
106
infra/compose/env.example
Normal file
106
infra/compose/env.example
Normal file
@@ -0,0 +1,106 @@
|
||||
# FILE: infra/compose/env.example
|
||||
|
||||
# Domain Configuration
|
||||
DOMAIN=local
|
||||
EMAIL=admin@local.lan
|
||||
|
||||
# Database Passwords
|
||||
POSTGRES_PASSWORD=postgres
|
||||
NEO4J_PASSWORD=neo4jpass
|
||||
AUTHENTIK_DB_PASSWORD=authentik
|
||||
|
||||
# Object Storage
|
||||
MINIO_ROOT_USER=minio
|
||||
MINIO_ROOT_PASSWORD=miniopass
|
||||
MINIO_ACCESS_KEY=minio
|
||||
MINIO_SECRET_KEY=miniopass
|
||||
|
||||
# Vector Database
|
||||
QDRANT__SERVICE__GRPC_PORT=6334
|
||||
|
||||
# Secrets Management
|
||||
VAULT_DEV_ROOT_TOKEN_ID=root
|
||||
|
||||
# Identity & SSO
|
||||
AUTHENTIK_SECRET_KEY=changeme
|
||||
AUTHENTIK_OUTPOST_TOKEN=changeme
|
||||
AUTHENTIK_BOOTSTRAP_EMAIL=admin@local.lan
|
||||
AUTHENTIK_BOOTSTRAP_PASSWORD=admin123
|
||||
AUTHENTIK_BOOTSTRAP_TOKEN=
|
||||
|
||||
# Monitoring
|
||||
GRAFANA_PASSWORD=admin
|
||||
GRAFANA_OAUTH_CLIENT_ID=grafana
|
||||
GRAFANA_OAUTH_CLIENT_SECRET=changeme
|
||||
|
||||
# OAuth Client Secrets for Authentik Providers
|
||||
AUTHENTIK_API_CLIENT_SECRET=changeme-api-secret
|
||||
AUTHENTIK_UI_REVIEW_CLIENT_SECRET=changeme-ui-review-secret
|
||||
AUTHENTIK_GRAFANA_CLIENT_SECRET=changeme-grafana-secret
|
||||
AUTHENTIK_MINIO_CLIENT_SECRET=changeme-minio-secret
|
||||
AUTHENTIK_VAULT_CLIENT_SECRET=changeme-vault-secret
|
||||
|
||||
# Feature Flags
|
||||
UNLEASH_ADMIN_TOKEN=development.unleash-insecure-admin-api-token
|
||||
|
||||
# Application Configuration
|
||||
NEXTAUTH_SECRET=changeme
|
||||
|
||||
# RAG & ML Models
|
||||
RAG_EMBEDDING_MODEL=bge-small-en-v1.5
|
||||
RAG_RERANKER_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
|
||||
RAG_ALPHA_BETA_GAMMA=0.5,0.3,0.2
|
||||
|
||||
# HMRC Integration
|
||||
HMRC_MTD_ITSA_MODE=sandbox
|
||||
|
||||
# Rate Limits
|
||||
RATE_LIMITS_HMRC_API_RPS=3
|
||||
RATE_LIMITS_HMRC_API_BURST=6
|
||||
RATE_LIMITS_LLM_API_RPS=10
|
||||
RATE_LIMITS_LLM_API_BURST=20
|
||||
|
||||
# Confidence Thresholds
|
||||
CONFIDENCE_AUTO_SUBMIT=0.95
|
||||
CONFIDENCE_HUMAN_REVIEW=0.85
|
||||
CONFIDENCE_REJECT=0.50
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=INFO
|
||||
LOG_FORMAT=json
|
||||
|
||||
# Development Settings
|
||||
DEBUG=false
|
||||
DEVELOPMENT_MODE=true
|
||||
|
||||
# Security
|
||||
ENCRYPTION_KEY_ID=default
|
||||
AUDIT_LOG_RETENTION_DAYS=90
|
||||
PII_LOG_RETENTION_DAYS=30
|
||||
|
||||
# Backup & DR
|
||||
BACKUP_ENABLED=true
|
||||
BACKUP_SCHEDULE=0 2 * * *
|
||||
BACKUP_RETENTION_DAYS=30
|
||||
|
||||
# Performance Tuning
|
||||
MAX_WORKERS=4
|
||||
BATCH_SIZE=100
|
||||
CACHE_TTL_SECONDS=3600
|
||||
CONNECTION_POOL_SIZE=20
|
||||
|
||||
# Feature Flags
|
||||
FEATURE_RAG_ENABLED=true
|
||||
FEATURE_FIRM_CONNECTORS_ENABLED=false
|
||||
FEATURE_HMRC_SUBMISSION_ENABLED=false
|
||||
FEATURE_ADVANCED_CALCULATIONS_ENABLED=true
|
||||
|
||||
# Event Bus Configuration
|
||||
EVENT_BUS_TYPE=memory
|
||||
KAFKA_BOOTSTRAP_SERVERS=
|
||||
|
||||
# NATS Configuration
|
||||
NATS_SERVERS=nats://nats:4222
|
||||
NATS_STREAM_NAME=TAX_AGENT_EVENTS
|
||||
NATS_CONSUMER_GROUP=tax-agent
|
||||
NATS_LOG_LEVEL=info
|
||||
63
infra/compose/gitea/compose.yaml
Normal file
63
infra/compose/gitea/compose.yaml
Normal file
@@ -0,0 +1,63 @@
|
||||
---
|
||||
services:
|
||||
gitea-server:
|
||||
image: docker.io/gitea/gitea:1.24.5
|
||||
container_name: gitea-server
|
||||
env_file:
|
||||
- ./.env # contains the GoDaddy API Key and Secret
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__database__DB_TYPE=postgres
|
||||
- GITEA__database__HOST=${POSTGRES_HOST:-gitea-postgres}:${POSTGRES_PORT:-5432}
|
||||
- GITEA__database__NAME=${POSTGRES_DB:-gitea}
|
||||
- GITEA__database__USER=${POSTGRES_USER:-gitea}
|
||||
- GITEA__database__PASSWD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD not set}
|
||||
- GITEA__server__SSH_PORT=2221 # <-- (Optional) Replace with your desired SSH port
|
||||
- GITEA__server__ROOT_URL=https://gitea.harkon.co.uk # <-- Replace with your FQDN
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
volumes:
|
||||
- gitea-data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "2221:22" # <-- (Optional) Replace with your desired SSH port
|
||||
depends_on:
|
||||
- gitea-postgres
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.services.gitea.loadbalancer.server.port=3000
|
||||
- traefik.http.services.gitea.loadbalancer.server.scheme=http
|
||||
- traefik.http.routers.gitea-https.entrypoints=websecure
|
||||
- traefik.http.routers.gitea-https.rule=Host(`gitea.harkon.co.uk`) # <-- Replace with your FQDN
|
||||
- traefik.http.routers.gitea-https.tls=true
|
||||
- traefik.http.routers.gitea-https.tls.certresolver=godaddy # <-- Replace with your certresolver
|
||||
- traefik.http.routers.gitea.service=gitea
|
||||
restart: unless-stopped
|
||||
|
||||
gitea-postgres:
|
||||
image: docker.io/library/postgres:17.5
|
||||
container_name: gitea-postgres
|
||||
environment:
|
||||
- POSTGRES_USER=${POSTGRES_USER:-gitea}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD not set}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-gitea}
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- gitea-db:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
gitea-data:
|
||||
driver: local
|
||||
gitea-db:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
external: true
|
||||
backend:
|
||||
external: true
|
||||
104
infra/compose/nextcloud/compose.yaml
Normal file
104
infra/compose/nextcloud/compose.yaml
Normal file
@@ -0,0 +1,104 @@
|
||||
# /opt/compose/nextcloud/compose.yml
|
||||
networks:
|
||||
frontend:
|
||||
external: true
|
||||
backend:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
nextcloud_html:
|
||||
nextcloud_data:
|
||||
nextcloud_config:
|
||||
nextcloud_apps:
|
||||
nextcloud_postgres:
|
||||
nextcloud_redis:
|
||||
|
||||
services:
|
||||
nextcloud-postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: nextcloud-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: nextcloud
|
||||
POSTGRES_USER: nextcloud
|
||||
POSTGRES_PASSWORD: ${NEXTCLOUD_DB_PASSWORD}
|
||||
volumes:
|
||||
- nextcloud_postgres:/var/lib/postgresql/data
|
||||
networks: [backend]
|
||||
|
||||
nextcloud-redis:
|
||||
image: redis:7-alpine
|
||||
container_name: nextcloud-redis
|
||||
restart: unless-stopped
|
||||
command:
|
||||
[
|
||||
"redis-server",
|
||||
"--appendonly",
|
||||
"yes",
|
||||
"--requirepass",
|
||||
"${REDIS_PASSWORD}",
|
||||
]
|
||||
volumes:
|
||||
- nextcloud_redis:/data
|
||||
networks: [backend]
|
||||
|
||||
nextcloud-server:
|
||||
image: nextcloud:apache
|
||||
container_name: nextcloud-server
|
||||
restart: unless-stopped
|
||||
depends_on: [nextcloud-postgres, nextcloud-redis]
|
||||
env_file:
|
||||
- ./.env
|
||||
environment:
|
||||
# DB
|
||||
POSTGRES_DB: nextcloud
|
||||
POSTGRES_USER: nextcloud
|
||||
POSTGRES_PASSWORD: ${NEXTCLOUD_DB_PASSWORD}
|
||||
POSTGRES_HOST: nextcloud-postgres
|
||||
# Initial admin (used only on first run)
|
||||
NEXTCLOUD_ADMIN_USER: ${NEXTCLOUD_ADMIN_USER}
|
||||
NEXTCLOUD_ADMIN_PASSWORD: ${NEXTCLOUD_ADMIN_PASSWORD}
|
||||
# Reverse frontend awareness
|
||||
NEXTCLOUD_TRUSTED_DOMAINS: cloud.harkon.co.uk
|
||||
OVERWRITEHOST: cloud.harkon.co.uk
|
||||
OVERWRITEPROTOCOL: https
|
||||
# Redis for locks/cache
|
||||
REDIS_HOST: nextcloud-redis
|
||||
REDIS_HOST_PASSWORD: ${REDIS_PASSWORD}
|
||||
volumes:
|
||||
- nextcloud_html:/var/www/html
|
||||
- nextcloud_data:/var/www/html/data
|
||||
- nextcloud_config:/var/www/html/config
|
||||
- nextcloud_apps:/var/www/html/custom_apps
|
||||
networks:
|
||||
- frontend # for Traefik
|
||||
- backend # for DB/Redis
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.nextcloud.rule=Host(`cloud.harkon.co.uk`)
|
||||
- traefik.http.routers.nextcloud.entrypoints=websecure
|
||||
- traefik.http.routers.nextcloud.tls=true
|
||||
- traefik.http.routers.nextcloud.tls.certresolver=godaddy
|
||||
- traefik.http.services.nextcloud.loadbalancer.server.port=80
|
||||
- traefik.http.routers.nextcloud.service=nextcloud
|
||||
|
||||
# Run background jobs as a separate container
|
||||
cron:
|
||||
image: nextcloud:apache
|
||||
container_name: nextcloud-cron
|
||||
restart: unless-stopped
|
||||
depends_on: [nc_db, nc_redis]
|
||||
entrypoint: /cron.sh
|
||||
environment:
|
||||
POSTGRES_DB: nextcloud
|
||||
POSTGRES_USER: nextcloud
|
||||
POSTGRES_PASSWORD: ${NEXTCLOUD_DB_PASSWORD}
|
||||
POSTGRES_HOST: db
|
||||
REDIS_HOST: redis
|
||||
REDIS_HOST_PASSWORD: ${REDIS_PASSWORD}
|
||||
volumes:
|
||||
- nextcloud_html:/var/www/html
|
||||
- nextcloud_data:/var/www/html/data
|
||||
- nextcloud_config:/var/www/html/config
|
||||
- nextcloud_apps:/var/www/html/custom_apps
|
||||
networks: [backend]
|
||||
27
infra/compose/portainer/docker-compose.yaml
Normal file
27
infra/compose/portainer/docker-compose.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
services:
|
||||
app:
|
||||
container_name: portainer
|
||||
image: docker.io/portainer/portainer-ce:2.33.1-alpine
|
||||
volumes:
|
||||
- /run/docker.sock:/var/run/docker.sock
|
||||
- portainer-data:/data
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.services.portainer.loadbalancer.server.port=9000
|
||||
- traefik.http.routers.portainer.service=portainer
|
||||
- traefik.http.routers.portainer.entrypoints=websecure
|
||||
- traefik.http.routers.portainer.rule=Host(`portainer.harkon.co.uk`)
|
||||
- traefik.http.routers.portainer.tls=true
|
||||
- traefik.http.routers.portainer.tls.certresolver=godaddy
|
||||
networks:
|
||||
- frontend
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
portainer-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
external: true
|
||||
39
infra/compose/traefik/compose.yaml
Normal file
39
infra/compose/traefik/compose.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
# FILE: infra/compose/traefik/compose.yaml
|
||||
# there is another traefik instance in the infra used by the application.
|
||||
# Current instance used for company services on the dev environment.
|
||||
# TODO: Unify the two traefik instances.
|
||||
---
|
||||
services:
|
||||
traefik:
|
||||
image: docker.io/library/traefik:v3.5.1
|
||||
container_name: traefik
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
# --> (Optional) Enable Dashboard, don't do in production
|
||||
# - 8080:8080
|
||||
# <--
|
||||
volumes:
|
||||
- /run/docker.sock:/run/docker.sock:ro
|
||||
- ./config/:/etc/traefik/:ro
|
||||
- ./certs/:/var/traefik/certs/:rw
|
||||
environment:
|
||||
- CF_DNS_API_TOKEN=your-cloudflare-api-token # <-- Change this to your Cloudflare API Token
|
||||
env_file:
|
||||
- ./.provider.env # contains the GoDaddy API Key and Secret
|
||||
networks:
|
||||
- frontend
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.middlewares.basicauth.basicauth.users=admin:$2y$05$/B2hjJGytCjjMK4Rah1/aeJofBrzqEnAVoZCMKKwetS9mgmck.MVS
|
||||
- traefik.http.routers.traefik.rule=Host(`traefik.harkon.co.uk`)
|
||||
- traefik.http.routers.traefik.entrypoints=websecure
|
||||
- traefik.http.routers.traefik.tls.certresolver=le
|
||||
- traefik.http.routers.traefik.middlewares=basicauth@docker
|
||||
- traefik.http.routers.traefik.service=api@internal
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
external: true # <-- (Optional) Change this to false if you want to create a new network
|
||||
#
|
||||
21
infra/compose/traefik/config/example.externalservice.yaml
Normal file
21
infra/compose/traefik/config/example.externalservice.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# --> (Example) Expose an external service using Traefik...
|
||||
# http:
|
||||
# # -- Change Router Configuration here...
|
||||
# routers:
|
||||
# your-local-router:
|
||||
# rule: "Host(`your-local-service.your-domain.com`)" # <-- Change Rules here...
|
||||
# service: your-local-service # <-- Change Service Name here...
|
||||
# priority: 1000 # <-- (Optional) Change Routing Priority here...
|
||||
# entryPoints:
|
||||
# - web
|
||||
# - websecure
|
||||
# tls:
|
||||
# certResolver: cloudflare
|
||||
#
|
||||
# # -- Change Service Configuration here...
|
||||
# services:
|
||||
# your-local-service: # <-- Change Service Name here...
|
||||
# loadBalancer:
|
||||
# servers:
|
||||
# - url: "http://your-local-service:port" # <-- Change Target Service URL here...
|
||||
# <--
|
||||
@@ -0,0 +1,19 @@
|
||||
# --> (Example) Securely expose apps using the Traefik proxy outpost...
|
||||
http:
|
||||
middlewares:
|
||||
authentik:
|
||||
forwardAuth:
|
||||
address: http://authentik-server:9000/outpost.goauthentik.io/auth/traefik
|
||||
trustForwardHeader: true
|
||||
authResponseHeaders:
|
||||
- X-authentik-username
|
||||
- X-authentik-groups
|
||||
- X-authentik-email
|
||||
- X-authentik-name
|
||||
- X-authentik-uid
|
||||
- X-authentik-jwt
|
||||
- X-authentik-meta-jwks
|
||||
- X-authentik-meta-outpost
|
||||
- X-authentik-meta-provider
|
||||
- X-authentik-meta-app
|
||||
- X-authentik-meta-version
|
||||
@@ -0,0 +1,22 @@
|
||||
# --> (Optional) When using Passbolt with Traefik...
|
||||
# http:
|
||||
# middlewares:
|
||||
# passbolt-middleware:
|
||||
# headers:
|
||||
# FrameDeny: true
|
||||
# AccessControlAllowMethods: 'GET,OPTIONS,PUT'
|
||||
# AccessControlAllowOriginList:
|
||||
# - origin-list-or-null
|
||||
# AccessControlMaxAge: 100
|
||||
# AddVaryHeader: true
|
||||
# BrowserXssFilter: true
|
||||
# ContentTypeNosniff: true
|
||||
# ForceSTSHeader: true
|
||||
# STSIncludeSubdomains: true
|
||||
# STSPreload: true
|
||||
# ContentSecurityPolicy: default-src 'self' 'unsafe-inline'
|
||||
# CustomFrameOptionsValue: SAMEORIGIN
|
||||
# ReferrerPolicy: same-origin
|
||||
# PermissionsPolicy: vibrate 'self'
|
||||
# STSSeconds: 315360000
|
||||
# <--
|
||||
18
infra/compose/traefik/config/example.tls.yaml
Normal file
18
infra/compose/traefik/config/example.tls.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
# --> (Example) Change TLS Configuration here...
|
||||
# tls:
|
||||
# options:
|
||||
# default:
|
||||
# minVersion: VersionTLS12
|
||||
# sniStrict: true
|
||||
# curvePreferences:
|
||||
# - CurveP256
|
||||
# - CurveP384
|
||||
# - CurveP521
|
||||
# cipherSuites:
|
||||
# - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
# - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
||||
# - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
|
||||
# - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
# - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
# - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
|
||||
# <--
|
||||
64
infra/compose/traefik/config/traefik.yaml
Normal file
64
infra/compose/traefik/config/traefik.yaml
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
global:
|
||||
checkNewVersion: false
|
||||
sendAnonymousUsage: false
|
||||
|
||||
# --> (Optional) Change log level and format here ...
|
||||
# - level: [TRACE, DEBUG, INFO, WARN, ERROR, FATAL]
|
||||
log:
|
||||
level: DEBUG
|
||||
# <--
|
||||
|
||||
# --> (Optional) Enable accesslog here ...
|
||||
accesslog: {}
|
||||
# <--
|
||||
|
||||
# --> (Optional) Enable API and Dashboard here, don't do in production
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: true
|
||||
# <--
|
||||
|
||||
# -- Change EntryPoints here...
|
||||
entryPoints:
|
||||
web:
|
||||
address: :80
|
||||
# --> (Optional) Redirect all HTTP to HTTPS
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
scheme: https
|
||||
# <--
|
||||
websecure:
|
||||
address: :443
|
||||
|
||||
# -- Configure your CertificateResolver here...
|
||||
certificatesResolvers:
|
||||
godaddy:
|
||||
acme:
|
||||
email: info@harkon.co.uk
|
||||
storage: /var/traefik/certs/godaddy-acme.json
|
||||
caServer: "https://acme-v02.api.letsencrypt.org/directory"
|
||||
dnsChallenge:
|
||||
provider: godaddy
|
||||
resolvers:
|
||||
- 1.1.1.1:53
|
||||
- 8.8.8.8:53
|
||||
- 97.74.103.44:53
|
||||
- 173.201.71.44:53
|
||||
|
||||
# --> (Optional) Disable TLS Cert verification check
|
||||
# serversTransport:
|
||||
# insecureSkipVerify: true
|
||||
# <--
|
||||
|
||||
providers:
|
||||
docker:
|
||||
exposedByDefault: false # <-- (Optional) Change this to true if you want to expose all services
|
||||
# Specify discovery network - This ensures correct name resolving and possible issues with containers, that are in multiple networks.
|
||||
# E.g. Database container in a separate network and a container in the frontend and database network.
|
||||
network: frontend
|
||||
file:
|
||||
directory: /etc/traefik
|
||||
watch: true
|
||||
Reference in New Issue
Block a user