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:
37
infra/.gitignore
vendored
Normal file
37
infra/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# Environment files (contain secrets)
|
||||
environments/*/.env
|
||||
!environments/*/.env.example
|
||||
compose/*/.env
|
||||
!compose/env.example
|
||||
|
||||
# Certificates
|
||||
certs/*/
|
||||
!certs/.gitkeep
|
||||
compose/*/certs/
|
||||
!compose/*/certs/.gitkeep
|
||||
|
||||
# Provider credentials
|
||||
compose/traefik/.provider.env
|
||||
configs/traefik/.provider.env
|
||||
|
||||
# Data directories
|
||||
compose/*/data/
|
||||
compose/*/media/
|
||||
compose/authentik/media/
|
||||
compose/authentik/custom-templates/
|
||||
compose/portainer/portainer/
|
||||
|
||||
# Backup files
|
||||
*.backup
|
||||
*.tmp
|
||||
*-backup-*/
|
||||
|
||||
# Docker volumes (if mounted locally)
|
||||
volumes/
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# Moved markers
|
||||
**/.moved
|
||||
541
infra/DEPLOYMENT_GUIDE.md
Normal file
541
infra/DEPLOYMENT_GUIDE.md
Normal file
@@ -0,0 +1,541 @@
|
||||
# AI Tax Agent Infrastructure Deployment Guide
|
||||
|
||||
Complete guide for deploying AI Tax Agent infrastructure across all environments.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Prerequisites](#prerequisites)
|
||||
2. [Quick Start](#quick-start)
|
||||
3. [Local Development](#local-development)
|
||||
4. [Development Server](#development-server)
|
||||
5. [Production Server](#production-server)
|
||||
6. [Troubleshooting](#troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Required Software
|
||||
|
||||
- Docker 24.0+ with Compose V2
|
||||
- Git
|
||||
- SSH access (for remote deployments)
|
||||
- Domain with DNS access (for dev/prod)
|
||||
|
||||
### Required Accounts
|
||||
|
||||
- GoDaddy account (for DNS-01 challenge)
|
||||
- Gitea account (for container registry)
|
||||
- OpenAI/Anthropic API keys (optional)
|
||||
|
||||
### Network Requirements
|
||||
|
||||
- Ports 80, 443 open (for Traefik)
|
||||
- Docker networks: `frontend`, `backend`
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Clone Repository
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd ai-tax-agent
|
||||
```
|
||||
|
||||
### 2. Choose Environment
|
||||
|
||||
```bash
|
||||
# Local development
|
||||
export ENV=local
|
||||
|
||||
# Development server
|
||||
export ENV=development
|
||||
|
||||
# Production server
|
||||
export ENV=production
|
||||
```
|
||||
|
||||
### 3. Setup Environment File
|
||||
|
||||
```bash
|
||||
# Copy template
|
||||
cp infra/environments/$ENV/.env.example infra/environments/$ENV/.env
|
||||
|
||||
# Edit configuration
|
||||
vim infra/environments/$ENV/.env
|
||||
```
|
||||
|
||||
### 4. Generate Secrets (Dev/Prod only)
|
||||
|
||||
```bash
|
||||
./scripts/generate-production-secrets.sh
|
||||
```
|
||||
|
||||
### 5. Deploy
|
||||
|
||||
```bash
|
||||
# Setup networks
|
||||
./infra/scripts/setup-networks.sh
|
||||
|
||||
# Deploy all services
|
||||
./infra/scripts/deploy.sh $ENV all
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Local Development
|
||||
|
||||
### Setup
|
||||
|
||||
1. **Create environment file**:
|
||||
```bash
|
||||
cp infra/environments/local/.env.example infra/environments/local/.env
|
||||
```
|
||||
|
||||
2. **Edit configuration**:
|
||||
```bash
|
||||
vim infra/environments/local/.env
|
||||
```
|
||||
|
||||
Key settings for local:
|
||||
```env
|
||||
DOMAIN=localhost
|
||||
POSTGRES_PASSWORD=postgres
|
||||
MINIO_ROOT_PASSWORD=minioadmin
|
||||
GRAFANA_PASSWORD=admin
|
||||
```
|
||||
|
||||
3. **Generate self-signed certificates** (optional):
|
||||
```bash
|
||||
./scripts/generate-dev-certs.sh
|
||||
```
|
||||
|
||||
### Deploy
|
||||
|
||||
```bash
|
||||
# Setup networks
|
||||
./infra/scripts/setup-networks.sh
|
||||
|
||||
# Deploy infrastructure
|
||||
./infra/scripts/deploy.sh local infrastructure
|
||||
|
||||
# Deploy monitoring
|
||||
./infra/scripts/deploy.sh local monitoring
|
||||
|
||||
# Deploy services
|
||||
./infra/scripts/deploy.sh local services
|
||||
```
|
||||
|
||||
### Access Services
|
||||
|
||||
- **Grafana**: http://localhost:3000 (admin/admin)
|
||||
- **MinIO Console**: http://localhost:9093 (minioadmin/minioadmin)
|
||||
- **Vault**: http://localhost:8200 (token: dev-root-token)
|
||||
- **Traefik Dashboard**: http://localhost:8080
|
||||
|
||||
### Development Workflow
|
||||
|
||||
1. Make code changes
|
||||
2. Build images: `./scripts/build-and-push-images.sh localhost:5000 latest local`
|
||||
3. Restart services: `./infra/scripts/deploy.sh local services`
|
||||
4. Test changes
|
||||
5. Check logs: `docker compose -f infra/base/services.yaml --env-file infra/environments/local/.env logs -f`
|
||||
|
||||
---
|
||||
|
||||
## Development Server
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Server with Docker installed
|
||||
- Domain: `dev.harkon.co.uk`
|
||||
- GoDaddy API credentials
|
||||
- SSH access to server
|
||||
|
||||
### Setup
|
||||
|
||||
1. **SSH to development server**:
|
||||
```bash
|
||||
ssh deploy@dev-server.harkon.co.uk
|
||||
```
|
||||
|
||||
2. **Clone repository**:
|
||||
```bash
|
||||
cd /opt
|
||||
git clone <repository-url> ai-tax-agent
|
||||
cd ai-tax-agent
|
||||
```
|
||||
|
||||
3. **Create environment file**:
|
||||
```bash
|
||||
cp infra/environments/development/.env.example infra/environments/development/.env
|
||||
```
|
||||
|
||||
4. **Generate secrets**:
|
||||
```bash
|
||||
./scripts/generate-production-secrets.sh
|
||||
```
|
||||
|
||||
5. **Edit environment file**:
|
||||
```bash
|
||||
vim infra/environments/development/.env
|
||||
```
|
||||
|
||||
Update:
|
||||
- `DOMAIN=dev.harkon.co.uk`
|
||||
- `EMAIL=dev@harkon.co.uk`
|
||||
- API keys
|
||||
- Registry credentials
|
||||
|
||||
6. **Setup GoDaddy DNS**:
|
||||
```bash
|
||||
# Create Traefik provider file
|
||||
vim infra/configs/traefik/.provider.env
|
||||
```
|
||||
|
||||
Add:
|
||||
```env
|
||||
GODADDY_API_KEY=your-api-key
|
||||
GODADDY_API_SECRET=your-api-secret
|
||||
```
|
||||
|
||||
### Deploy
|
||||
|
||||
```bash
|
||||
# Setup networks
|
||||
./infra/scripts/setup-networks.sh
|
||||
|
||||
# Deploy infrastructure
|
||||
./infra/scripts/deploy.sh development infrastructure
|
||||
|
||||
# Wait for services to be healthy
|
||||
sleep 30
|
||||
|
||||
# Deploy monitoring
|
||||
./infra/scripts/deploy.sh development monitoring
|
||||
|
||||
# Deploy services
|
||||
./infra/scripts/deploy.sh development services
|
||||
```
|
||||
|
||||
### Verify Deployment
|
||||
|
||||
```bash
|
||||
# Check services
|
||||
docker ps
|
||||
|
||||
# Check logs
|
||||
docker compose -f infra/base/infrastructure.yaml --env-file infra/environments/development/.env logs -f
|
||||
|
||||
# Test endpoints
|
||||
curl https://vault.dev.harkon.co.uk
|
||||
curl https://grafana.dev.harkon.co.uk
|
||||
```
|
||||
|
||||
### Access Services
|
||||
|
||||
- **Grafana**: https://grafana.dev.harkon.co.uk
|
||||
- **MinIO**: https://minio.dev.harkon.co.uk
|
||||
- **Vault**: https://vault.dev.harkon.co.uk
|
||||
- **UI Review**: https://ui-review.dev.harkon.co.uk
|
||||
|
||||
---
|
||||
|
||||
## Production Server
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Production server (141.136.35.199)
|
||||
- Domain: `harkon.co.uk`
|
||||
- Existing Traefik, Authentik, Gitea
|
||||
- SSH access as `deploy` user
|
||||
|
||||
### Pre-Deployment Checklist
|
||||
|
||||
- [ ] Backup existing data
|
||||
- [ ] Test in development first
|
||||
- [ ] Generate production secrets
|
||||
- [ ] Update DNS records
|
||||
- [ ] Configure Authentik OAuth providers
|
||||
- [ ] Setup Gitea container registry
|
||||
- [ ] Build and push Docker images
|
||||
|
||||
### Setup
|
||||
|
||||
1. **SSH to production server**:
|
||||
```bash
|
||||
ssh deploy@141.136.35.199
|
||||
```
|
||||
|
||||
2. **Navigate to project**:
|
||||
```bash
|
||||
cd /opt/ai-tax-agent
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
3. **Verify environment file**:
|
||||
```bash
|
||||
cat infra/environments/production/.env | grep DOMAIN
|
||||
```
|
||||
|
||||
Should show:
|
||||
```env
|
||||
DOMAIN=harkon.co.uk
|
||||
```
|
||||
|
||||
4. **Verify secrets are set**:
|
||||
```bash
|
||||
# Check all secrets are not CHANGE_ME
|
||||
grep -i "CHANGE_ME" infra/environments/production/.env
|
||||
```
|
||||
|
||||
Should return nothing.
|
||||
|
||||
### Deploy Infrastructure
|
||||
|
||||
```bash
|
||||
# Setup networks (if not already created)
|
||||
./infra/scripts/setup-networks.sh
|
||||
|
||||
# Deploy infrastructure services
|
||||
./infra/scripts/deploy.sh production infrastructure
|
||||
```
|
||||
|
||||
This deploys:
|
||||
- Vault (secrets management)
|
||||
- MinIO (object storage)
|
||||
- PostgreSQL (relational database)
|
||||
- Neo4j (graph database)
|
||||
- Qdrant (vector database)
|
||||
- Redis (cache)
|
||||
- NATS (message queue)
|
||||
|
||||
### Deploy Monitoring
|
||||
|
||||
```bash
|
||||
./infra/scripts/deploy.sh production monitoring
|
||||
```
|
||||
|
||||
This deploys:
|
||||
- Prometheus (metrics)
|
||||
- Grafana (dashboards)
|
||||
- Loki (logs)
|
||||
- Promtail (log collector)
|
||||
|
||||
### Deploy Services
|
||||
|
||||
```bash
|
||||
./infra/scripts/deploy.sh production services
|
||||
```
|
||||
|
||||
This deploys all 14 microservices.
|
||||
|
||||
### Post-Deployment
|
||||
|
||||
1. **Verify all services are running**:
|
||||
```bash
|
||||
docker ps | grep ai-tax-agent
|
||||
```
|
||||
|
||||
2. **Check health**:
|
||||
```bash
|
||||
curl https://vault.harkon.co.uk/v1/sys/health
|
||||
curl https://minio-api.harkon.co.uk/minio/health/live
|
||||
```
|
||||
|
||||
3. **Configure Authentik OAuth**:
|
||||
- Create OAuth providers for each service
|
||||
- Update environment variables with client secrets
|
||||
- Restart services
|
||||
|
||||
4. **Initialize Vault**:
|
||||
```bash
|
||||
# Access Vault
|
||||
docker exec -it vault sh
|
||||
|
||||
# Initialize (if first time)
|
||||
vault operator init
|
||||
|
||||
# Unseal (if needed)
|
||||
vault operator unseal
|
||||
```
|
||||
|
||||
5. **Setup MinIO buckets**:
|
||||
```bash
|
||||
# Access MinIO console
|
||||
# https://minio.harkon.co.uk
|
||||
|
||||
# Create buckets:
|
||||
# - documents
|
||||
# - embeddings
|
||||
# - models
|
||||
# - backups
|
||||
```
|
||||
|
||||
### Access Services
|
||||
|
||||
All services available at `https://<service>.harkon.co.uk`:
|
||||
|
||||
- **UI Review**: https://ui-review.harkon.co.uk
|
||||
- **Grafana**: https://grafana.harkon.co.uk
|
||||
- **Prometheus**: https://prometheus.harkon.co.uk
|
||||
- **Vault**: https://vault.harkon.co.uk
|
||||
- **MinIO**: https://minio.harkon.co.uk
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Services Not Starting
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
docker compose -f infra/base/infrastructure.yaml --env-file infra/environments/production/.env logs -f
|
||||
|
||||
# Check specific service
|
||||
docker logs vault
|
||||
|
||||
# Check Docker daemon
|
||||
sudo systemctl status docker
|
||||
```
|
||||
|
||||
### Network Issues
|
||||
|
||||
```bash
|
||||
# Check networks exist
|
||||
docker network ls | grep -E "frontend|backend"
|
||||
|
||||
# Inspect network
|
||||
docker network inspect frontend
|
||||
|
||||
# Recreate networks
|
||||
docker network rm frontend backend
|
||||
./infra/scripts/setup-networks.sh
|
||||
```
|
||||
|
||||
### Traefik Routing Issues
|
||||
|
||||
```bash
|
||||
# Check Traefik logs
|
||||
docker logs traefik | grep -i error
|
||||
|
||||
# Check container labels
|
||||
docker inspect vault | grep -A 20 Labels
|
||||
|
||||
# Check Traefik dashboard
|
||||
https://traefik.harkon.co.uk/dashboard/
|
||||
```
|
||||
|
||||
### Database Connection Issues
|
||||
|
||||
```bash
|
||||
# Check PostgreSQL
|
||||
docker exec -it postgres psql -U postgres -c "\l"
|
||||
|
||||
# Check Neo4j
|
||||
docker exec -it neo4j cypher-shell -u neo4j -p $NEO4J_PASSWORD
|
||||
|
||||
# Check Redis
|
||||
docker exec -it redis redis-cli ping
|
||||
```
|
||||
|
||||
### Volume/Data Issues
|
||||
|
||||
```bash
|
||||
# List volumes
|
||||
docker volume ls
|
||||
|
||||
# Inspect volume
|
||||
docker volume inspect postgres_data
|
||||
|
||||
# Backup volume
|
||||
docker run --rm -v postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres_backup.tar.gz /data
|
||||
```
|
||||
|
||||
### SSL Certificate Issues
|
||||
|
||||
```bash
|
||||
# Check Traefik logs for ACME errors
|
||||
docker logs traefik | grep -i acme
|
||||
|
||||
# Check GoDaddy credentials
|
||||
cat infra/configs/traefik/.provider.env
|
||||
|
||||
# Force certificate renewal
|
||||
docker exec traefik rm -rf /var/traefik/certs/acme.json
|
||||
docker restart traefik
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Update Services
|
||||
|
||||
```bash
|
||||
# Pull latest code
|
||||
git pull origin main
|
||||
|
||||
# Rebuild images
|
||||
./scripts/build-and-push-images.sh gitea.harkon.co.uk v1.0.2 harkon
|
||||
|
||||
# Deploy updates
|
||||
./infra/scripts/deploy.sh production services --pull
|
||||
```
|
||||
|
||||
### Backup Data
|
||||
|
||||
```bash
|
||||
# Backup all volumes
|
||||
./scripts/backup-volumes.sh production
|
||||
|
||||
# Backup specific service
|
||||
docker run --rm -v postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres_backup.tar.gz /data
|
||||
```
|
||||
|
||||
### Scale Services
|
||||
|
||||
```bash
|
||||
# Scale a service
|
||||
docker compose -f infra/base/services.yaml --env-file infra/environments/production/.env up -d --scale svc-ingestion=3
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# All services
|
||||
docker compose -f infra/base/services.yaml --env-file infra/environments/production/.env logs -f
|
||||
|
||||
# Specific service
|
||||
docker logs -f svc-ingestion
|
||||
|
||||
# With Loki (via Grafana)
|
||||
https://grafana.harkon.co.uk/explore
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Rotate secrets regularly** - Use `generate-production-secrets.sh`
|
||||
2. **Use Authentik SSO** - Enable for all services
|
||||
3. **Keep images updated** - Regular security patches
|
||||
4. **Monitor logs** - Check for suspicious activity
|
||||
5. **Backup regularly** - Automated daily backups
|
||||
6. **Use strong passwords** - Minimum 32 characters
|
||||
7. **Limit network exposure** - Only expose necessary ports
|
||||
8. **Enable audit logging** - Track all access
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For issues:
|
||||
1. Check logs
|
||||
2. Review documentation
|
||||
3. Check Traefik dashboard
|
||||
4. Verify environment variables
|
||||
5. Test in development first
|
||||
|
||||
415
infra/FINAL_STRUCTURE.md
Normal file
415
infra/FINAL_STRUCTURE.md
Normal file
@@ -0,0 +1,415 @@
|
||||
# AI Tax Agent Infrastructure - Final Structure
|
||||
|
||||
## Overview
|
||||
|
||||
The infrastructure is organized into two main categories:
|
||||
|
||||
1. **External Services** - Production-only services deployed individually
|
||||
2. **Application Infrastructure** - Multi-environment services for the application
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
ai-tax-agent/
|
||||
├── infra/
|
||||
│ ├── compose/ # External services (production)
|
||||
│ │ ├── traefik/ # Reverse proxy
|
||||
│ │ │ ├── compose.yaml
|
||||
│ │ │ ├── config/ # Traefik configuration (source of truth)
|
||||
│ │ │ ├── certs/
|
||||
│ │ │ └── .provider.env
|
||||
│ │ ├── authentik/ # SSO provider
|
||||
│ │ │ ├── compose.yaml
|
||||
│ │ │ ├── .env
|
||||
│ │ │ ├── media/
|
||||
│ │ │ └── custom-templates/
|
||||
│ │ ├── gitea/ # Git + Container Registry
|
||||
│ │ │ ├── compose.yaml
|
||||
│ │ │ └── .env
|
||||
│ │ ├── nextcloud/ # File storage
|
||||
│ │ │ └── compose.yaml
|
||||
│ │ ├── portainer/ # Docker management
|
||||
│ │ │ └── docker-compose.yaml
|
||||
│ │ ├── docker-compose.local.yml # Local dev (all-in-one)
|
||||
│ │ ├── docker-compose.backend.yml # Backend services
|
||||
│ │ └── README.md
|
||||
│ │
|
||||
│ ├── base/ # Application infrastructure (multi-env)
|
||||
│ │ ├── infrastructure.yaml # Core services (Vault, MinIO, DBs, etc.)
|
||||
│ │ ├── services.yaml # Application microservices (14 services)
|
||||
│ │ └── monitoring.yaml # Monitoring stack (Prometheus, Grafana, Loki)
|
||||
│ │
|
||||
│ ├── environments/ # Environment-specific configs
|
||||
│ │ ├── local/
|
||||
│ │ │ ├── .env.example
|
||||
│ │ │ └── .env # Local development config
|
||||
│ │ ├── development/
|
||||
│ │ │ ├── .env.example
|
||||
│ │ │ └── .env # Development server config
|
||||
│ │ └── production/
|
||||
│ │ ├── .env.example
|
||||
│ │ └── .env # Production server config
|
||||
│ │
|
||||
│ ├── configs/ # Application service configs
|
||||
│ │ ├── traefik/
|
||||
│ │ │ └── app-middlewares.yml # App-specific Traefik middlewares
|
||||
│ │ ├── authentik/
|
||||
│ │ │ └── bootstrap.yaml # App-specific Authentik bootstrap
|
||||
│ │ ├── grafana/
|
||||
│ │ │ ├── dashboards/
|
||||
│ │ │ └── provisioning/
|
||||
│ │ ├── prometheus/
|
||||
│ │ │ └── prometheus.yml
|
||||
│ │ ├── loki/
|
||||
│ │ │ └── loki-config.yml
|
||||
│ │ └── vault/
|
||||
│ │ └── config/
|
||||
│ │
|
||||
│ ├── docker/ # Dockerfile templates
|
||||
│ │ ├── base-runtime.Dockerfile
|
||||
│ │ ├── base-ml.Dockerfile
|
||||
│ │ └── Dockerfile.ml-service.template
|
||||
│ │
|
||||
│ ├── certs/ # SSL certificates
|
||||
│ │ ├── local/
|
||||
│ │ ├── development/
|
||||
│ │ └── production/
|
||||
│ │
|
||||
│ ├── scripts/ # Infrastructure deployment scripts
|
||||
│ │ ├── deploy.sh # Deploy application infrastructure
|
||||
│ │ ├── setup-networks.sh # Create Docker networks
|
||||
│ │ └── reorganize-structure.sh
|
||||
│ │
|
||||
│ ├── README.md # Main infrastructure docs
|
||||
│ ├── QUICK_START.md # Quick start guide
|
||||
│ ├── DEPLOYMENT_GUIDE.md # Complete deployment guide
|
||||
│ ├── MIGRATION_GUIDE.md # Migration from old structure
|
||||
│ ├── STRUCTURE_OVERVIEW.md # Architecture overview
|
||||
│ ├── STRUCTURE_CLEANUP.md # Cleanup plan
|
||||
│ └── FINAL_STRUCTURE.md # This file
|
||||
│
|
||||
├── scripts/ # Project-wide scripts
|
||||
│ ├── deploy-external.sh # Deploy external services
|
||||
│ ├── cleanup-infra-structure.sh # Cleanup and align structure
|
||||
│ ├── build-and-push-images.sh # Build and push Docker images
|
||||
│ ├── generate-secrets.sh # Generate secrets
|
||||
│ └── ...
|
||||
│
|
||||
└── Makefile # Project commands
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment Workflows
|
||||
|
||||
### 1. Local Development
|
||||
|
||||
```bash
|
||||
# Option A: Use Makefile (recommended)
|
||||
make bootstrap
|
||||
make run
|
||||
|
||||
# Option B: Use compose directly
|
||||
cd infra/compose
|
||||
docker compose -f docker-compose.local.yml up -d
|
||||
|
||||
# Option C: Use new multi-env structure
|
||||
cp infra/environments/local/.env.example infra/environments/local/.env
|
||||
./infra/scripts/setup-networks.sh
|
||||
./infra/scripts/deploy.sh local all
|
||||
```
|
||||
|
||||
### 2. Production - External Services
|
||||
|
||||
Deploy individually on remote server:
|
||||
|
||||
```bash
|
||||
# SSH to server
|
||||
ssh deploy@141.136.35.199
|
||||
|
||||
# Deploy all external services
|
||||
cd /opt/ai-tax-agent
|
||||
./scripts/deploy-external.sh all
|
||||
|
||||
# Or deploy individually
|
||||
cd /opt/ai-tax-agent/infra/compose/traefik
|
||||
docker compose up -d
|
||||
|
||||
cd /opt/ai-tax-agent/infra/compose/authentik
|
||||
docker compose up -d
|
||||
|
||||
cd /opt/ai-tax-agent/infra/compose/gitea
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 3. Production - Application Infrastructure
|
||||
|
||||
```bash
|
||||
# SSH to server
|
||||
ssh deploy@141.136.35.199
|
||||
cd /opt/ai-tax-agent
|
||||
|
||||
# Deploy infrastructure
|
||||
./infra/scripts/deploy.sh production infrastructure
|
||||
|
||||
# Deploy monitoring
|
||||
./infra/scripts/deploy.sh production monitoring
|
||||
|
||||
# Deploy services
|
||||
./infra/scripts/deploy.sh production services
|
||||
|
||||
# Or use Makefile
|
||||
make deploy-infra-prod
|
||||
make deploy-monitoring-prod
|
||||
make deploy-services-prod
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Makefile Commands
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
make bootstrap # Setup development environment
|
||||
make run # Start all services (local)
|
||||
make stop # Stop all services
|
||||
make restart # Restart all services
|
||||
make logs # Show logs from all services
|
||||
make status # Show status of all services
|
||||
make health # Check health of all services
|
||||
```
|
||||
|
||||
### External Services (Production)
|
||||
|
||||
```bash
|
||||
make deploy-external # Deploy all external services
|
||||
make deploy-traefik # Deploy Traefik only
|
||||
make deploy-authentik # Deploy Authentik only
|
||||
make deploy-gitea # Deploy Gitea only
|
||||
make deploy-nextcloud # Deploy Nextcloud only
|
||||
make deploy-portainer # Deploy Portainer only
|
||||
```
|
||||
|
||||
### Application Infrastructure (Multi-Environment)
|
||||
|
||||
```bash
|
||||
# Local
|
||||
make deploy-infra-local
|
||||
make deploy-services-local
|
||||
make deploy-monitoring-local
|
||||
|
||||
# Development
|
||||
make deploy-infra-dev
|
||||
make deploy-services-dev
|
||||
make deploy-monitoring-dev
|
||||
|
||||
# Production
|
||||
make deploy-infra-prod
|
||||
make deploy-services-prod
|
||||
make deploy-monitoring-prod
|
||||
```
|
||||
|
||||
### Development Tools
|
||||
|
||||
```bash
|
||||
make test # Run all tests
|
||||
make lint # Run linting
|
||||
make format # Format code
|
||||
make build # Build Docker images
|
||||
make clean # Clean up containers and volumes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Management
|
||||
|
||||
### External Services
|
||||
|
||||
Each external service has its own configuration:
|
||||
|
||||
- **Traefik**: `infra/compose/traefik/config/` (source of truth)
|
||||
- **Authentik**: `infra/compose/authentik/.env`
|
||||
- **Gitea**: `infra/compose/gitea/.env`
|
||||
|
||||
### Application Infrastructure
|
||||
|
||||
Application-specific configurations:
|
||||
|
||||
- **Environment Variables**: `infra/environments/<env>/.env`
|
||||
- **Traefik Middlewares**: `infra/configs/traefik/app-middlewares.yml`
|
||||
- **Authentik Bootstrap**: `infra/configs/authentik/bootstrap.yaml`
|
||||
- **Grafana Dashboards**: `infra/configs/grafana/dashboards/`
|
||||
- **Prometheus Config**: `infra/configs/prometheus/prometheus.yml`
|
||||
|
||||
---
|
||||
|
||||
## Key Differences
|
||||
|
||||
### External Services vs Application Infrastructure
|
||||
|
||||
| Aspect | External Services | Application Infrastructure |
|
||||
|--------|------------------|---------------------------|
|
||||
| **Location** | `infra/compose/` | `infra/base/` + `infra/environments/` |
|
||||
| **Deployment** | Individual compose files | Unified deployment script |
|
||||
| **Environment** | Production only | Local, Dev, Prod |
|
||||
| **Purpose** | Shared company services | AI Tax Agent application |
|
||||
| **Examples** | Traefik, Authentik, Gitea | Vault, MinIO, Microservices |
|
||||
|
||||
---
|
||||
|
||||
## Networks
|
||||
|
||||
All services use two shared Docker networks:
|
||||
|
||||
- **frontend**: Public-facing services (connected to Traefik)
|
||||
- **backend**: Internal services (databases, message queues)
|
||||
|
||||
Create networks:
|
||||
|
||||
```bash
|
||||
docker network create frontend
|
||||
docker network create backend
|
||||
|
||||
# Or use script
|
||||
./infra/scripts/setup-networks.sh
|
||||
|
||||
# Or use Makefile
|
||||
make networks
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Service Access
|
||||
|
||||
### Local Development
|
||||
|
||||
- **Grafana**: http://localhost:3000
|
||||
- **MinIO**: http://localhost:9093
|
||||
- **Vault**: http://localhost:8200
|
||||
- **Traefik Dashboard**: http://localhost:8080
|
||||
|
||||
### Production
|
||||
|
||||
- **Traefik**: https://traefik.harkon.co.uk
|
||||
- **Authentik**: https://authentik.harkon.co.uk
|
||||
- **Gitea**: https://gitea.harkon.co.uk
|
||||
- **Grafana**: https://grafana.harkon.co.uk
|
||||
- **MinIO**: https://minio.harkon.co.uk
|
||||
- **Vault**: https://vault.harkon.co.uk
|
||||
- **UI Review**: https://ui-review.harkon.co.uk
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Configuration Management
|
||||
|
||||
- ✅ External service configs live with their compose files
|
||||
- ✅ Application configs live in `infra/configs/`
|
||||
- ✅ Environment-specific settings in `.env` files
|
||||
- ✅ Never commit `.env` files (use `.env.example`)
|
||||
|
||||
### 2. Deployment
|
||||
|
||||
- ✅ Test in local first
|
||||
- ✅ Deploy to development before production
|
||||
- ✅ Deploy external services before application infrastructure
|
||||
- ✅ Deploy infrastructure before services
|
||||
|
||||
### 3. Secrets Management
|
||||
|
||||
- ✅ Use `./scripts/generate-secrets.sh` for production
|
||||
- ✅ Store secrets in `.env` files (gitignored)
|
||||
- ✅ Use Vault for runtime secrets
|
||||
- ✅ Rotate secrets regularly
|
||||
|
||||
### 4. Monitoring
|
||||
|
||||
- ✅ Check logs after deployment
|
||||
- ✅ Verify health endpoints
|
||||
- ✅ Monitor Grafana dashboards
|
||||
- ✅ Set up alerts for production
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Services Not Starting
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
docker compose logs -f <service>
|
||||
|
||||
# Check status
|
||||
docker ps -a
|
||||
|
||||
# Check networks
|
||||
docker network ls
|
||||
docker network inspect frontend
|
||||
```
|
||||
|
||||
### Configuration Issues
|
||||
|
||||
```bash
|
||||
# Verify environment file
|
||||
cat infra/environments/production/.env | grep DOMAIN
|
||||
|
||||
# Check compose file syntax
|
||||
docker compose -f infra/base/infrastructure.yaml config
|
||||
|
||||
# Validate Traefik config
|
||||
docker exec traefik traefik version
|
||||
```
|
||||
|
||||
### Network Issues
|
||||
|
||||
```bash
|
||||
# Recreate networks
|
||||
docker network rm frontend backend
|
||||
./infra/scripts/setup-networks.sh
|
||||
|
||||
# Check network connectivity
|
||||
docker exec <service> ping <other-service>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration from Old Structure
|
||||
|
||||
If you have the old structure, run:
|
||||
|
||||
```bash
|
||||
./scripts/cleanup-infra-structure.sh
|
||||
```
|
||||
|
||||
This will:
|
||||
- Remove duplicate configurations
|
||||
- Align Traefik configs
|
||||
- Create app-specific middlewares
|
||||
- Update .gitignore
|
||||
- Create documentation
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ Structure cleaned up and aligned
|
||||
2. 📖 Read [QUICK_START.md](QUICK_START.md) for quick deployment
|
||||
3. 📚 Read [DEPLOYMENT_GUIDE.md](DEPLOYMENT_GUIDE.md) for detailed instructions
|
||||
4. 🧪 Test local deployment: `make run`
|
||||
5. 🚀 Deploy to production: `make deploy-infra-prod`
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
|
||||
1. Check logs: `make logs`
|
||||
2. Check health: `make health`
|
||||
3. Review documentation in `infra/`
|
||||
4. Check Traefik dashboard for routing issues
|
||||
|
||||
312
infra/MIGRATION_GUIDE.md
Normal file
312
infra/MIGRATION_GUIDE.md
Normal file
@@ -0,0 +1,312 @@
|
||||
# Infrastructure Migration Guide
|
||||
|
||||
This guide helps you migrate from the old infrastructure structure to the new organized multi-environment setup.
|
||||
|
||||
## Old Structure vs New Structure
|
||||
|
||||
### Old Structure
|
||||
```
|
||||
infra/
|
||||
├── compose/
|
||||
│ ├── docker-compose.local.yml (1013 lines - everything)
|
||||
│ ├── docker-compose.backend.yml (1014 lines - everything)
|
||||
│ ├── authentik/compose.yaml
|
||||
│ ├── gitea/compose.yaml
|
||||
│ ├── nextcloud/compose.yaml
|
||||
│ ├── portainer/docker-compose.yaml
|
||||
│ └── traefik/compose.yaml
|
||||
├── production/
|
||||
│ ├── infrastructure.yaml
|
||||
│ ├── services.yaml
|
||||
│ └── monitoring.yaml
|
||||
├── .env.production
|
||||
└── various config folders
|
||||
```
|
||||
|
||||
### New Structure
|
||||
```
|
||||
infra/
|
||||
├── base/ # Shared compose files
|
||||
│ ├── infrastructure.yaml
|
||||
│ ├── services.yaml
|
||||
│ ├── monitoring.yaml
|
||||
│ └── external.yaml
|
||||
├── environments/ # Environment-specific configs
|
||||
│ ├── local/.env
|
||||
│ ├── development/.env
|
||||
│ └── production/.env
|
||||
├── configs/ # Service configurations
|
||||
│ ├── traefik/
|
||||
│ ├── grafana/
|
||||
│ ├── prometheus/
|
||||
│ └── ...
|
||||
└── scripts/
|
||||
└── deploy.sh # Unified deployment script
|
||||
```
|
||||
|
||||
## Migration Steps
|
||||
|
||||
### Step 1: Backup Current Setup
|
||||
|
||||
```bash
|
||||
# Backup current environment files
|
||||
cp infra/.env.production infra/.env.production.backup
|
||||
cp infra/compose/.env infra/compose/.env.backup
|
||||
|
||||
# Backup compose files
|
||||
tar -czf infra-backup-$(date +%Y%m%d).tar.gz infra/
|
||||
```
|
||||
|
||||
### Step 2: Stop Current Services (if migrating live)
|
||||
|
||||
```bash
|
||||
# Stop services (if running)
|
||||
cd infra/compose
|
||||
docker compose -f docker-compose.local.yml down
|
||||
|
||||
# Or for production
|
||||
cd infra/production
|
||||
docker compose -f infrastructure.yaml down
|
||||
docker compose -f services.yaml down
|
||||
docker compose -f monitoring.yaml down
|
||||
```
|
||||
|
||||
### Step 3: Create Environment Files
|
||||
|
||||
```bash
|
||||
# For local development
|
||||
cp infra/environments/local/.env.example infra/environments/local/.env
|
||||
vim infra/environments/local/.env
|
||||
|
||||
# For development server
|
||||
cp infra/environments/development/.env.example infra/environments/development/.env
|
||||
vim infra/environments/development/.env
|
||||
|
||||
# For production (copy from existing)
|
||||
cp infra/.env.production infra/environments/production/.env
|
||||
```
|
||||
|
||||
### Step 4: Move Configuration Files
|
||||
|
||||
```bash
|
||||
# Move Traefik configs
|
||||
cp -r infra/traefik/* infra/configs/traefik/
|
||||
|
||||
# Move Grafana configs
|
||||
cp -r infra/grafana/* infra/configs/grafana/
|
||||
|
||||
# Move Prometheus configs
|
||||
cp -r infra/prometheus/* infra/configs/prometheus/
|
||||
|
||||
# Move Loki configs
|
||||
cp -r infra/loki/* infra/configs/loki/
|
||||
|
||||
# Move Vault configs
|
||||
cp -r infra/vault/* infra/configs/vault/
|
||||
|
||||
# Move Authentik configs
|
||||
cp -r infra/authentik/* infra/configs/authentik/
|
||||
```
|
||||
|
||||
### Step 5: Update Volume Names (if needed)
|
||||
|
||||
If you want to preserve existing data, you have two options:
|
||||
|
||||
#### Option A: Keep Existing Volumes (Recommended)
|
||||
|
||||
The new compose files use the same volume names, so your data will be preserved automatically.
|
||||
|
||||
#### Option B: Rename Volumes
|
||||
|
||||
If you want environment-specific volume names:
|
||||
|
||||
```bash
|
||||
# List current volumes
|
||||
docker volume ls
|
||||
|
||||
# Rename volumes (example for production)
|
||||
docker volume create prod_postgres_data
|
||||
docker run --rm -v postgres_data:/from -v prod_postgres_data:/to alpine sh -c "cd /from && cp -av . /to"
|
||||
|
||||
# Repeat for each volume
|
||||
```
|
||||
|
||||
### Step 6: Setup Networks
|
||||
|
||||
```bash
|
||||
# Create Docker networks
|
||||
./infra/scripts/setup-networks.sh
|
||||
```
|
||||
|
||||
### Step 7: Deploy New Structure
|
||||
|
||||
```bash
|
||||
# For local
|
||||
./infra/scripts/deploy.sh local all
|
||||
|
||||
# For development
|
||||
./infra/scripts/deploy.sh development all
|
||||
|
||||
# For production
|
||||
./infra/scripts/deploy.sh production all
|
||||
```
|
||||
|
||||
### Step 8: Verify Services
|
||||
|
||||
```bash
|
||||
# Check running services
|
||||
docker ps
|
||||
|
||||
# Check logs
|
||||
docker compose -f infra/base/infrastructure.yaml --env-file infra/environments/production/.env logs -f
|
||||
|
||||
# Test endpoints
|
||||
curl https://vault.harkon.co.uk
|
||||
curl https://minio.harkon.co.uk
|
||||
curl https://grafana.harkon.co.uk
|
||||
```
|
||||
|
||||
## Handling External Services
|
||||
|
||||
If you have existing Traefik, Authentik, Gitea, Nextcloud, or Portainer:
|
||||
|
||||
### Option 1: Keep Existing (Recommended for Production)
|
||||
|
||||
Don't deploy `external.yaml`. Just ensure:
|
||||
|
||||
1. Networks are shared:
|
||||
```yaml
|
||||
networks:
|
||||
frontend:
|
||||
external: true
|
||||
backend:
|
||||
external: true
|
||||
```
|
||||
|
||||
2. Services can discover each other via network
|
||||
|
||||
### Option 2: Migrate to New Structure
|
||||
|
||||
1. Stop existing services
|
||||
2. Update their compose files to use new structure
|
||||
3. Deploy via `external.yaml`
|
||||
|
||||
## Environment-Specific Differences
|
||||
|
||||
### Local Development
|
||||
|
||||
- Uses `localhost` or `*.local.harkon.co.uk`
|
||||
- Self-signed SSL certificates
|
||||
- Simple passwords
|
||||
- Optional Authentik
|
||||
- Traefik dashboard exposed on port 8080
|
||||
|
||||
### Development Server
|
||||
|
||||
- Uses `*.dev.harkon.co.uk`
|
||||
- Let's Encrypt SSL via DNS-01 challenge
|
||||
- Strong passwords (generated)
|
||||
- Authentik SSO enabled
|
||||
- Gitea container registry
|
||||
|
||||
### Production Server
|
||||
|
||||
- Uses `*.harkon.co.uk`
|
||||
- Let's Encrypt SSL via DNS-01 challenge
|
||||
- Strong passwords (generated)
|
||||
- Authentik SSO enabled
|
||||
- Gitea container registry
|
||||
- No debug ports exposed
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: Services can't find each other
|
||||
|
||||
**Solution**: Ensure networks are created and services are on the correct networks
|
||||
|
||||
```bash
|
||||
docker network ls
|
||||
docker network inspect frontend
|
||||
docker network inspect backend
|
||||
```
|
||||
|
||||
### Issue: Volumes not found
|
||||
|
||||
**Solution**: Check volume names match
|
||||
|
||||
```bash
|
||||
docker volume ls
|
||||
docker compose -f infra/base/infrastructure.yaml --env-file infra/environments/production/.env config
|
||||
```
|
||||
|
||||
### Issue: Environment variables not loaded
|
||||
|
||||
**Solution**: Check .env file exists and is in correct location
|
||||
|
||||
```bash
|
||||
ls -la infra/environments/production/.env
|
||||
cat infra/environments/production/.env | grep DOMAIN
|
||||
```
|
||||
|
||||
### Issue: Traefik routing not working
|
||||
|
||||
**Solution**: Check labels and ensure Traefik can see containers
|
||||
|
||||
```bash
|
||||
docker logs traefik | grep -i error
|
||||
docker inspect <container> | grep -A 20 Labels
|
||||
```
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If migration fails:
|
||||
|
||||
```bash
|
||||
# Stop new services
|
||||
./infra/scripts/deploy.sh production down
|
||||
|
||||
# Restore old structure
|
||||
cd infra/compose
|
||||
docker compose -f docker-compose.backend.yml up -d
|
||||
|
||||
# Or for production
|
||||
cd infra/production
|
||||
docker compose -f infrastructure.yaml up -d
|
||||
docker compose -f services.yaml up -d
|
||||
docker compose -f monitoring.yaml up -d
|
||||
```
|
||||
|
||||
## Post-Migration Cleanup
|
||||
|
||||
After successful migration and verification:
|
||||
|
||||
```bash
|
||||
# Remove old compose files (optional)
|
||||
rm -rf infra/compose/docker-compose.*.yml
|
||||
|
||||
# Remove old production folder (optional)
|
||||
rm -rf infra/production.old
|
||||
|
||||
# Remove backup files
|
||||
rm infra/.env.production.backup
|
||||
rm infra-backup-*.tar.gz
|
||||
```
|
||||
|
||||
## Benefits of New Structure
|
||||
|
||||
✅ **Multi-environment support** - Easy to deploy to local, dev, prod
|
||||
✅ **Cleaner organization** - Configs separated by purpose
|
||||
✅ **Unified deployment** - Single script for all environments
|
||||
✅ **Better security** - Environment-specific secrets
|
||||
✅ **Easier maintenance** - Clear separation of concerns
|
||||
✅ **Scalable** - Easy to add new environments or services
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Test in local environment first
|
||||
2. Deploy to development server
|
||||
3. Verify all services work
|
||||
4. Deploy to production
|
||||
5. Update documentation
|
||||
6. Train team on new structure
|
||||
|
||||
349
infra/QUICK_START.md
Normal file
349
infra/QUICK_START.md
Normal file
@@ -0,0 +1,349 @@
|
||||
# Quick Start Guide
|
||||
|
||||
Get AI Tax Agent infrastructure running in 5 minutes!
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker 24.0+ with Compose V2
|
||||
- Git
|
||||
- 10GB free disk space
|
||||
|
||||
## Local Development (Fastest)
|
||||
|
||||
### 1. Create Environment File
|
||||
|
||||
```bash
|
||||
cp infra/environments/local/.env.example infra/environments/local/.env
|
||||
```
|
||||
|
||||
### 2. Setup Networks
|
||||
|
||||
```bash
|
||||
./infra/scripts/setup-networks.sh
|
||||
```
|
||||
|
||||
### 3. Deploy
|
||||
|
||||
```bash
|
||||
./infra/scripts/deploy.sh local all
|
||||
```
|
||||
|
||||
### 4. Access Services
|
||||
|
||||
- **Grafana**: http://localhost:3000 (admin/admin)
|
||||
- **MinIO**: http://localhost:9093 (minioadmin/minioadmin)
|
||||
- **Vault**: http://localhost:8200 (token: dev-root-token)
|
||||
- **Traefik Dashboard**: http://localhost:8080
|
||||
|
||||
### 5. Build and Run Services
|
||||
|
||||
```bash
|
||||
# Build images
|
||||
./scripts/build-and-push-images.sh localhost:5000 latest local
|
||||
|
||||
# Services will auto-start via deploy script
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Development Server
|
||||
|
||||
### 1. SSH to Server
|
||||
|
||||
```bash
|
||||
ssh deploy@dev-server.harkon.co.uk
|
||||
cd /opt/ai-tax-agent
|
||||
```
|
||||
|
||||
### 2. Create Environment File
|
||||
|
||||
```bash
|
||||
cp infra/environments/development/.env.example infra/environments/development/.env
|
||||
```
|
||||
|
||||
### 3. Generate Secrets
|
||||
|
||||
```bash
|
||||
./scripts/generate-production-secrets.sh
|
||||
```
|
||||
|
||||
### 4. Edit Environment
|
||||
|
||||
```bash
|
||||
vim infra/environments/development/.env
|
||||
```
|
||||
|
||||
Update:
|
||||
- `DOMAIN=dev.harkon.co.uk`
|
||||
- API keys
|
||||
- Registry credentials
|
||||
|
||||
### 5. Deploy
|
||||
|
||||
```bash
|
||||
./infra/scripts/setup-networks.sh
|
||||
./infra/scripts/deploy.sh development all
|
||||
```
|
||||
|
||||
### 6. Access
|
||||
|
||||
- https://grafana.dev.harkon.co.uk
|
||||
- https://minio.dev.harkon.co.uk
|
||||
- https://vault.dev.harkon.co.uk
|
||||
|
||||
---
|
||||
|
||||
## Production Server
|
||||
|
||||
### 1. SSH to Server
|
||||
|
||||
```bash
|
||||
ssh deploy@141.136.35.199
|
||||
cd /opt/ai-tax-agent
|
||||
```
|
||||
|
||||
### 2. Verify Environment File
|
||||
|
||||
```bash
|
||||
# Should already exist from previous setup
|
||||
cat infra/environments/production/.env | grep DOMAIN
|
||||
```
|
||||
|
||||
### 3. Deploy Infrastructure
|
||||
|
||||
```bash
|
||||
./infra/scripts/setup-networks.sh
|
||||
./infra/scripts/deploy.sh production infrastructure
|
||||
```
|
||||
|
||||
### 4. Deploy Monitoring
|
||||
|
||||
```bash
|
||||
./infra/scripts/deploy.sh production monitoring
|
||||
```
|
||||
|
||||
### 5. Deploy Services
|
||||
|
||||
```bash
|
||||
./infra/scripts/deploy.sh production services
|
||||
```
|
||||
|
||||
### 6. Access
|
||||
|
||||
- https://grafana.harkon.co.uk
|
||||
- https://minio.harkon.co.uk
|
||||
- https://vault.harkon.co.uk
|
||||
- https://ui-review.harkon.co.uk
|
||||
|
||||
---
|
||||
|
||||
## Common Commands
|
||||
|
||||
### Deploy Specific Stack
|
||||
|
||||
```bash
|
||||
# Infrastructure only
|
||||
./infra/scripts/deploy.sh production infrastructure
|
||||
|
||||
# Monitoring only
|
||||
./infra/scripts/deploy.sh production monitoring
|
||||
|
||||
# Services only
|
||||
./infra/scripts/deploy.sh production services
|
||||
```
|
||||
|
||||
### Stop Services
|
||||
|
||||
```bash
|
||||
./infra/scripts/deploy.sh production down
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# All services
|
||||
docker compose -f infra/base/infrastructure.yaml --env-file infra/environments/production/.env logs -f
|
||||
|
||||
# Specific service
|
||||
docker logs -f vault
|
||||
```
|
||||
|
||||
### Restart Service
|
||||
|
||||
```bash
|
||||
docker restart vault
|
||||
```
|
||||
|
||||
### Check Status
|
||||
|
||||
```bash
|
||||
docker ps
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Services Not Starting
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
docker compose -f infra/base/infrastructure.yaml --env-file infra/environments/production/.env logs
|
||||
|
||||
# Check specific service
|
||||
docker logs vault
|
||||
```
|
||||
|
||||
### Network Issues
|
||||
|
||||
```bash
|
||||
# Verify networks exist
|
||||
docker network ls | grep -E "frontend|backend"
|
||||
|
||||
# Recreate networks
|
||||
docker network rm frontend backend
|
||||
./infra/scripts/setup-networks.sh
|
||||
```
|
||||
|
||||
### Environment Variables Not Loading
|
||||
|
||||
```bash
|
||||
# Verify .env file exists
|
||||
ls -la infra/environments/production/.env
|
||||
|
||||
# Check variables
|
||||
cat infra/environments/production/.env | grep DOMAIN
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ Infrastructure running
|
||||
2. 📖 Read [DEPLOYMENT_GUIDE.md](DEPLOYMENT_GUIDE.md) for detailed instructions
|
||||
3. 🔧 Configure Authentik OAuth providers
|
||||
4. 🚀 Deploy application services
|
||||
5. 📊 Setup Grafana dashboards
|
||||
6. 🔐 Initialize Vault secrets
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
- **Documentation**: See `infra/README.md`
|
||||
- **Deployment Guide**: See `infra/DEPLOYMENT_GUIDE.md`
|
||||
- **Migration Guide**: See `infra/MIGRATION_GUIDE.md`
|
||||
- **Structure Overview**: See `infra/STRUCTURE_OVERVIEW.md`
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Traefik │
|
||||
│ (Reverse Proxy) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────┼───────────────────┐
|
||||
│ │ │
|
||||
┌───────▼────────┐ ┌──────▼──────┐ ┌────────▼────────┐
|
||||
│ Authentik │ │ Monitoring │ │ Application │
|
||||
│ (SSO) │ │ (Grafana) │ │ Services │
|
||||
└────────────────┘ └──────────────┘ └─────────────────┘
|
||||
│
|
||||
┌───────────────────┼───────────────────┐
|
||||
│ │ │
|
||||
┌───────▼────────┐ ┌──────▼──────┐ ┌────────▼────────┐
|
||||
│ PostgreSQL │ │ Neo4j │ │ Qdrant │
|
||||
└────────────────┘ └──────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
┌───────▼────────┐ ┌──────▼──────┐ ┌────────▼────────┐
|
||||
│ MinIO │ │ Redis │ │ NATS │
|
||||
└────────────────┘ └──────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment Comparison
|
||||
|
||||
| Feature | Local | Development | Production |
|
||||
|---------|-------|-------------|------------|
|
||||
| Domain | localhost | dev.harkon.co.uk | harkon.co.uk |
|
||||
| SSL | Self-signed | Let's Encrypt | Let's Encrypt |
|
||||
| Auth | Optional | Authentik | Authentik |
|
||||
| Passwords | Simple | Strong | Strong |
|
||||
| Monitoring | Optional | Full | Full |
|
||||
| Backups | No | Daily | Daily |
|
||||
|
||||
---
|
||||
|
||||
## Service Ports (Local)
|
||||
|
||||
| Service | Port | URL |
|
||||
|---------|------|-----|
|
||||
| Traefik Dashboard | 8080 | http://localhost:8080 |
|
||||
| Grafana | 3000 | http://localhost:3000 |
|
||||
| MinIO Console | 9093 | http://localhost:9093 |
|
||||
| Vault | 8200 | http://localhost:8200 |
|
||||
| PostgreSQL | 5432 | localhost:5432 |
|
||||
| Neo4j | 7474 | http://localhost:7474 |
|
||||
| Redis | 6379 | localhost:6379 |
|
||||
| Qdrant | 6333 | http://localhost:6333 |
|
||||
|
||||
---
|
||||
|
||||
## Deployment Checklist
|
||||
|
||||
### Before Deployment
|
||||
|
||||
- [ ] Environment file created
|
||||
- [ ] Secrets generated (dev/prod)
|
||||
- [ ] Docker networks created
|
||||
- [ ] DNS configured (dev/prod)
|
||||
- [ ] GoDaddy API credentials set (dev/prod)
|
||||
- [ ] Gitea registry configured (dev/prod)
|
||||
|
||||
### After Deployment
|
||||
|
||||
- [ ] All services running (`docker ps`)
|
||||
- [ ] Services accessible via URLs
|
||||
- [ ] Grafana dashboards loaded
|
||||
- [ ] Vault initialized
|
||||
- [ ] MinIO buckets created
|
||||
- [ ] Authentik configured (dev/prod)
|
||||
- [ ] Monitoring alerts configured
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Environment Files
|
||||
|
||||
- Local: `infra/environments/local/.env`
|
||||
- Development: `infra/environments/development/.env`
|
||||
- Production: `infra/environments/production/.env`
|
||||
|
||||
### Compose Files
|
||||
|
||||
- Infrastructure: `infra/base/infrastructure.yaml`
|
||||
- Services: `infra/base/services.yaml`
|
||||
- Monitoring: `infra/base/monitoring.yaml`
|
||||
- External: `infra/base/external.yaml`
|
||||
|
||||
### Scripts
|
||||
|
||||
- Deploy: `./infra/scripts/deploy.sh <env> <stack>`
|
||||
- Setup Networks: `./infra/scripts/setup-networks.sh`
|
||||
- Reorganize: `./infra/scripts/reorganize-structure.sh`
|
||||
|
||||
---
|
||||
|
||||
**Ready to deploy? Start with local development!**
|
||||
|
||||
```bash
|
||||
cp infra/environments/local/.env.example infra/environments/local/.env
|
||||
./infra/scripts/setup-networks.sh
|
||||
./infra/scripts/deploy.sh local all
|
||||
```
|
||||
|
||||
247
infra/README.md
Normal file
247
infra/README.md
Normal file
@@ -0,0 +1,247 @@
|
||||
# AI Tax Agent Infrastructure
|
||||
|
||||
Multi-environment Docker Compose infrastructure for AI Tax Agent.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
infra/
|
||||
├── environments/ # Environment-specific configurations
|
||||
│ ├── local/ # Local development (localhost, self-signed certs)
|
||||
│ ├── development/ # Development server (dev.harkon.co.uk)
|
||||
│ └── production/ # Production server (harkon.co.uk)
|
||||
│
|
||||
├── base/ # Base compose files (shared across environments)
|
||||
│ ├── infrastructure.yaml # Core infra (Vault, MinIO, DBs, etc.)
|
||||
│ ├── monitoring.yaml # Monitoring stack (Prometheus, Grafana, Loki)
|
||||
│ ├── services.yaml # Application services
|
||||
│ └── external.yaml # External services (Traefik, Authentik, Gitea, etc.)
|
||||
│
|
||||
├── configs/ # Service configurations
|
||||
│ ├── traefik/ # Traefik configs
|
||||
│ ├── grafana/ # Grafana dashboards & provisioning
|
||||
│ ├── prometheus/ # Prometheus config
|
||||
│ ├── loki/ # Loki config
|
||||
│ ├── vault/ # Vault config
|
||||
│ └── authentik/ # Authentik bootstrap
|
||||
│
|
||||
├── certs/ # SSL certificates (gitignored)
|
||||
│ ├── local/ # Self-signed certs for local
|
||||
│ ├── development/ # Let's Encrypt certs for dev
|
||||
│ └── production/ # Let's Encrypt certs for prod
|
||||
│
|
||||
└── scripts/ # Deployment scripts
|
||||
├── deploy.sh # Main deployment script
|
||||
├── setup-networks.sh # Create Docker networks
|
||||
└── cleanup.sh # Cleanup script
|
||||
```
|
||||
|
||||
## Environments
|
||||
|
||||
### Local Development
|
||||
- **Domain**: `localhost` / `*.local.harkon.co.uk`
|
||||
- **SSL**: Self-signed certificates
|
||||
- **Auth**: Authentik (optional)
|
||||
- **Registry**: Local Docker registry or Gitea
|
||||
- **Purpose**: Local development and testing
|
||||
|
||||
### Development
|
||||
- **Domain**: `*.dev.harkon.co.uk`
|
||||
- **SSL**: Let's Encrypt (DNS-01 challenge)
|
||||
- **Auth**: Authentik SSO
|
||||
- **Registry**: Gitea container registry
|
||||
- **Purpose**: Staging/testing before production
|
||||
|
||||
### Production
|
||||
- **Domain**: `*.harkon.co.uk`
|
||||
- **SSL**: Let's Encrypt (DNS-01 challenge)
|
||||
- **Auth**: Authentik SSO
|
||||
- **Registry**: Gitea container registry
|
||||
- **Purpose**: Production deployment
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Setup Environment
|
||||
|
||||
```bash
|
||||
# Choose your environment
|
||||
export ENV=local # or development, production
|
||||
|
||||
# Copy environment template
|
||||
cp infra/environments/$ENV/.env.example infra/environments/$ENV/.env
|
||||
|
||||
# Edit environment variables
|
||||
vim infra/environments/$ENV/.env
|
||||
```
|
||||
|
||||
### 2. Generate Secrets (Production/Development only)
|
||||
|
||||
```bash
|
||||
./scripts/generate-production-secrets.sh
|
||||
```
|
||||
|
||||
### 3. Create Docker Networks
|
||||
|
||||
```bash
|
||||
./infra/scripts/setup-networks.sh
|
||||
```
|
||||
|
||||
### 4. Deploy Infrastructure
|
||||
|
||||
```bash
|
||||
# Deploy everything
|
||||
./infra/scripts/deploy.sh $ENV all
|
||||
|
||||
# Or deploy specific stacks
|
||||
./infra/scripts/deploy.sh $ENV infrastructure
|
||||
./infra/scripts/deploy.sh $ENV monitoring
|
||||
./infra/scripts/deploy.sh $ENV services
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Each environment has its own `.env` file with:
|
||||
|
||||
- **Domain Configuration**: `DOMAIN`, `EMAIL`
|
||||
- **Database Passwords**: `POSTGRES_PASSWORD`, `NEO4J_PASSWORD`, etc.
|
||||
- **Object Storage**: `MINIO_ROOT_USER`, `MINIO_ROOT_PASSWORD`
|
||||
- **Secrets Management**: `VAULT_DEV_ROOT_TOKEN_ID`
|
||||
- **SSO/Auth**: `AUTHENTIK_SECRET_KEY`, `AUTHENTIK_BOOTSTRAP_PASSWORD`
|
||||
- **Monitoring**: `GRAFANA_PASSWORD`, OAuth secrets
|
||||
- **Application**: Service-specific configs
|
||||
|
||||
## Deployment Commands
|
||||
|
||||
### Deploy Full Stack
|
||||
|
||||
```bash
|
||||
# Local
|
||||
./infra/scripts/deploy.sh local all
|
||||
|
||||
# Development
|
||||
./infra/scripts/deploy.sh development all
|
||||
|
||||
# Production
|
||||
./infra/scripts/deploy.sh production all
|
||||
```
|
||||
|
||||
### Deploy Individual Stacks
|
||||
|
||||
```bash
|
||||
# Infrastructure only (Vault, MinIO, DBs, etc.)
|
||||
./infra/scripts/deploy.sh production infrastructure
|
||||
|
||||
# Monitoring only (Prometheus, Grafana, Loki)
|
||||
./infra/scripts/deploy.sh production monitoring
|
||||
|
||||
# Services only (Application microservices)
|
||||
./infra/scripts/deploy.sh production services
|
||||
|
||||
# External services (Traefik, Authentik, Gitea - usually pre-existing)
|
||||
./infra/scripts/deploy.sh production external
|
||||
```
|
||||
|
||||
### Stop/Remove Stacks
|
||||
|
||||
```bash
|
||||
# Stop all
|
||||
./infra/scripts/deploy.sh production down
|
||||
|
||||
# Stop specific stack
|
||||
docker compose -f infra/base/infrastructure.yaml --env-file infra/environments/production/.env down
|
||||
```
|
||||
|
||||
## Network Architecture
|
||||
|
||||
All environments use two Docker networks:
|
||||
|
||||
- **frontend**: Public-facing services (Traefik, UI)
|
||||
- **backend**: Internal services (DBs, message queues, etc.)
|
||||
|
||||
Networks are created with:
|
||||
```bash
|
||||
docker network create frontend
|
||||
docker network create backend
|
||||
```
|
||||
|
||||
## Volume Management
|
||||
|
||||
Volumes are environment-specific and named with environment prefix:
|
||||
|
||||
- Local: `local_postgres_data`, `local_vault_data`, etc.
|
||||
- Development: `dev_postgres_data`, `dev_vault_data`, etc.
|
||||
- Production: `prod_postgres_data`, `prod_vault_data`, etc.
|
||||
|
||||
## SSL Certificates
|
||||
|
||||
### Local
|
||||
- Self-signed certificates in `infra/certs/local/`
|
||||
- Generated with `scripts/generate-dev-certs.sh`
|
||||
|
||||
### Development/Production
|
||||
- Let's Encrypt certificates via Traefik
|
||||
- DNS-01 challenge using GoDaddy API
|
||||
- Stored in `infra/certs/{environment}/`
|
||||
|
||||
## External Services
|
||||
|
||||
Some services (Traefik, Authentik, Gitea, Nextcloud, Portainer) may already exist on the server.
|
||||
|
||||
To use existing services:
|
||||
1. Don't deploy `external.yaml`
|
||||
2. Ensure networks are shared
|
||||
3. Update service discovery labels
|
||||
|
||||
## Monitoring
|
||||
|
||||
Access monitoring dashboards:
|
||||
|
||||
- **Grafana**: `https://grafana.{domain}`
|
||||
- **Prometheus**: `https://prometheus.{domain}`
|
||||
- **Traefik Dashboard**: `https://traefik.{domain}/dashboard/`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check Service Status
|
||||
|
||||
```bash
|
||||
docker compose -f infra/base/infrastructure.yaml --env-file infra/environments/production/.env ps
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
docker compose -f infra/base/infrastructure.yaml --env-file infra/environments/production/.env logs -f vault
|
||||
```
|
||||
|
||||
### Restart Service
|
||||
|
||||
```bash
|
||||
docker compose -f infra/base/infrastructure.yaml --env-file infra/environments/production/.env restart vault
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- **Never commit `.env` files** - They contain secrets!
|
||||
- **Rotate secrets regularly** - Use `generate-production-secrets.sh`
|
||||
- **Use strong passwords** - Minimum 32 characters
|
||||
- **Enable Authentik SSO** - For all production services
|
||||
- **Backup volumes** - Especially databases and Vault
|
||||
|
||||
## Migration from Old Structure
|
||||
|
||||
If migrating from the old structure:
|
||||
|
||||
1. Copy environment variables from old `.env` files
|
||||
2. Update volume names if needed
|
||||
3. Migrate data volumes
|
||||
4. Update Traefik labels if using existing Traefik
|
||||
5. Test in development first!
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- Check logs: `docker compose logs -f <service>`
|
||||
- Review documentation in `docs/`
|
||||
- Check Traefik dashboard for routing issues
|
||||
|
||||
243
infra/STRUCTURE_CLEANUP.md
Normal file
243
infra/STRUCTURE_CLEANUP.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# Infrastructure Structure Cleanup Plan
|
||||
|
||||
## Current Situation
|
||||
|
||||
We have two parallel structures that need to be aligned:
|
||||
|
||||
### 1. External Services (Production/Remote)
|
||||
Located in `infra/compose/` - These are deployed individually on the remote server:
|
||||
- **Traefik** - `infra/compose/traefik/`
|
||||
- **Authentik** - `infra/compose/authentik/`
|
||||
- **Gitea** - `infra/compose/gitea/`
|
||||
- **Nextcloud** - `infra/compose/nextcloud/`
|
||||
- **Portainer** - `infra/compose/portainer/`
|
||||
|
||||
### 2. Application Infrastructure (Multi-Environment)
|
||||
Located in `infra/base/` and `infra/environments/`:
|
||||
- Infrastructure services (Vault, MinIO, DBs, etc.)
|
||||
- Application services (14 microservices)
|
||||
- Monitoring stack (Prometheus, Grafana, Loki)
|
||||
|
||||
### 3. Configuration Duplication
|
||||
- `infra/compose/traefik/config/` - Production Traefik config
|
||||
- `infra/configs/traefik/` - Application Traefik config (copied)
|
||||
- Similar duplication for other services
|
||||
|
||||
---
|
||||
|
||||
## Cleanup Strategy
|
||||
|
||||
### Phase 1: Consolidate Configurations
|
||||
|
||||
#### Traefik
|
||||
- **Keep**: `infra/compose/traefik/` as the source of truth for production
|
||||
- **Symlink**: `infra/configs/traefik/` → `../compose/traefik/`
|
||||
- **Reason**: External service configs should live with their compose files
|
||||
|
||||
#### Authentik
|
||||
- **Keep**: `infra/compose/authentik/` for production
|
||||
- **Keep**: `infra/configs/authentik/` for application-specific bootstrap
|
||||
- **Reason**: Different purposes - one for service, one for app integration
|
||||
|
||||
#### Grafana/Prometheus/Loki
|
||||
- **Keep**: `infra/configs/grafana/`, `infra/configs/prometheus/`, `infra/configs/loki/`
|
||||
- **Reason**: These are application-specific, not external services
|
||||
|
||||
### Phase 2: Update References
|
||||
|
||||
#### Makefile
|
||||
- Update paths to reference correct locations
|
||||
- Add targets for external service deployment
|
||||
- Separate local dev from production deployment
|
||||
|
||||
#### Scripts
|
||||
- Update `scripts/deploy.sh` to handle external services
|
||||
- Create `scripts/deploy-external.sh` for production external services
|
||||
- Update `infra/scripts/deploy.sh` for application infrastructure
|
||||
|
||||
### Phase 3: Documentation
|
||||
|
||||
- Clear separation between:
|
||||
- External services (production only)
|
||||
- Application infrastructure (multi-environment)
|
||||
- Development environment (local only)
|
||||
|
||||
---
|
||||
|
||||
## Proposed Final Structure
|
||||
|
||||
```
|
||||
ai-tax-agent/
|
||||
├── infra/
|
||||
│ ├── compose/ # External services (production)
|
||||
│ │ ├── traefik/
|
||||
│ │ │ ├── compose.yaml # Traefik service definition
|
||||
│ │ │ ├── config/ # Traefik configuration
|
||||
│ │ │ ├── certs/ # SSL certificates
|
||||
│ │ │ └── .provider.env # GoDaddy API credentials
|
||||
│ │ ├── authentik/
|
||||
│ │ │ ├── compose.yaml
|
||||
│ │ │ ├── .env
|
||||
│ │ │ ├── media/
|
||||
│ │ │ └── custom-templates/
|
||||
│ │ ├── gitea/
|
||||
│ │ │ ├── compose.yaml
|
||||
│ │ │ └── .env
|
||||
│ │ ├── nextcloud/
|
||||
│ │ │ └── compose.yaml
|
||||
│ │ ├── portainer/
|
||||
│ │ │ └── docker-compose.yaml
|
||||
│ │ ├── docker-compose.local.yml # Local dev (all-in-one)
|
||||
│ │ └── docker-compose.backend.yml # Backend services
|
||||
│ │
|
||||
│ ├── base/ # Application infrastructure (multi-env)
|
||||
│ │ ├── infrastructure.yaml # Core infra services
|
||||
│ │ ├── services.yaml # Application microservices
|
||||
│ │ └── monitoring.yaml # Monitoring stack
|
||||
│ │
|
||||
│ ├── environments/ # Environment-specific configs
|
||||
│ │ ├── local/
|
||||
│ │ │ ├── .env.example
|
||||
│ │ │ └── .env
|
||||
│ │ ├── development/
|
||||
│ │ │ ├── .env.example
|
||||
│ │ │ └── .env
|
||||
│ │ └── production/
|
||||
│ │ ├── .env.example
|
||||
│ │ └── .env
|
||||
│ │
|
||||
│ ├── configs/ # Application service configs
|
||||
│ │ ├── authentik/ # App-specific Authentik bootstrap
|
||||
│ │ ├── grafana/ # Grafana dashboards
|
||||
│ │ ├── prometheus/ # Prometheus scrape configs
|
||||
│ │ ├── loki/ # Loki config
|
||||
│ │ └── vault/ # Vault config
|
||||
│ │
|
||||
│ └── scripts/ # Infrastructure deployment scripts
|
||||
│ ├── deploy.sh # Deploy application infrastructure
|
||||
│ ├── setup-networks.sh # Create Docker networks
|
||||
│ └── reorganize-structure.sh
|
||||
│
|
||||
├── scripts/ # Project-wide scripts
|
||||
│ ├── deploy-external.sh # Deploy external services (production)
|
||||
│ ├── build-and-push-images.sh # Build and push Docker images
|
||||
│ ├── generate-secrets.sh # Generate secrets
|
||||
│ └── ...
|
||||
│
|
||||
└── Makefile # Project commands
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment Workflows
|
||||
|
||||
### Local Development
|
||||
```bash
|
||||
# Use all-in-one compose file
|
||||
make bootstrap
|
||||
make run
|
||||
# OR
|
||||
cd infra/compose
|
||||
docker compose -f docker-compose.local.yml up -d
|
||||
```
|
||||
|
||||
### Production - External Services
|
||||
```bash
|
||||
# Deploy individually on remote server
|
||||
cd /opt/ai-tax-agent/infra/compose/traefik
|
||||
docker compose up -d
|
||||
|
||||
cd /opt/ai-tax-agent/infra/compose/authentik
|
||||
docker compose up -d
|
||||
|
||||
cd /opt/ai-tax-agent/infra/compose/gitea
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Production - Application Infrastructure
|
||||
```bash
|
||||
# Deploy application infrastructure
|
||||
./infra/scripts/deploy.sh production infrastructure
|
||||
./infra/scripts/deploy.sh production monitoring
|
||||
./infra/scripts/deploy.sh production services
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration Steps
|
||||
|
||||
### Step 1: Align Traefik Configs
|
||||
|
||||
```bash
|
||||
# Remove duplicate configs
|
||||
rm -rf infra/configs/traefik/config/traefik-dynamic.yml
|
||||
|
||||
# Keep only app-specific middleware
|
||||
# Move production configs to compose/traefik/config/
|
||||
```
|
||||
|
||||
### Step 2: Update Makefile
|
||||
|
||||
- Add targets for external service deployment
|
||||
- Update paths to reference correct locations
|
||||
- Separate local dev from production
|
||||
|
||||
### Step 3: Update Scripts
|
||||
|
||||
- Create `scripts/deploy-external.sh` for production
|
||||
- Update `infra/scripts/deploy.sh` for application infra
|
||||
- Update all path references
|
||||
|
||||
### Step 4: Documentation
|
||||
|
||||
- Update README files
|
||||
- Create deployment guides for each environment
|
||||
- Document external vs application services
|
||||
|
||||
---
|
||||
|
||||
## Key Decisions
|
||||
|
||||
### 1. External Services Location
|
||||
**Decision**: Keep in `infra/compose/` with individual folders
|
||||
**Reason**: These are production-only, deployed separately, have their own configs
|
||||
|
||||
### 2. Application Infrastructure Location
|
||||
**Decision**: Keep in `infra/base/` with environment-specific `.env` files
|
||||
**Reason**: Multi-environment support, shared compose files
|
||||
|
||||
### 3. Configuration Management
|
||||
**Decision**:
|
||||
- External service configs live with their compose files
|
||||
- Application configs live in `infra/configs/`
|
||||
**Reason**: Clear separation of concerns
|
||||
|
||||
### 4. Makefile Targets
|
||||
**Decision**:
|
||||
- `make run` - Local development (all-in-one)
|
||||
- `make deploy-external` - Production external services
|
||||
- `make deploy-infra` - Application infrastructure
|
||||
**Reason**: Clear separation of deployment targets
|
||||
|
||||
---
|
||||
|
||||
## Benefits
|
||||
|
||||
✅ **Clear Separation** - External vs application services
|
||||
✅ **No Duplication** - Single source of truth for configs
|
||||
✅ **Multi-Environment** - Easy to deploy to local/dev/prod
|
||||
✅ **Maintainable** - Logical organization
|
||||
✅ **Scalable** - Easy to add new services
|
||||
✅ **Production-Ready** - Matches actual deployment
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Run cleanup script to align configurations
|
||||
2. Update Makefile with new targets
|
||||
3. Update deployment scripts
|
||||
4. Test local deployment
|
||||
5. Test production deployment
|
||||
6. Update documentation
|
||||
|
||||
346
infra/STRUCTURE_OVERVIEW.md
Normal file
346
infra/STRUCTURE_OVERVIEW.md
Normal file
@@ -0,0 +1,346 @@
|
||||
# Infrastructure Structure Overview
|
||||
|
||||
## New Multi-Environment Structure
|
||||
|
||||
```
|
||||
infra/
|
||||
├── README.md # Main infrastructure documentation
|
||||
├── DEPLOYMENT_GUIDE.md # Complete deployment guide
|
||||
├── MIGRATION_GUIDE.md # Migration from old structure
|
||||
├── STRUCTURE_OVERVIEW.md # This file
|
||||
│
|
||||
├── base/ # Base compose files (environment-agnostic)
|
||||
│ ├── infrastructure.yaml # Core infrastructure services
|
||||
│ ├── services.yaml # Application microservices
|
||||
│ ├── monitoring.yaml # Monitoring stack
|
||||
│ └── external.yaml # External services (Traefik, Authentik, etc.)
|
||||
│
|
||||
├── environments/ # Environment-specific configurations
|
||||
│ ├── local/ # Local development
|
||||
│ │ ├── .env.example # Template
|
||||
│ │ └── .env # Actual config (gitignored)
|
||||
│ ├── development/ # Development server
|
||||
│ │ ├── .env.example # Template
|
||||
│ │ └── .env # Actual config (gitignored)
|
||||
│ └── production/ # Production server
|
||||
│ ├── .env.example # Template
|
||||
│ └── .env # Actual config (gitignored)
|
||||
│
|
||||
├── configs/ # Service configuration files
|
||||
│ ├── traefik/ # Traefik configs
|
||||
│ │ ├── config/ # Dynamic configuration
|
||||
│ │ │ ├── middlewares.yml
|
||||
│ │ │ ├── routers.yml
|
||||
│ │ │ └── services.yml
|
||||
│ │ ├── traefik.yml # Static configuration
|
||||
│ │ └── .provider.env # GoDaddy API credentials (gitignored)
|
||||
│ ├── grafana/ # Grafana configs
|
||||
│ │ ├── dashboards/ # Dashboard JSON files
|
||||
│ │ └── provisioning/ # Datasources, dashboards
|
||||
│ ├── prometheus/ # Prometheus config
|
||||
│ │ └── prometheus.yml
|
||||
│ ├── loki/ # Loki config
|
||||
│ │ └── loki-config.yml
|
||||
│ ├── promtail/ # Promtail config
|
||||
│ │ └── promtail-config.yml
|
||||
│ ├── vault/ # Vault config
|
||||
│ │ └── config/
|
||||
│ └── authentik/ # Authentik bootstrap
|
||||
│ ├── bootstrap.yaml
|
||||
│ ├── custom-templates/
|
||||
│ └── media/
|
||||
│
|
||||
├── certs/ # SSL certificates (gitignored)
|
||||
│ ├── local/ # Self-signed certs
|
||||
│ ├── development/ # Let's Encrypt certs
|
||||
│ └── production/ # Let's Encrypt certs
|
||||
│
|
||||
├── docker/ # Dockerfile templates
|
||||
│ ├── base-runtime.Dockerfile # Base image for all services
|
||||
│ ├── base-ml.Dockerfile # Base image for ML services
|
||||
│ └── Dockerfile.ml-service.template
|
||||
│
|
||||
└── scripts/ # Deployment and utility scripts
|
||||
├── deploy.sh # Main deployment script
|
||||
├── setup-networks.sh # Create Docker networks
|
||||
└── cleanup.sh # Cleanup script
|
||||
```
|
||||
|
||||
## Base Compose Files
|
||||
|
||||
### infrastructure.yaml
|
||||
Core infrastructure services needed by the application:
|
||||
- **Vault** - Secrets management
|
||||
- **MinIO** - Object storage (S3-compatible)
|
||||
- **PostgreSQL** - Relational database
|
||||
- **Neo4j** - Graph database
|
||||
- **Qdrant** - Vector database
|
||||
- **Redis** - Cache and session store
|
||||
- **NATS** - Message queue (with JetStream)
|
||||
|
||||
### services.yaml
|
||||
Application microservices (14 services):
|
||||
- **svc-ingestion** - Document ingestion
|
||||
- **svc-extract** - Data extraction
|
||||
- **svc-kg** - Knowledge graph
|
||||
- **svc-rag-indexer** - RAG indexing (ML)
|
||||
- **svc-rag-retriever** - RAG retrieval (ML)
|
||||
- **svc-forms** - Form processing
|
||||
- **svc-hmrc** - HMRC integration
|
||||
- **svc-ocr** - OCR processing (ML)
|
||||
- **svc-rpa** - RPA automation
|
||||
- **svc-normalize-map** - Data normalization
|
||||
- **svc-reason** - Reasoning engine
|
||||
- **svc-firm-connectors** - Firm integrations
|
||||
- **svc-coverage** - Coverage analysis
|
||||
- **ui-review** - Review UI (Next.js)
|
||||
|
||||
### monitoring.yaml
|
||||
Monitoring and observability stack:
|
||||
- **Prometheus** - Metrics collection
|
||||
- **Grafana** - Dashboards and visualization
|
||||
- **Loki** - Log aggregation
|
||||
- **Promtail** - Log collection
|
||||
|
||||
### external.yaml (optional)
|
||||
External services that may already exist:
|
||||
- **Traefik** - Reverse proxy and load balancer
|
||||
- **Authentik** - SSO and authentication
|
||||
- **Gitea** - Git repository and container registry
|
||||
- **Nextcloud** - File storage
|
||||
- **Portainer** - Docker management UI
|
||||
|
||||
## Environment Configurations
|
||||
|
||||
### Local Development
|
||||
- **Domain**: `localhost` or `*.local.harkon.co.uk`
|
||||
- **SSL**: Self-signed certificates
|
||||
- **Auth**: Optional (can disable Authentik)
|
||||
- **Registry**: Local Docker registry or Gitea
|
||||
- **Passwords**: Simple (postgres, admin, etc.)
|
||||
- **Purpose**: Local development and testing
|
||||
- **Traefik Dashboard**: Exposed on port 8080
|
||||
|
||||
### Development Server
|
||||
- **Domain**: `*.dev.harkon.co.uk`
|
||||
- **SSL**: Let's Encrypt (DNS-01 via GoDaddy)
|
||||
- **Auth**: Authentik SSO enabled
|
||||
- **Registry**: Gitea container registry
|
||||
- **Passwords**: Strong (auto-generated)
|
||||
- **Purpose**: Staging and integration testing
|
||||
- **Traefik Dashboard**: Protected by Authentik
|
||||
|
||||
### Production Server
|
||||
- **Domain**: `*.harkon.co.uk`
|
||||
- **SSL**: Let's Encrypt (DNS-01 via GoDaddy)
|
||||
- **Auth**: Authentik SSO enabled
|
||||
- **Registry**: Gitea container registry
|
||||
- **Passwords**: Strong (auto-generated)
|
||||
- **Purpose**: Production deployment
|
||||
- **Traefik Dashboard**: Protected by Authentik
|
||||
- **Monitoring**: Full stack enabled
|
||||
|
||||
## Docker Networks
|
||||
|
||||
All environments use two networks:
|
||||
|
||||
### frontend
|
||||
- Public-facing services
|
||||
- Connected to Traefik
|
||||
- Services: UI, Grafana, Vault, MinIO console
|
||||
|
||||
### backend
|
||||
- Internal services
|
||||
- Not directly accessible
|
||||
- Services: Databases, message queues, internal APIs
|
||||
|
||||
## Volume Naming
|
||||
|
||||
Volumes are named consistently across environments:
|
||||
- `postgres_data`
|
||||
- `neo4j_data`
|
||||
- `neo4j_logs`
|
||||
- `qdrant_data`
|
||||
- `minio_data`
|
||||
- `vault_data`
|
||||
- `redis_data`
|
||||
- `nats_data`
|
||||
- `prometheus_data`
|
||||
- `grafana_data`
|
||||
- `loki_data`
|
||||
|
||||
## Deployment Workflow
|
||||
|
||||
### 1. Setup Environment
|
||||
```bash
|
||||
cp infra/environments/production/.env.example infra/environments/production/.env
|
||||
vim infra/environments/production/.env
|
||||
```
|
||||
|
||||
### 2. Generate Secrets
|
||||
```bash
|
||||
./scripts/generate-production-secrets.sh
|
||||
```
|
||||
|
||||
### 3. Setup Networks
|
||||
```bash
|
||||
./infra/scripts/setup-networks.sh
|
||||
```
|
||||
|
||||
### 4. Deploy Infrastructure
|
||||
```bash
|
||||
./infra/scripts/deploy.sh production infrastructure
|
||||
```
|
||||
|
||||
### 5. Deploy Monitoring
|
||||
```bash
|
||||
./infra/scripts/deploy.sh production monitoring
|
||||
```
|
||||
|
||||
### 6. Deploy Services
|
||||
```bash
|
||||
./infra/scripts/deploy.sh production services
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
### ✅ Multi-Environment Support
|
||||
Single codebase deploys to local, development, and production with environment-specific configurations.
|
||||
|
||||
### ✅ Modular Architecture
|
||||
Services split into logical groups (infrastructure, monitoring, services, external) for independent deployment.
|
||||
|
||||
### ✅ Unified Deployment
|
||||
Single `deploy.sh` script handles all environments and stacks.
|
||||
|
||||
### ✅ Environment Isolation
|
||||
Each environment has its own `.env` file with appropriate secrets and configurations.
|
||||
|
||||
### ✅ Shared Configurations
|
||||
Common service configs in `configs/` directory, referenced by all environments.
|
||||
|
||||
### ✅ Security Best Practices
|
||||
- Secrets in gitignored `.env` files
|
||||
- Strong password generation
|
||||
- Authentik SSO integration
|
||||
- SSL/TLS everywhere (Let's Encrypt)
|
||||
|
||||
### ✅ Easy Maintenance
|
||||
- Clear directory structure
|
||||
- Comprehensive documentation
|
||||
- Migration guide from old structure
|
||||
- Troubleshooting guides
|
||||
|
||||
## Service Access
|
||||
|
||||
### Local
|
||||
- http://localhost:3000 - Grafana
|
||||
- http://localhost:9093 - MinIO
|
||||
- http://localhost:8200 - Vault
|
||||
- http://localhost:8080 - Traefik Dashboard
|
||||
|
||||
### Development
|
||||
- https://grafana.dev.harkon.co.uk
|
||||
- https://minio.dev.harkon.co.uk
|
||||
- https://vault.dev.harkon.co.uk
|
||||
- https://ui-review.dev.harkon.co.uk
|
||||
|
||||
### Production
|
||||
- https://grafana.harkon.co.uk
|
||||
- https://minio.harkon.co.uk
|
||||
- https://vault.harkon.co.uk
|
||||
- https://ui-review.harkon.co.uk
|
||||
|
||||
## Configuration Management
|
||||
|
||||
### Environment Variables
|
||||
All configuration via environment variables in `.env` files:
|
||||
- Domain settings
|
||||
- Database passwords
|
||||
- API keys
|
||||
- OAuth secrets
|
||||
- Registry credentials
|
||||
|
||||
### Service Configs
|
||||
Static configurations in `configs/` directory:
|
||||
- Traefik routing rules
|
||||
- Grafana dashboards
|
||||
- Prometheus scrape configs
|
||||
- Loki retention policies
|
||||
|
||||
### Secrets Management
|
||||
- Development/Production: Vault
|
||||
- Local: Environment variables
|
||||
- Rotation: `generate-production-secrets.sh`
|
||||
|
||||
## Monitoring and Observability
|
||||
|
||||
### Metrics (Prometheus)
|
||||
- Service health
|
||||
- Resource usage
|
||||
- Request rates
|
||||
- Error rates
|
||||
|
||||
### Logs (Loki)
|
||||
- Centralized logging
|
||||
- Query via Grafana
|
||||
- Retention policies
|
||||
- Log aggregation
|
||||
|
||||
### Dashboards (Grafana)
|
||||
- Infrastructure overview
|
||||
- Service metrics
|
||||
- Application performance
|
||||
- Business metrics
|
||||
|
||||
### Alerts
|
||||
- Prometheus AlertManager
|
||||
- Slack/Email notifications
|
||||
- PagerDuty integration
|
||||
|
||||
## Backup Strategy
|
||||
|
||||
### What to Backup
|
||||
- PostgreSQL database
|
||||
- Neo4j graph data
|
||||
- Vault secrets
|
||||
- MinIO objects
|
||||
- Qdrant vectors
|
||||
- Grafana dashboards
|
||||
|
||||
### How to Backup
|
||||
```bash
|
||||
# Automated backup script
|
||||
./scripts/backup-volumes.sh production
|
||||
|
||||
# Manual backup
|
||||
docker run --rm -v postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres.tar.gz /data
|
||||
```
|
||||
|
||||
### Backup Schedule
|
||||
- Daily: Databases
|
||||
- Weekly: Full system
|
||||
- Monthly: Archive
|
||||
|
||||
## Disaster Recovery
|
||||
|
||||
### Recovery Steps
|
||||
1. Restore infrastructure
|
||||
2. Restore volumes from backup
|
||||
3. Deploy services
|
||||
4. Verify functionality
|
||||
5. Update DNS if needed
|
||||
|
||||
### RTO/RPO
|
||||
- **RTO**: 4 hours (Recovery Time Objective)
|
||||
- **RPO**: 24 hours (Recovery Point Objective)
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Review [DEPLOYMENT_GUIDE.md](DEPLOYMENT_GUIDE.md) for deployment instructions
|
||||
2. Review [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) if migrating from old structure
|
||||
3. Setup environment files
|
||||
4. Deploy to local first
|
||||
5. Test in development
|
||||
6. Deploy to production
|
||||
|
||||
228
infra/base/infrastructure.yaml
Normal file
228
infra/base/infrastructure.yaml
Normal file
@@ -0,0 +1,228 @@
|
||||
# FILE: infra/base/infrastructure.yaml
|
||||
# Infrastructure Services for AI Tax Agent
|
||||
# Environment-agnostic - use with environment-specific .env files
|
||||
# Deploy with: ./infra/scripts/deploy.sh <environment> infrastructure
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
external: true
|
||||
name: frontend
|
||||
backend:
|
||||
external: true
|
||||
name: backend
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
neo4j_data:
|
||||
neo4j_logs:
|
||||
qdrant_data:
|
||||
minio_data:
|
||||
vault_data:
|
||||
redis_data:
|
||||
nats_data:
|
||||
|
||||
services:
|
||||
# Secrets Management
|
||||
vault:
|
||||
image: hashicorp/vault:1.15
|
||||
container_name: vault
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
volumes:
|
||||
- vault_data:/vault/data
|
||||
environment:
|
||||
VAULT_DEV_ROOT_TOKEN_ID: ${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
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}`)"
|
||||
- "traefik.http.routers.vault.entrypoints=websecure"
|
||||
- "traefik.http.routers.vault.tls=true"
|
||||
- "traefik.http.routers.vault.tls.certresolver=godaddy"
|
||||
- "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
|
||||
- frontend
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
MINIO_BROWSER_REDIRECT_URL: https://minio.${DOMAIN}
|
||||
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}`)"
|
||||
- "traefik.http.routers.minio-api.entrypoints=websecure"
|
||||
- "traefik.http.routers.minio-api.tls=true"
|
||||
- "traefik.http.routers.minio-api.tls.certresolver=godaddy"
|
||||
- "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}`)"
|
||||
- "traefik.http.routers.minio-console.entrypoints=websecure"
|
||||
- "traefik.http.routers.minio-console.tls=true"
|
||||
- "traefik.http.routers.minio-console.tls.certresolver=godaddy"
|
||||
- "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
|
||||
- frontend
|
||||
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}`)"
|
||||
- "traefik.http.routers.qdrant.entrypoints=websecure"
|
||||
- "traefik.http.routers.qdrant.tls=true"
|
||||
- "traefik.http.routers.qdrant.tls.certresolver=godaddy"
|
||||
- "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
|
||||
- frontend
|
||||
volumes:
|
||||
- neo4j_data:/data
|
||||
- neo4j_logs:/logs
|
||||
environment:
|
||||
NEO4J_AUTH: neo4j/${NEO4J_PASSWORD}
|
||||
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}`)"
|
||||
- "traefik.http.routers.neo4j.entrypoints=websecure"
|
||||
- "traefik.http.routers.neo4j.tls=true"
|
||||
- "traefik.http.routers.neo4j.tls.certresolver=godaddy"
|
||||
- "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
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: tax_system
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
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
|
||||
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
|
||||
- frontend
|
||||
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}`)"
|
||||
- "traefik.http.routers.nats-monitor.entrypoints=websecure"
|
||||
- "traefik.http.routers.nats-monitor.tls=true"
|
||||
- "traefik.http.routers.nats-monitor.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.nats-monitor.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.nats-monitor.loadbalancer.server.port=8222"
|
||||
126
infra/base/monitoring.yaml
Normal file
126
infra/base/monitoring.yaml
Normal file
@@ -0,0 +1,126 @@
|
||||
# FILE: infra/compose/production/monitoring.yaml
|
||||
# Production Monitoring Stack for AI Tax Agent
|
||||
# Deploy to: /opt/compose/ai-tax-agent/monitoring.yaml
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
external: true
|
||||
name: frontend
|
||||
backend:
|
||||
external: true
|
||||
name: backend
|
||||
|
||||
volumes:
|
||||
prometheus_data:
|
||||
grafana_data:
|
||||
loki_data:
|
||||
|
||||
services:
|
||||
# Metrics Collection
|
||||
prometheus:
|
||||
image: prom/prometheus:v2.48.1
|
||||
container_name: prometheus
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
volumes:
|
||||
- prometheus_data:/prometheus
|
||||
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
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}`)"
|
||||
- "traefik.http.routers.prometheus.entrypoints=websecure"
|
||||
- "traefik.http.routers.prometheus.tls=true"
|
||||
- "traefik.http.routers.prometheus.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.prometheus.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
|
||||
|
||||
# Visualization & Dashboards
|
||||
grafana:
|
||||
image: grafana/grafana:10.2.3
|
||||
container_name: grafana
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
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}
|
||||
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}
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: ${GRAFANA_OAUTH_CLIENT_SECRET}
|
||||
GF_AUTH_GENERIC_OAUTH_SCOPES: openid profile email groups
|
||||
GF_AUTH_GENERIC_OAUTH_AUTH_URL: https://authentik.${DOMAIN}/application/o/authorize/
|
||||
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: https://authentik.${DOMAIN}/application/o/token/
|
||||
GF_AUTH_GENERIC_OAUTH_API_URL: https://authentik.${DOMAIN}/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
|
||||
GF_SERVER_ROOT_URL: https://grafana.${DOMAIN}
|
||||
GF_SERVER_SERVE_FROM_SUB_PATH: false
|
||||
GF_SECURITY_COOKIE_SECURE: true
|
||||
GF_SECURITY_COOKIE_SAMESITE: lax
|
||||
GF_AUTH_GENERIC_OAUTH_USE_PKCE: true
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN}`)"
|
||||
- "traefik.http.routers.grafana.entrypoints=websecure"
|
||||
- "traefik.http.routers.grafana.tls=true"
|
||||
- "traefik.http.routers.grafana.tls.certresolver=godaddy"
|
||||
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
|
||||
|
||||
# Log Aggregation
|
||||
loki:
|
||||
image: grafana/loki:2.9.4
|
||||
container_name: loki
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
volumes:
|
||||
- loki_data:/loki
|
||||
- ./loki/loki.yml:/etc/loki/local-config.yaml:ro
|
||||
command: -config.file=/etc/loki/local-config.yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.loki.rule=Host(`loki.${DOMAIN}`)"
|
||||
- "traefik.http.routers.loki.entrypoints=websecure"
|
||||
- "traefik.http.routers.loki.tls=true"
|
||||
- "traefik.http.routers.loki.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.loki.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.loki.loadbalancer.server.port=3100"
|
||||
|
||||
# Log Shipper (for Docker containers)
|
||||
promtail:
|
||||
image: grafana/promtail:2.9.4
|
||||
container_name: promtail
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- /var/log:/var/log:ro
|
||||
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
||||
- ./loki/promtail-config.yml:/etc/promtail/config.yml:ro
|
||||
command: -config.file=/etc/promtail/config.yml
|
||||
depends_on:
|
||||
- loki
|
||||
|
||||
453
infra/base/services.yaml
Normal file
453
infra/base/services.yaml
Normal file
@@ -0,0 +1,453 @@
|
||||
# FILE: infra/compose/production/services.yaml
|
||||
# Production Application Services for AI Tax Agent
|
||||
# Deploy to: /opt/compose/ai-tax-agent/services.yaml
|
||||
# NOTE: Build images locally and push to registry before deploying
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
external: true
|
||||
name: frontend
|
||||
backend:
|
||||
external: true
|
||||
name: backend
|
||||
|
||||
services:
|
||||
# Document Ingestion Service
|
||||
svc-ingestion:
|
||||
image: gitea.harkon.co.uk/harkon/svc-ingestion:latest
|
||||
container_name: svc-ingestion
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-ingestion.rule=Host(`api.${DOMAIN}`) && PathPrefix(`/ingestion`)"
|
||||
- "traefik.http.routers.svc-ingestion.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-ingestion.tls=true"
|
||||
- "traefik.http.routers.svc-ingestion.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-ingestion.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-ingestion.loadbalancer.server.port=8000"
|
||||
|
||||
# Data Extraction Service
|
||||
svc-extract:
|
||||
image: gitea.harkon.co.uk/harkon/svc-extract:latest
|
||||
container_name: svc-extract
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- RAG_EMBEDDING_MODEL=${RAG_EMBEDDING_MODEL}
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-extract.rule=Host(`api.${DOMAIN}`) && PathPrefix(`/extract`)"
|
||||
- "traefik.http.routers.svc-extract.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-extract.tls=true"
|
||||
- "traefik.http.routers.svc-extract.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-extract.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-extract.loadbalancer.server.port=8000"
|
||||
|
||||
# Knowledge Graph Service
|
||||
svc-kg:
|
||||
image: gitea.harkon.co.uk/harkon/svc-kg:latest
|
||||
container_name: svc-kg
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- NEO4J_URI=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-kg.rule=Host(`api.${DOMAIN}`) && PathPrefix(`/kg`)"
|
||||
- "traefik.http.routers.svc-kg.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-kg.tls=true"
|
||||
- "traefik.http.routers.svc-kg.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-kg.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-kg.loadbalancer.server.port=8000"
|
||||
|
||||
# RAG Retrieval Service
|
||||
svc-rag-retriever:
|
||||
image: gitea.harkon.co.uk/harkon/svc-rag-retriever:latest
|
||||
container_name: svc-rag-retriever
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- NEO4J_URI=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- RAG_EMBEDDING_MODEL=${RAG_EMBEDDING_MODEL}
|
||||
- RAG_RERANKER_MODEL=${RAG_RERANKER_MODEL}
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-rag-retriever.rule=Host(`api.${DOMAIN}`) && PathPrefix(`/rag`)"
|
||||
- "traefik.http.routers.svc-rag-retriever.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-rag-retriever.tls=true"
|
||||
- "traefik.http.routers.svc-rag-retriever.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-rag-retriever.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-rag-retriever.loadbalancer.server.port=8000"
|
||||
|
||||
# Forms Service
|
||||
svc-forms:
|
||||
image: gitea.harkon.co.uk/harkon/svc-forms:latest
|
||||
container_name: svc-forms
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-forms.rule=Host(`api.${DOMAIN}`) && PathPrefix(`/forms`)"
|
||||
- "traefik.http.routers.svc-forms.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-forms.tls=true"
|
||||
- "traefik.http.routers.svc-forms.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-forms.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-forms.loadbalancer.server.port=8000"
|
||||
|
||||
# HMRC Integration Service
|
||||
svc-hmrc:
|
||||
image: gitea.harkon.co.uk/harkon/svc-hmrc:latest
|
||||
container_name: svc-hmrc
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- HMRC_MTD_ITSA_MODE=${HMRC_MTD_ITSA_MODE}
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-hmrc.rule=Host(`api.${DOMAIN}`) && PathPrefix(`/hmrc`)"
|
||||
- "traefik.http.routers.svc-hmrc.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-hmrc.tls=true"
|
||||
- "traefik.http.routers.svc-hmrc.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-hmrc.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-hmrc.loadbalancer.server.port=8000"
|
||||
|
||||
# OCR Service
|
||||
svc-ocr:
|
||||
image: gitea.harkon.co.uk/harkon/svc-ocr:latest
|
||||
container_name: svc-ocr
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-ocr.rule=Host(`api.${DOMAIN}`) && PathPrefix(`/ocr`)"
|
||||
- "traefik.http.routers.svc-ocr.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-ocr.tls=true"
|
||||
- "traefik.http.routers.svc-ocr.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-ocr.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-ocr.loadbalancer.server.port=8000"
|
||||
|
||||
# RAG Indexer Service
|
||||
svc-rag-indexer:
|
||||
image: gitea.harkon.co.uk/harkon/svc-rag-indexer:latest
|
||||
container_name: svc-rag-indexer
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-rag-indexer.rule=Host(`api.${DOMAIN}`) && 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.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-rag-indexer.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-rag-indexer.loadbalancer.server.port=8000"
|
||||
|
||||
# Reasoning Service
|
||||
svc-reason:
|
||||
image: gitea.harkon.co.uk/harkon/svc-reason:latest
|
||||
container_name: svc-reason
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-reason.rule=Host(`api.${DOMAIN}`) && PathPrefix(`/reason`)"
|
||||
- "traefik.http.routers.svc-reason.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-reason.tls=true"
|
||||
- "traefik.http.routers.svc-reason.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-reason.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-reason.loadbalancer.server.port=8000"
|
||||
|
||||
# RPA Service
|
||||
svc-rpa:
|
||||
image: gitea.harkon.co.uk/harkon/svc-rpa:latest
|
||||
container_name: svc-rpa
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-rpa.rule=Host(`api.${DOMAIN}`) && PathPrefix(`/rpa`)"
|
||||
- "traefik.http.routers.svc-rpa.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-rpa.tls=true"
|
||||
- "traefik.http.routers.svc-rpa.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-rpa.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-rpa.loadbalancer.server.port=8000"
|
||||
|
||||
# Normalize & Map Service
|
||||
svc-normalize-map:
|
||||
image: gitea.harkon.co.uk/harkon/svc-normalize-map:latest
|
||||
container_name: svc-normalize-map
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-normalize-map.rule=Host(`api.${DOMAIN}`) && 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.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-normalize-map.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-normalize-map.loadbalancer.server.port=8000"
|
||||
|
||||
# Coverage Service
|
||||
svc-coverage:
|
||||
image: gitea.harkon.co.uk/harkon/svc-coverage:latest
|
||||
container_name: svc-coverage
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-coverage.rule=Host(`api.${DOMAIN}`) && PathPrefix(`/coverage`)"
|
||||
- "traefik.http.routers.svc-coverage.entrypoints=websecure"
|
||||
- "traefik.http.routers.svc-coverage.tls=true"
|
||||
- "traefik.http.routers.svc-coverage.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-coverage.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-coverage.loadbalancer.server.port=8000"
|
||||
|
||||
# Firm Connectors Service
|
||||
svc-firm-connectors:
|
||||
image: gitea.harkon.co.uk/harkon/svc-firm-connectors:latest
|
||||
container_name: svc-firm-connectors
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
environment:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID}
|
||||
- POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/tax_system
|
||||
- NEO4J_URL=bolt://neo4j:7687
|
||||
- NEO4J_USER=neo4j
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MINIO_ENDPOINT=minio:9092
|
||||
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
|
||||
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- EVENT_BUS_TYPE=${EVENT_BUS_TYPE}
|
||||
- NATS_SERVERS=${NATS_SERVERS}
|
||||
- NATS_STREAM_NAME=${NATS_STREAM_NAME}
|
||||
- NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.svc-firm-connectors.rule=Host(`api.${DOMAIN}`) && 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.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.svc-firm-connectors.middlewares=authentik-forwardauth@file,rate-limit@file"
|
||||
- "traefik.http.services.svc-firm-connectors.loadbalancer.server.port=8000"
|
||||
|
||||
# Review UI
|
||||
ui-review:
|
||||
image: gitea.harkon.co.uk/harkon/ui-review:latest
|
||||
container_name: ui-review
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- frontend
|
||||
environment:
|
||||
- NEXTAUTH_URL=https://app.${DOMAIN}
|
||||
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
|
||||
- API_BASE_URL=https://api.${DOMAIN}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.ui-review.rule=Host(`app.${DOMAIN}`)"
|
||||
- "traefik.http.routers.ui-review.entrypoints=websecure"
|
||||
- "traefik.http.routers.ui-review.tls=true"
|
||||
- "traefik.http.routers.ui-review.tls.certresolver=godaddy"
|
||||
- "traefik.http.routers.ui-review.middlewares=authentik-forwardauth@file"
|
||||
- "traefik.http.services.ui-review.loadbalancer.server.port=3030"
|
||||
23
infra/certs/local.crt
Normal file
23
infra/certs/local.crt
Normal file
@@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDwjCCAqqgAwIBAgIJAKln1RPU8Us4MA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNV
|
||||
BAMMBWxvY2FsMB4XDTI1MDkxOTA3NDg1N1oXDTM1MDkxNzA3NDg1N1owEDEOMAwG
|
||||
A1UEAwwFbG9jYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYyuta
|
||||
8C2BBd8lzbbLCsemT3hMDrVrYfKab8Iog1wpRWImuupyToWUaqgc0noy0GvaMM08
|
||||
SV72cjEOOgvcXwEu1a1hUow00uc7Mm1qjWZGIjD2QxnydpibmnhKWtEGkVZpZXk1
|
||||
aZ6cYiv6w60fGDRNbLdZHUHtq0IC8szVUbvC4WA3W1aFMxWkP3oXyhdUM/i9P/y8
|
||||
njyW+QZdCYeX9zUPH6CpMeGSofGTvsWSwLCIiBXQHkDLzmUItTYZEQFMBbo/SwjW
|
||||
VTQi5lWwQya/CKpnXQUldnMjvPOi4aZLVTnDPRjONILR0ZSUwijMdOaf2rNvN7C3
|
||||
7WwSiy0V423ExXj/AgMBAAGjggEdMIIBGTCCARUGA1UdEQSCAQwwggEIgglsb2Nh
|
||||
bGhvc3SHBH8AAAGCCyoubG9jYWwubGFugg5hdXRoLmxvY2FsLmxhboIRZ3JhZmFu
|
||||
YS5sb2NhbC5sYW6CEHJldmlldy5sb2NhbC5sYW6CDWFwaS5sb2NhbC5sYW6CD3Zh
|
||||
dWx0LmxvY2FsLmxhboIPbWluaW8ubG9jYWwubGFughNtaW5pby1hcGkubG9jYWwu
|
||||
bGFughBxZHJhbnQubG9jYWwubGFugg9uZW80ai5sb2NhbC5sYW6CFHByb21ldGhl
|
||||
dXMubG9jYWwubGFugg5sb2tpLmxvY2FsLmxhboIRdW5sZWFzaC5sb2NhbC5sYW6C
|
||||
EXRyYWVmaWsubG9jYWwubGFuMA0GCSqGSIb3DQEBCwUAA4IBAQAGC2uAwxlKbRnH
|
||||
QutOXJNKvcwZ8BnrIbVSdvuRRzaGDDXxjpFa35Z3QvmO+Qd6IqZHEEQvxRVZWtR6
|
||||
eWr9jiqi/NmhbxKiXnC0QzWotW4/As4uMGPPbJQXn35EbnSpt0XBrYjXvkX6kRUq
|
||||
WI3h0gH7sTrA8GObi9vZ5ySAGT0xxTxu9m4juBNqi++z6urr8exxoIMUNm9H49lW
|
||||
u4euVbI5+CKm603P9+pgTQPIT32U6ciPcrp4NJDTQ1lbejCi1aM9HTrvATgH5kYU
|
||||
2CsRU1oOOjn1kLyu+slk0T0HKOfDZtp6ByPrzQKnTz0TVLlXn7UBOimHEmPlXYW4
|
||||
O8Q/a0tg
|
||||
-----END CERTIFICATE-----
|
||||
28
infra/certs/local.key
Normal file
28
infra/certs/local.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCYyuta8C2BBd8l
|
||||
zbbLCsemT3hMDrVrYfKab8Iog1wpRWImuupyToWUaqgc0noy0GvaMM08SV72cjEO
|
||||
OgvcXwEu1a1hUow00uc7Mm1qjWZGIjD2QxnydpibmnhKWtEGkVZpZXk1aZ6cYiv6
|
||||
w60fGDRNbLdZHUHtq0IC8szVUbvC4WA3W1aFMxWkP3oXyhdUM/i9P/y8njyW+QZd
|
||||
CYeX9zUPH6CpMeGSofGTvsWSwLCIiBXQHkDLzmUItTYZEQFMBbo/SwjWVTQi5lWw
|
||||
Qya/CKpnXQUldnMjvPOi4aZLVTnDPRjONILR0ZSUwijMdOaf2rNvN7C37WwSiy0V
|
||||
423ExXj/AgMBAAECggEACGI5/8dl98pmsCBVg1aYFdwOcb3s3nOFaEvxj1+F0w3n
|
||||
kNB4xMTiN36SsuIpqlgdUt+So1gzSbqCTpGIzRK5ceRvmwN4hf18ipb9wfb4Qajm
|
||||
ntyXs+ImBYO4TfwltAKNh0L2H6Qn+9S3LQ9HlIkzdXwdo1ojn/LhsF+6NYpCjzLQ
|
||||
6m3RT4n9HEFB4N/S4WHJKL5RHrwlQ9A9o6t/BwLIMbUKDNZWHpcyrX/Ne3tzoYtd
|
||||
9csQ3GGGiVoqwB9m75nLEmB/atGK6sV7Zos6fa1Ln1mGKWRfkm+UYzuC/S1RPEHq
|
||||
LfbcQRGbgoEp7yoPZgLCEoX3xNp3vE+PJ+JVchZuYQKBgQDLOaU8msF6SApZwNjL
|
||||
QG20hHu4m99pe0h8bDd9MMzbMuHRY5FZFv6MrffEDa48vAPiKcbUiJ0N4p7txQJ3
|
||||
VBdz7ryZ92vE4H8R61IJRzpGVjuac/tWUpK5+pIF7TvGVrd8hS3i3so3m4AYmlW0
|
||||
5HBvNIF0qjT0o1SZwlZBDtJ10wKBgQDAeIiO2x3XSPXB7plS018AjammlI2Pn207
|
||||
WmLKuQw5E/d9smDSK4bT55gXyDWKgkPhjlk6LxbvSnyBHhVwshzJAf43ZByRaIht
|
||||
V7D4YnbgdiOWVr8aDeEgHRH1vy5Z99SZuyQU/beWxasb2P36xKifi92nNSSiPEqL
|
||||
9lQguIVYpQKBgQDDuvF6PVK7A0d0ylgC6jq+8hp24yl53lMiAtguqyGivI7hrJQA
|
||||
yjTAKY3INaTquerDmJj3edxJ00pelrCZXVR5RCZB5BrXs6CvEYYhiYiG1ebyC2K2
|
||||
8TCADuU08BfyHvL56wsWxpzckdf92idR4fKoKFnGk2gNdoG01YddgXkSIQKBgB7S
|
||||
bpPp9QJn1atDyVvhK4KMLRHXEkBguH5bwBxUu+dcEjMX4LdnbwT6Pnn4ftJ6f+Jc
|
||||
CF/v8I1LcVq/9ZEBhOiPoCVAq+6BPe+8rkNoiT7yzEokBCBo/pdE8H5ZKlQQAwTH
|
||||
WkTeSIslhnxEKJAC9DnwjQNc2Ev+ubVmMhy3T+tdAoGAN99dnO11+qQ1jHEwIKeI
|
||||
1JYeOizER62rk1CDStuGs92eiUF/eeYhzejgmk6pvtXeKgTw7vv4SKTfTxyg0pBY
|
||||
uTd3dctKLcZqE5sb6vrHH/GD1/TbEY0hCgcDQWBiO6hoq3KR8qK2+SvvZCmxr3H8
|
||||
zSB9dB99lRP1gfdPVyiwBr4=
|
||||
-----END PRIVATE KEY-----
|
||||
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
|
||||
334
infra/configs/authentik/bootstrap.yaml
Normal file
334
infra/configs/authentik/bootstrap.yaml
Normal file
@@ -0,0 +1,334 @@
|
||||
# FILE: blueprints/ai-tax-agent-bootstrap.yaml
|
||||
# Authentik Bootstrap (v2025.x): users, groups, scope mappings, OIDC providers, applications
|
||||
|
||||
version: 1
|
||||
|
||||
metadata:
|
||||
name: AI Tax Agent — Bootstrap + OIDC Providers
|
||||
|
||||
entries:
|
||||
# --- Groups first (so the admin user can reference them) -------------------
|
||||
- model: authentik_core.group
|
||||
state: present
|
||||
identifiers:
|
||||
name: "Administrators"
|
||||
attrs:
|
||||
is_superuser: true
|
||||
|
||||
- model: authentik_core.group
|
||||
state: present
|
||||
identifiers:
|
||||
name: "Tax Reviewers"
|
||||
attrs:
|
||||
is_superuser: false
|
||||
|
||||
- model: authentik_core.group
|
||||
state: present
|
||||
identifiers:
|
||||
name: "Accountants"
|
||||
attrs:
|
||||
is_superuser: false
|
||||
|
||||
- model: authentik_core.group
|
||||
state: present
|
||||
identifiers:
|
||||
name: "Clients"
|
||||
attrs:
|
||||
is_superuser: false
|
||||
|
||||
# --- Admin user ------------------------------------------------------------
|
||||
- model: authentik_core.user
|
||||
state: present
|
||||
identifiers:
|
||||
username: admin
|
||||
attrs:
|
||||
name: "System Administrator"
|
||||
email: admin@local.lan
|
||||
is_active: true
|
||||
is_staff: true
|
||||
is_superuser: true
|
||||
groups:
|
||||
- !Find [authentik_core.group, [name, "Administrators"]]
|
||||
|
||||
# --- Scope mappings (find existing ones and get stable IDs) -----------------
|
||||
- id: scope_openid
|
||||
model: authentik_providers_oauth2.scopemapping
|
||||
identifiers:
|
||||
scope_name: openid
|
||||
|
||||
- id: scope_profile
|
||||
model: authentik_providers_oauth2.scopemapping
|
||||
identifiers:
|
||||
scope_name: profile
|
||||
|
||||
- id: scope_email
|
||||
model: authentik_providers_oauth2.scopemapping
|
||||
identifiers:
|
||||
scope_name: email
|
||||
|
||||
- id: scope_groups
|
||||
model: authentik_providers_oauth2.scopemapping
|
||||
identifiers:
|
||||
scope_name: groups
|
||||
|
||||
- id: scope_offline
|
||||
model: authentik_providers_oauth2.scopemapping
|
||||
identifiers:
|
||||
scope_name: offline_access
|
||||
|
||||
# Helper finders
|
||||
- id: default_signing_key
|
||||
model: authentik_crypto.certificatekeypair
|
||||
state: present
|
||||
identifiers:
|
||||
name: "authentik Self-signed Certificate"
|
||||
|
||||
- id: default_authz_flow
|
||||
model: authentik_flows.flow
|
||||
state: present
|
||||
identifiers:
|
||||
slug: "default-authentication-flow"
|
||||
|
||||
- id: default_inval_flow
|
||||
model: authentik_flows.flow
|
||||
state: present
|
||||
identifiers:
|
||||
slug: "default-invalidation-flow"
|
||||
|
||||
# ========= OIDC Providers + Applications ==================================
|
||||
|
||||
# --- AI Tax Agent API ------------------------------------------------------
|
||||
- model: authentik_providers_oauth2.oauth2provider
|
||||
state: present
|
||||
identifiers:
|
||||
name: "AI Tax Agent API"
|
||||
attrs:
|
||||
client_id: "ai-tax-agent-api"
|
||||
client_secret: !Env [AUTHENTIK_API_CLIENT_SECRET, "changeme-api-secret"]
|
||||
authorization_grant_type: "authorization-code"
|
||||
client_type: "confidential"
|
||||
issuer_mode: "per_provider"
|
||||
sub_mode: "hashed_user_id"
|
||||
include_claims_in_id_token: true
|
||||
signing_key: !KeyOf default_signing_key
|
||||
redirect_uris:
|
||||
- matching_mode: strict
|
||||
url: "https://api.local.lan/auth/callback"
|
||||
- matching_mode: strict
|
||||
url: "https://review.local.lan/auth/callback"
|
||||
scope_mappings:
|
||||
- !KeyOf scope_openid
|
||||
- !KeyOf scope_profile
|
||||
- !KeyOf scope_email
|
||||
- !KeyOf scope_groups
|
||||
- !KeyOf scope_offline
|
||||
authorization_flow: !KeyOf default_authz_flow
|
||||
invalidation_flow: !KeyOf default_inval_flow
|
||||
|
||||
- model: authentik_core.application
|
||||
state: present
|
||||
identifiers:
|
||||
slug: "ai-tax-agent-api"
|
||||
attrs:
|
||||
name: "AI Tax Agent API"
|
||||
provider:
|
||||
!Find [
|
||||
authentik_providers_oauth2.oauth2provider,
|
||||
[name, "AI Tax Agent API"],
|
||||
]
|
||||
meta_launch_url: "https://api.local.lan"
|
||||
meta_description: "AI Tax Agent API Services"
|
||||
meta_publisher: "AI Tax Agent"
|
||||
policy_engine_mode: "any"
|
||||
|
||||
# --- MinIO -----------------------------------------------------------------
|
||||
- model: authentik_providers_oauth2.oauth2provider
|
||||
state: present
|
||||
identifiers:
|
||||
name: "MinIO"
|
||||
attrs:
|
||||
client_id: "minio"
|
||||
client_secret:
|
||||
!Env [AUTHENTIK_MINIO_CLIENT_SECRET, "changeme-minio-secret"]
|
||||
authorization_grant_type: "authorization-code"
|
||||
client_type: "confidential"
|
||||
issuer_mode: "per_provider"
|
||||
sub_mode: "hashed_user_id"
|
||||
include_claims_in_id_token: true
|
||||
signing_key: !KeyOf default_signing_key
|
||||
redirect_uris:
|
||||
- matching_mode: strict
|
||||
url: "https://minio.local.lan/oauth_callback"
|
||||
scope_mappings:
|
||||
- !KeyOf scope_openid
|
||||
- !KeyOf scope_profile
|
||||
- !KeyOf scope_email
|
||||
- !KeyOf scope_groups
|
||||
- !KeyOf scope_offline
|
||||
authorization_flow: !KeyOf default_authz_flow
|
||||
invalidation_flow: !KeyOf default_inval_flow
|
||||
|
||||
- model: authentik_core.application
|
||||
state: present
|
||||
identifiers:
|
||||
slug: "minio"
|
||||
attrs:
|
||||
name: "MinIO"
|
||||
provider:
|
||||
!Find [authentik_providers_oauth2.oauth2provider, [name, "MinIO"]]
|
||||
meta_launch_url: "https://minio.local.lan"
|
||||
meta_description: "Object storage console"
|
||||
meta_publisher: "AI Tax Agent"
|
||||
policy_engine_mode: "any"
|
||||
|
||||
# --- UI Review (Proxy Provider for ForwardAuth) ---------------------------
|
||||
- model: authentik_providers_proxy.proxyprovider
|
||||
state: present
|
||||
identifiers:
|
||||
name: "UI Review Proxy"
|
||||
attrs:
|
||||
external_host: "https://review.${DOMAIN:-local}"
|
||||
internal_host: "http://ui-review:3030"
|
||||
authorization_flow: !KeyOf default_authz_flow
|
||||
invalidation_flow: !KeyOf default_inval_flow
|
||||
mode: "forward_single"
|
||||
cookie_domain: "${DOMAIN:-local}"
|
||||
|
||||
- model: authentik_core.application
|
||||
state: present
|
||||
identifiers:
|
||||
slug: "ui-review"
|
||||
attrs:
|
||||
name: "UI Review"
|
||||
provider:
|
||||
!Find [
|
||||
authentik_providers_proxy.proxyprovider,
|
||||
[name, "UI Review Proxy"],
|
||||
]
|
||||
meta_launch_url: "https://review.${DOMAIN:-local}"
|
||||
meta_description: "Tax Agent Platform - Review UI"
|
||||
meta_publisher: "AI Tax Agent"
|
||||
policy_engine_mode: "any"
|
||||
|
||||
# --- Vault -----------------------------------------------------------------
|
||||
- model: authentik_providers_oauth2.oauth2provider
|
||||
state: present
|
||||
identifiers:
|
||||
name: "Vault"
|
||||
attrs:
|
||||
client_id: "vault"
|
||||
client_secret:
|
||||
!Env [AUTHENTIK_VAULT_CLIENT_SECRET, "changeme-vault-secret"]
|
||||
authorization_grant_type: "authorization-code"
|
||||
client_type: "confidential"
|
||||
issuer_mode: "per_provider"
|
||||
sub_mode: "hashed_user_id"
|
||||
include_claims_in_id_token: true
|
||||
signing_key: !KeyOf default_signing_key
|
||||
redirect_uris:
|
||||
- matching_mode: strict
|
||||
url: "https://vault.local.lan/ui/vault/auth/oidc/oidc/callback"
|
||||
- matching_mode: strict
|
||||
url: "https://vault.local.lan/oidc/callback"
|
||||
- matching_mode: strict
|
||||
url: "http://localhost:8250/oidc/callback"
|
||||
scope_mappings:
|
||||
- !KeyOf scope_openid
|
||||
- !KeyOf scope_profile
|
||||
- !KeyOf scope_email
|
||||
- !KeyOf scope_groups
|
||||
- !KeyOf scope_offline
|
||||
authorization_flow: !KeyOf default_authz_flow
|
||||
invalidation_flow: !KeyOf default_inval_flow
|
||||
|
||||
- model: authentik_core.application
|
||||
state: present
|
||||
identifiers:
|
||||
slug: "vault"
|
||||
attrs:
|
||||
name: "Vault"
|
||||
provider:
|
||||
!Find [authentik_providers_oauth2.oauth2provider, [name, "Vault"]]
|
||||
meta_launch_url: "https://vault.local.lan"
|
||||
meta_description: "Secrets management (Vault)"
|
||||
meta_publisher: "AI Tax Agent"
|
||||
policy_engine_mode: "any"
|
||||
|
||||
# --- Grafana SSO Configuration -------------------------------------------
|
||||
|
||||
# Custom Role Mapping for Grafana
|
||||
- model: authentik_providers_oauth2.scopemapping
|
||||
state: present
|
||||
identifiers:
|
||||
name: "Grafana Role Mapping"
|
||||
attrs:
|
||||
name: "Grafana Role Mapping"
|
||||
description: "Maps Authentik groups to Grafana roles"
|
||||
scope_name: "role"
|
||||
expression: |
|
||||
# Map Authentik groups to Grafana roles
|
||||
user_groups = [group.name for group in request.user.ak_groups.all()]
|
||||
|
||||
# Admin role mapping
|
||||
if "authentik Admins" in user_groups or "Administrators" in user_groups:
|
||||
return "Admin"
|
||||
|
||||
# Editor role mapping
|
||||
if "Tax Reviewers" in user_groups or "Accountants" in user_groups:
|
||||
return "Editor"
|
||||
|
||||
# Default to Viewer role
|
||||
return "Viewer"
|
||||
|
||||
# Grafana OAuth2 Provider
|
||||
- model: authentik_providers_oauth2.oauth2provider
|
||||
state: present
|
||||
identifiers:
|
||||
name: "Grafana"
|
||||
attrs:
|
||||
client_id: "grafana"
|
||||
client_secret: "${AUTHENTIK_GRAFANA_CLIENT_SECRET:-changeme-grafana-secret}"
|
||||
client_type: "confidential"
|
||||
redirect_uris: "https://grafana.${DOMAIN:-local.lan}/login/generic_oauth"
|
||||
sub_mode: "hashed_user_id"
|
||||
include_claims_in_id_token: true
|
||||
issuer_mode: "per_provider"
|
||||
signing_key:
|
||||
!Find [
|
||||
authentik_crypto.certificatekeypair,
|
||||
[name, "authentik Self-signed Certificate"],
|
||||
]
|
||||
property_mappings:
|
||||
- !Find [
|
||||
authentik_providers_oauth2.scopemapping,
|
||||
[scope_name, "openid"],
|
||||
]
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, "email"]]
|
||||
- !Find [
|
||||
authentik_providers_oauth2.scopemapping,
|
||||
[scope_name, "profile"],
|
||||
]
|
||||
- !Find [
|
||||
authentik_providers_oauth2.scopemapping,
|
||||
[scope_name, "groups"],
|
||||
]
|
||||
- !Find [
|
||||
authentik_providers_oauth2.scopemapping,
|
||||
[name, "Grafana Role Mapping"],
|
||||
]
|
||||
authorization_flow: !KeyOf default_authz_flow
|
||||
invalidation_flow: !KeyOf default_inval_flow
|
||||
|
||||
# Grafana Application
|
||||
- model: authentik_core.application
|
||||
state: present
|
||||
identifiers:
|
||||
slug: "grafana"
|
||||
attrs:
|
||||
name: "Grafana"
|
||||
provider:
|
||||
!Find [authentik_providers_oauth2.oauth2provider, [name, "Grafana"]]
|
||||
meta_launch_url: "https://grafana.${DOMAIN:-local.lan}"
|
||||
meta_description: "Grafana monitoring and observability platform"
|
||||
meta_publisher: "Grafana Labs"
|
||||
policy_engine_mode: "any"
|
||||
61
infra/configs/loki/loki-config.yml
Normal file
61
infra/configs/loki/loki-config.yml
Normal file
@@ -0,0 +1,61 @@
|
||||
auth_enabled: false
|
||||
|
||||
server:
|
||||
http_listen_port: 3100
|
||||
grpc_listen_port: 9096
|
||||
|
||||
common:
|
||||
path_prefix: /loki
|
||||
storage:
|
||||
filesystem:
|
||||
chunks_directory: /loki/chunks
|
||||
rules_directory: /loki/rules
|
||||
replication_factor: 1
|
||||
ring:
|
||||
instance_addr: 127.0.0.1
|
||||
kvstore:
|
||||
store: inmemory
|
||||
|
||||
query_range:
|
||||
results_cache:
|
||||
cache:
|
||||
embedded_cache:
|
||||
enabled: true
|
||||
max_size_mb: 100
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2020-10-24
|
||||
store: boltdb-shipper
|
||||
object_store: filesystem
|
||||
schema: v11
|
||||
index:
|
||||
prefix: index_
|
||||
period: 24h
|
||||
|
||||
ruler:
|
||||
alertmanager_url: http://localhost:9093
|
||||
|
||||
# Retention configuration
|
||||
limits_config:
|
||||
retention_period: 744h # 31 days
|
||||
enforce_metric_name: false
|
||||
reject_old_samples: true
|
||||
reject_old_samples_max_age: 168h
|
||||
ingestion_rate_mb: 10
|
||||
ingestion_burst_size_mb: 20
|
||||
|
||||
# Compactor for retention
|
||||
compactor:
|
||||
working_directory: /loki/compactor
|
||||
shared_store: filesystem
|
||||
compaction_interval: 10m
|
||||
retention_enabled: true
|
||||
retention_delete_delay: 2h
|
||||
retention_delete_worker_count: 150
|
||||
|
||||
# Table manager for retention
|
||||
table_manager:
|
||||
retention_deletes_enabled: true
|
||||
retention_period: 744h
|
||||
|
||||
49
infra/configs/promtail/promtail-config.yml
Normal file
49
infra/configs/promtail/promtail-config.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
server:
|
||||
http_listen_port: 9080
|
||||
grpc_listen_port: 0
|
||||
|
||||
positions:
|
||||
filename: /tmp/positions.yaml
|
||||
|
||||
clients:
|
||||
- url: http://loki:3100/loki/api/v1/push
|
||||
|
||||
scrape_configs:
|
||||
# Docker container logs
|
||||
- job_name: docker
|
||||
docker_sd_configs:
|
||||
- host: unix:///var/run/docker.sock
|
||||
refresh_interval: 5s
|
||||
filters:
|
||||
- name: label
|
||||
values: ["logging=promtail"]
|
||||
relabel_configs:
|
||||
- source_labels: ['__meta_docker_container_name']
|
||||
regex: '/(.*)'
|
||||
target_label: 'container'
|
||||
- source_labels: ['__meta_docker_container_log_stream']
|
||||
target_label: 'logstream'
|
||||
- source_labels: ['__meta_docker_container_label_com_docker_compose_project']
|
||||
target_label: 'project'
|
||||
- source_labels: ['__meta_docker_container_label_com_docker_compose_service']
|
||||
target_label: 'service'
|
||||
|
||||
# System logs (optional)
|
||||
- job_name: system
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: varlogs
|
||||
__path__: /var/log/*log
|
||||
|
||||
# Application-specific logs
|
||||
- job_name: ai-tax-agent
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: ai-tax-agent
|
||||
environment: production
|
||||
__path__: /var/log/ai-tax-agent/*.log
|
||||
|
||||
31
infra/configs/traefik/app-middlewares.yml
Normal file
31
infra/configs/traefik/app-middlewares.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
# Application-specific Traefik middlewares
|
||||
# These are loaded by the application infrastructure, not the external Traefik
|
||||
|
||||
http:
|
||||
middlewares:
|
||||
# Large upload middleware for Gitea registry
|
||||
gitea-large-upload:
|
||||
buffering:
|
||||
maxRequestBodyBytes: 5368709120 # 5GB
|
||||
memRequestBodyBytes: 104857600 # 100MB
|
||||
maxResponseBodyBytes: 5368709120 # 5GB
|
||||
memResponseBodyBytes: 104857600 # 100MB
|
||||
retryExpression: "IsNetworkError() && Attempts() < 3"
|
||||
|
||||
# Rate limiting for public APIs
|
||||
api-ratelimit:
|
||||
rateLimit:
|
||||
average: 100
|
||||
burst: 50
|
||||
period: 1s
|
||||
|
||||
# Security headers
|
||||
security-headers:
|
||||
headers:
|
||||
frameDeny: true
|
||||
sslRedirect: true
|
||||
browserXssFilter: true
|
||||
contentTypeNosniff: true
|
||||
stsIncludeSubdomains: true
|
||||
stsPreload: true
|
||||
stsSeconds: 31536000
|
||||
0
infra/configs/traefik/certs/acme.json
Normal file
0
infra/configs/traefik/certs/acme.json
Normal file
25
infra/configs/traefik/certs/local.crt
Normal file
25
infra/configs/traefik/certs/local.crt
Normal file
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEHjCCAwagAwIBAgIUbOm5g4Xhb08Lk6DIpVst7+xZHOswDQYJKoZIhvcNAQEL
|
||||
BQAwEDEOMAwGA1UEAwwFbG9jYWwwHhcNMjUwOTI4MTExNTM1WhcNMzUwOTI2MTEx
|
||||
NTM1WjAQMQ4wDAYDVQQDDAVsb2NhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAK0370DEo3dScS8uLwBsXkuaAHn9wO2fjxEHLZwHWfFo/16t+EEAi5c3
|
||||
zDs7nYQ7LPLndxBfO6xZ5uWKNIVtp6ARzAeRbGgbjXDdK3fOyRdhhKR3aZVOH1D0
|
||||
xUjEm/X5jEDv81sufSjk+DIQmh8hQnp3RwdHyhkIZUCTsBXMfnj+zs1UKTdRQBF5
|
||||
SUplGsbh6z3xCSI4jiNRb7mNHXqV3Fv6ycwF8YdthSDfueltBP4vT/CDtebkkKPF
|
||||
dx7YWEIPPUNqEoHqeI5iYP6gnWJYcr3vU+p2BuTwUICo+njzAf+P/SsjPHbujJob
|
||||
dbHUclBHIrIO4BpYZtY1a7E219MbqcECAwEAAaOCAW4wggFqMB0GA1UdDgQWBBQ7
|
||||
qHpza0Bb1xI1g7cMBx33JnFQljAfBgNVHSMEGDAWgBQ7qHpza0Bb1xI1g7cMBx33
|
||||
JnFQljAPBgNVHRMBAf8EBTADAQH/MIIBFQYDVR0RBIIBDDCCAQiCCWxvY2FsaG9z
|
||||
dIcEfwAAAYILKi5sb2NhbC5sYW6CDmF1dGgubG9jYWwubGFughFncmFmYW5hLmxv
|
||||
Y2FsLmxhboIQcmV2aWV3LmxvY2FsLmxhboINYXBpLmxvY2FsLmxhboIPdmF1bHQu
|
||||
bG9jYWwubGFugg9taW5pby5sb2NhbC5sYW6CE21pbmlvLWFwaS5sb2NhbC5sYW6C
|
||||
EHFkcmFudC5sb2NhbC5sYW6CD25lbzRqLmxvY2FsLmxhboIUcHJvbWV0aGV1cy5s
|
||||
b2NhbC5sYW6CDmxva2kubG9jYWwubGFughF1bmxlYXNoLmxvY2FsLmxhboIRdHJh
|
||||
ZWZpay5sb2NhbC5sYW4wDQYJKoZIhvcNAQELBQADggEBAICf+2MZ7BHbSD/pnvll
|
||||
G7Zmk+Bntj2F6RBQVZ2ZsKPWkHeZEYJDRvU0I2uL5tvvDJp4q0hjdluJllchhGgr
|
||||
qfu7i+kRnhzme7oyRTFGYp8b3zHBvLyJLmdIALxuNSjIEeh1Fx0lEhKwqOlA4y6T
|
||||
jziPmsGv3IonGJM2dURGNcR7DfG6H/Yl12qV8u/tVFTxqWL+hyCE7u8v+ZIcZ+fj
|
||||
82X7hXt1HvfP84EhVtfqQMb5xykLtXvPqggSCFXYIj2PanWdwEdE6P5Yr2D1Yz7r
|
||||
tzpmpoetrGoMWIeB0yiWgt0qJ/KK7meoCp64mqfBc48p1p/7kj2R/FRH1Jx3gFWy
|
||||
dT4=
|
||||
-----END CERTIFICATE-----
|
||||
28
infra/configs/traefik/certs/local.key
Normal file
28
infra/configs/traefik/certs/local.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCtN+9AxKN3UnEv
|
||||
Li8AbF5LmgB5/cDtn48RBy2cB1nxaP9erfhBAIuXN8w7O52EOyzy53cQXzusWebl
|
||||
ijSFbaegEcwHkWxoG41w3St3zskXYYSkd2mVTh9Q9MVIxJv1+YxA7/NbLn0o5Pgy
|
||||
EJofIUJ6d0cHR8oZCGVAk7AVzH54/s7NVCk3UUAReUlKZRrG4es98QkiOI4jUW+5
|
||||
jR16ldxb+snMBfGHbYUg37npbQT+L0/wg7Xm5JCjxXce2FhCDz1DahKB6niOYmD+
|
||||
oJ1iWHK971Pqdgbk8FCAqPp48wH/j/0rIzx27oyaG3Wx1HJQRyKyDuAaWGbWNWux
|
||||
NtfTG6nBAgMBAAECggEAHvtkNcd2HX+HcxLloUPA0fDnqOo0OcxSQI9yHvhJpB5N
|
||||
nterEaVRUmjOhMGy+NXEwmWYLDt8ZuVloSTJJBxq4PyN68SdCTn0YH2Oqs03tpDg
|
||||
srIRFn10qHw/VTalVqed6HeCpYp5JHlf00SY7Hx8cX8oGytCAJw50AUad6ut62IM
|
||||
sp/QFdtkLhtq9vGzQUqyIP92Y/+GbxhB+eHkuvvFau1KJq7K8qhroFTwQFts9er2
|
||||
890Ujmz3bF2RhHixQcpXpsf/DMyylGJTbZDmSFkTDa/c1PzqvKrmL3wP7A3bk1E5
|
||||
CP8/a65ykotJEX8RkWqH2XxvRKpdWtCaeuCsmWUQ4QKBgQDTLbC9DWHCUYMWJhyW
|
||||
TKAeXx5xFGHIqggN28lIkXFiCVsTZyOuRDN7Q/CbOat/0JthrzyP18L+6ewZt2ZN
|
||||
RjdfGdnpUCJx6LR4dtBH8Rc+CjlSnqEgJIkgfIs8b9uEhMI1eQV+BAFQON3BzdpT
|
||||
wQ86aGsrdqtpfav7cImVfGcY/QKBgQDR+7OcnEwh8s/1J2niMKjk8agyCGGHWW4M
|
||||
g+vIv7lptavgEGOPMBv7QgmeuUjwSszphQXL36m39ZRmI5B+J0/onuQzv04tJeZY
|
||||
WZhA+T12a+1VnvUZNZm/qp0I2rW+4m+DmJoLQlvpaaFit/1fPJ6+IzI2VzPeWhw2
|
||||
vUQ5QIYhFQKBgFUWZc3mpGsNOMol1QLiIOnb3YImejfF+rTKx9FLeOnNZzrsJb5D
|
||||
kJKsDzgcBnPbc5/qYXZ7sv/O9OhvsvKTxh+1ZM3TEe3fm0emZ8l05K6EpBAcBkPT
|
||||
NMU4KUnSsBo2+6Fb/9CEgJr4LrG15bA1a5NXG0dJ60r37eHDuEvY8hlpAoGADWv2
|
||||
PhNrdlwL2NKtHO0ZTpD3vEL24OzhcOFZx9ohYtVe6BKEGpnrn/LHpKKZO+q8EE0V
|
||||
YsOoGH8U/jZVvQqMPAUz9u7Kc25Ru+H2Lmj/+brKT8e6SOM5MZwZL4CzT0Ev+Yxe
|
||||
hEu4jkHXM/Uot9arGuIrCngmc5b06LbOTo6GREUCgYArWyPYeETah/GVwU7/TNY5
|
||||
5f8lNbWBoXZfpVbWdoUZT6tGWciZsiXSR4x9f+1/LMIuChegSEazrJUDt7TbCkZs
|
||||
s4A66pnME37aYP2sMvJF3zSnQWVIyBgGI5xX0XW/WdozKl1mdFfigyWp58uo2dS2
|
||||
TxE3dy8rxpUdDCUmvJT/Fw==
|
||||
-----END PRIVATE KEY-----
|
||||
47
infra/docker/Dockerfile.ml-service.template
Normal file
47
infra/docker/Dockerfile.ml-service.template
Normal file
@@ -0,0 +1,47 @@
|
||||
# Template Dockerfile for ML Services
|
||||
# This uses the pre-built base-ml image which contains all heavy ML dependencies
|
||||
# Only the application code is added on top (~50MB vs 1.2GB)
|
||||
#
|
||||
# Usage: Copy this template to apps/svc_*/Dockerfile and replace SERVICE_NAME
|
||||
|
||||
# Use the pre-built ML base image
|
||||
ARG REGISTRY=gitea.harkon.co.uk
|
||||
ARG OWNER=harkon
|
||||
ARG BASE_VERSION=v1.0.1
|
||||
FROM ${REGISTRY}/${OWNER}/base-ml:${BASE_VERSION}
|
||||
|
||||
# Switch to root to install service-specific dependencies
|
||||
USER root
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy service-specific requirements (if any additional deps needed)
|
||||
# Most ML deps are already in base-ml, so this should be minimal
|
||||
COPY apps/SERVICE_NAME/requirements.txt /tmp/service-requirements.txt
|
||||
|
||||
# Install any service-specific dependencies (should be very few)
|
||||
RUN if [ -s /tmp/service-requirements.txt ]; then \
|
||||
pip install --no-cache-dir -r /tmp/service-requirements.txt; \
|
||||
fi
|
||||
|
||||
# Copy application code
|
||||
COPY libs/ ./libs/
|
||||
COPY apps/SERVICE_NAME/ ./apps/SERVICE_NAME/
|
||||
|
||||
# Set permissions
|
||||
RUN chown -R appuser:appuser /app
|
||||
|
||||
# Switch back to non-root user
|
||||
USER appuser
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8000/healthz || exit 1
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
# Run the application
|
||||
CMD ["python", "-m", "uvicorn", "apps.SERVICE_NAME.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
|
||||
58
infra/docker/base-ml.Dockerfile
Normal file
58
infra/docker/base-ml.Dockerfile
Normal file
@@ -0,0 +1,58 @@
|
||||
# Base ML Image - Contains all heavy ML dependencies
|
||||
# This image is built once and reused by all ML services (svc-ocr, svc-rag-indexer, svc-rag-retriever)
|
||||
#
|
||||
# Build: docker build -t gitea.harkon.co.uk/harkon/base-ml:v1.0.1 -f infra/docker/base-ml.Dockerfile .
|
||||
# Push: docker push gitea.harkon.co.uk/harkon/base-ml:v1.0.1
|
||||
|
||||
FROM python:3.12-slim as builder
|
||||
|
||||
# Install build dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
curl \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create virtual environment
|
||||
RUN python -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
# Copy requirements files
|
||||
COPY libs/requirements-base.txt /tmp/requirements-base.txt
|
||||
COPY libs/requirements-ml.txt /tmp/requirements-ml.txt
|
||||
|
||||
# Install all dependencies (base + ML)
|
||||
RUN pip install --no-cache-dir --upgrade pip && \
|
||||
pip install --no-cache-dir -r /tmp/requirements-base.txt && \
|
||||
pip install --no-cache-dir -r /tmp/requirements-ml.txt
|
||||
|
||||
# Final stage - Runtime image
|
||||
FROM python:3.12-slim
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& groupadd -r appuser \
|
||||
&& useradd -r -g appuser appuser
|
||||
|
||||
# Copy virtual environment from builder
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
|
||||
# Set environment variables
|
||||
ENV PATH="/opt/venv/bin:$PATH" \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD python -c "import sentence_transformers; import transformers; print('ML base image healthy')"
|
||||
|
||||
# Default user
|
||||
USER appuser
|
||||
|
||||
# Label
|
||||
LABEL maintainer="AI Tax Agent Team" \
|
||||
description="Base ML image with sentence-transformers, PyTorch, and ML dependencies" \
|
||||
version="1.0.1"
|
||||
|
||||
55
infra/docker/base-runtime.Dockerfile
Normal file
55
infra/docker/base-runtime.Dockerfile
Normal file
@@ -0,0 +1,55 @@
|
||||
# Base Runtime Image - Contains core dependencies for ALL services
|
||||
# This image is built once and reused by all non-ML services
|
||||
#
|
||||
# Build: docker build -t gitea.harkon.co.uk/harkon/base-runtime:v1.0.1 -f infra/docker/base-runtime.Dockerfile .
|
||||
# Push: docker push gitea.harkon.co.uk/harkon/base-runtime:v1.0.1
|
||||
|
||||
FROM python:3.12-slim as builder
|
||||
|
||||
# Install build dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create virtual environment
|
||||
RUN python -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
# Copy requirements file
|
||||
COPY libs/requirements-base.txt /tmp/requirements-base.txt
|
||||
|
||||
# Install base dependencies
|
||||
RUN pip install --no-cache-dir --upgrade pip && \
|
||||
pip install --no-cache-dir -r /tmp/requirements-base.txt
|
||||
|
||||
# Final stage - Runtime image
|
||||
FROM python:3.12-slim
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& groupadd -r appuser \
|
||||
&& useradd -r -g appuser appuser
|
||||
|
||||
# Copy virtual environment from builder
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
|
||||
# Set environment variables
|
||||
ENV PATH="/opt/venv/bin:$PATH" \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD python -c "import fastapi; import uvicorn; print('Base runtime image healthy')"
|
||||
|
||||
# Default user
|
||||
USER appuser
|
||||
|
||||
# Label
|
||||
LABEL maintainer="AI Tax Agent Team" \
|
||||
description="Base runtime image with FastAPI, database drivers, and core dependencies" \
|
||||
version="1.0.1"
|
||||
|
||||
74
infra/environments/development/.env.example
Normal file
74
infra/environments/development/.env.example
Normal file
@@ -0,0 +1,74 @@
|
||||
# FILE: infra/environments/development/.env.example
|
||||
# Development Environment Configuration
|
||||
# Copy this to .env and customize for your development server
|
||||
# WARNING: This file contains sensitive credentials. DO NOT commit to git!
|
||||
|
||||
# Domain Configuration
|
||||
DOMAIN=dev.harkon.co.uk
|
||||
EMAIL=dev@harkon.co.uk
|
||||
|
||||
# Database Passwords (CHANGE THESE!)
|
||||
POSTGRES_PASSWORD=CHANGE_ME_POSTGRES_PASSWORD
|
||||
NEO4J_PASSWORD=CHANGE_ME_NEO4J_PASSWORD
|
||||
AUTHENTIK_DB_PASSWORD=CHANGE_ME_AUTHENTIK_DB_PASSWORD
|
||||
|
||||
# Object Storage (CHANGE THESE!)
|
||||
MINIO_ROOT_USER=admin
|
||||
MINIO_ROOT_PASSWORD=CHANGE_ME_MINIO_ROOT_PASSWORD
|
||||
MINIO_ACCESS_KEY=admin
|
||||
MINIO_SECRET_KEY=CHANGE_ME_MINIO_SECRET_KEY
|
||||
|
||||
# Vector Database
|
||||
QDRANT__SERVICE__GRPC_PORT=6334
|
||||
|
||||
# Secrets Management (CHANGE THIS!)
|
||||
VAULT_DEV_ROOT_TOKEN_ID=CHANGE_ME_VAULT_TOKEN
|
||||
|
||||
# Identity & SSO (CHANGE THESE!)
|
||||
# Generate with: openssl rand -base64 32
|
||||
AUTHENTIK_SECRET_KEY=CHANGE_ME_AUTHENTIK_SECRET
|
||||
AUTHENTIK_OUTPOST_TOKEN=CHANGE_ME_OUTPOST_TOKEN
|
||||
AUTHENTIK_BOOTSTRAP_EMAIL=admin@dev.harkon.co.uk
|
||||
AUTHENTIK_BOOTSTRAP_PASSWORD=CHANGE_ME_ADMIN_PASSWORD
|
||||
AUTHENTIK_BOOTSTRAP_TOKEN=
|
||||
|
||||
# Monitoring (CHANGE THIS!)
|
||||
GRAFANA_PASSWORD=CHANGE_ME_GRAFANA_PASSWORD
|
||||
GRAFANA_OAUTH_CLIENT_ID=grafana
|
||||
GRAFANA_OAUTH_CLIENT_SECRET=CHANGE_ME_GRAFANA_OAUTH_SECRET
|
||||
|
||||
# OAuth Client Secrets for Authentik Providers (CHANGE THESE!)
|
||||
AUTHENTIK_API_CLIENT_SECRET=CHANGE_ME_API_SECRET
|
||||
AUTHENTIK_UI_REVIEW_CLIENT_SECRET=CHANGE_ME_UI_SECRET
|
||||
AUTHENTIK_GRAFANA_CLIENT_SECRET=CHANGE_ME_GRAFANA_SECRET
|
||||
AUTHENTIK_MINIO_CLIENT_SECRET=CHANGE_ME_MINIO_SECRET
|
||||
AUTHENTIK_VAULT_CLIENT_SECRET=CHANGE_ME_VAULT_SECRET
|
||||
|
||||
# Feature Flags
|
||||
UNLEASH_ADMIN_TOKEN=development.unleash-admin-api-token
|
||||
|
||||
# Application Configuration (CHANGE THIS!)
|
||||
NEXTAUTH_SECRET=CHANGE_ME_NEXTAUTH_SECRET
|
||||
|
||||
# Redis Configuration
|
||||
REDIS_PASSWORD=CHANGE_ME_REDIS_PASSWORD
|
||||
|
||||
# NATS Configuration
|
||||
NATS_USER=nats
|
||||
NATS_PASSWORD=CHANGE_ME_NATS_PASSWORD
|
||||
|
||||
# Application Secrets
|
||||
JWT_SECRET=CHANGE_ME_JWT_SECRET_32_CHARS_MIN
|
||||
ENCRYPTION_KEY=CHANGE_ME_ENCRYPTION_KEY_32_CHARS
|
||||
|
||||
# API Keys (for development testing)
|
||||
OPENAI_API_KEY=sk-your-openai-key
|
||||
ANTHROPIC_API_KEY=sk-ant-your-anthropic-key
|
||||
|
||||
# Registry Configuration
|
||||
REGISTRY=gitea.dev.harkon.co.uk
|
||||
REGISTRY_USER=harkon
|
||||
REGISTRY_PASSWORD=CHANGE_ME_GITEA_TOKEN
|
||||
IMAGE_TAG=dev
|
||||
OWNER=harkon
|
||||
|
||||
72
infra/environments/local/.env.example
Normal file
72
infra/environments/local/.env.example
Normal file
@@ -0,0 +1,72 @@
|
||||
# FILE: infra/environments/local/.env.example
|
||||
# Local Development Environment Configuration
|
||||
# Copy this to .env and customize for your local setup
|
||||
|
||||
# Domain Configuration
|
||||
DOMAIN=localhost
|
||||
EMAIL=dev@localhost
|
||||
|
||||
# Database Passwords (use simple passwords for local)
|
||||
POSTGRES_PASSWORD=postgres
|
||||
NEO4J_PASSWORD=neo4j123
|
||||
AUTHENTIK_DB_PASSWORD=authentik123
|
||||
|
||||
# Object Storage
|
||||
MINIO_ROOT_USER=minioadmin
|
||||
MINIO_ROOT_PASSWORD=minioadmin
|
||||
MINIO_ACCESS_KEY=minioadmin
|
||||
MINIO_SECRET_KEY=minioadmin123
|
||||
|
||||
# Vector Database
|
||||
QDRANT__SERVICE__GRPC_PORT=6334
|
||||
|
||||
# Secrets Management
|
||||
VAULT_DEV_ROOT_TOKEN_ID=dev-root-token
|
||||
|
||||
# Identity & SSO (optional for local)
|
||||
AUTHENTIK_SECRET_KEY=local-secret-key-change-me
|
||||
AUTHENTIK_OUTPOST_TOKEN=local-outpost-token
|
||||
AUTHENTIK_BOOTSTRAP_EMAIL=admin@localhost
|
||||
AUTHENTIK_BOOTSTRAP_PASSWORD=admin123
|
||||
AUTHENTIK_BOOTSTRAP_TOKEN=
|
||||
|
||||
# Monitoring
|
||||
GRAFANA_PASSWORD=admin
|
||||
GRAFANA_OAUTH_CLIENT_ID=grafana
|
||||
GRAFANA_OAUTH_CLIENT_SECRET=grafana-secret
|
||||
|
||||
# OAuth Client Secrets (not needed for local without Authentik)
|
||||
AUTHENTIK_API_CLIENT_SECRET=api-secret
|
||||
AUTHENTIK_UI_REVIEW_CLIENT_SECRET=ui-secret
|
||||
AUTHENTIK_GRAFANA_CLIENT_SECRET=grafana-secret
|
||||
AUTHENTIK_MINIO_CLIENT_SECRET=minio-secret
|
||||
AUTHENTIK_VAULT_CLIENT_SECRET=vault-secret
|
||||
|
||||
# Feature Flags
|
||||
UNLEASH_ADMIN_TOKEN=local-unleash-token
|
||||
|
||||
# Application Configuration
|
||||
NEXTAUTH_SECRET=local-nextauth-secret
|
||||
|
||||
# Redis Configuration
|
||||
REDIS_PASSWORD=redis123
|
||||
|
||||
# NATS Configuration
|
||||
NATS_USER=nats
|
||||
NATS_PASSWORD=nats123
|
||||
|
||||
# Application Secrets
|
||||
JWT_SECRET=local-jwt-secret-change-me
|
||||
ENCRYPTION_KEY=local-encryption-key-32-chars!!
|
||||
|
||||
# API Keys (for local testing)
|
||||
OPENAI_API_KEY=sk-test-key
|
||||
ANTHROPIC_API_KEY=sk-ant-test-key
|
||||
|
||||
# Registry Configuration
|
||||
REGISTRY=localhost:5000
|
||||
REGISTRY_USER=admin
|
||||
REGISTRY_PASSWORD=admin123
|
||||
IMAGE_TAG=latest
|
||||
OWNER=local
|
||||
|
||||
74
infra/environments/production/.env.example
Normal file
74
infra/environments/production/.env.example
Normal file
@@ -0,0 +1,74 @@
|
||||
# FILE: infra/environments/production/.env.example
|
||||
# Production Environment Configuration
|
||||
# Copy this to .env and customize for your production server
|
||||
# WARNING: This file contains sensitive credentials. DO NOT commit to git!
|
||||
|
||||
# Domain Configuration
|
||||
DOMAIN=harkon.co.uk
|
||||
EMAIL=info@harkon.co.uk
|
||||
|
||||
# Database Passwords (CHANGE THESE!)
|
||||
POSTGRES_PASSWORD=CHANGE_ME_POSTGRES_PASSWORD
|
||||
NEO4J_PASSWORD=CHANGE_ME_NEO4J_PASSWORD
|
||||
AUTHENTIK_DB_PASSWORD=CHANGE_ME_AUTHENTIK_DB_PASSWORD
|
||||
|
||||
# Object Storage (CHANGE THESE!)
|
||||
MINIO_ROOT_USER=admin
|
||||
MINIO_ROOT_PASSWORD=CHANGE_ME_MINIO_ROOT_PASSWORD
|
||||
MINIO_ACCESS_KEY=admin
|
||||
MINIO_SECRET_KEY=CHANGE_ME_MINIO_SECRET_KEY
|
||||
|
||||
# Vector Database
|
||||
QDRANT__SERVICE__GRPC_PORT=6334
|
||||
|
||||
# Secrets Management (CHANGE THIS!)
|
||||
VAULT_DEV_ROOT_TOKEN_ID=CHANGE_ME_VAULT_TOKEN
|
||||
|
||||
# Identity & SSO (CHANGE THESE!)
|
||||
# Generate with: openssl rand -base64 32
|
||||
AUTHENTIK_SECRET_KEY=CHANGE_ME_AUTHENTIK_SECRET
|
||||
AUTHENTIK_OUTPOST_TOKEN=CHANGE_ME_OUTPOST_TOKEN
|
||||
AUTHENTIK_BOOTSTRAP_EMAIL=admin@harkon.co.uk
|
||||
AUTHENTIK_BOOTSTRAP_PASSWORD=CHANGE_ME_ADMIN_PASSWORD
|
||||
AUTHENTIK_BOOTSTRAP_TOKEN=
|
||||
|
||||
# Monitoring (CHANGE THIS!)
|
||||
GRAFANA_PASSWORD=CHANGE_ME_GRAFANA_PASSWORD
|
||||
GRAFANA_OAUTH_CLIENT_ID=grafana
|
||||
GRAFANA_OAUTH_CLIENT_SECRET=CHANGE_ME_GRAFANA_OAUTH_SECRET
|
||||
|
||||
# OAuth Client Secrets for Authentik Providers (CHANGE THESE!)
|
||||
AUTHENTIK_API_CLIENT_SECRET=CHANGE_ME_API_SECRET
|
||||
AUTHENTIK_UI_REVIEW_CLIENT_SECRET=CHANGE_ME_UI_SECRET
|
||||
AUTHENTIK_GRAFANA_CLIENT_SECRET=CHANGE_ME_GRAFANA_SECRET
|
||||
AUTHENTIK_MINIO_CLIENT_SECRET=CHANGE_ME_MINIO_SECRET
|
||||
AUTHENTIK_VAULT_CLIENT_SECRET=CHANGE_ME_VAULT_SECRET
|
||||
|
||||
# Feature Flags
|
||||
UNLEASH_ADMIN_TOKEN=production.unleash-admin-api-token
|
||||
|
||||
# Application Configuration (CHANGE THIS!)
|
||||
NEXTAUTH_SECRET=CHANGE_ME_NEXTAUTH_SECRET
|
||||
|
||||
# Redis Configuration
|
||||
REDIS_PASSWORD=CHANGE_ME_REDIS_PASSWORD
|
||||
|
||||
# NATS Configuration
|
||||
NATS_USER=nats
|
||||
NATS_PASSWORD=CHANGE_ME_NATS_PASSWORD
|
||||
|
||||
# Application Secrets
|
||||
JWT_SECRET=CHANGE_ME_JWT_SECRET_32_CHARS_MIN
|
||||
ENCRYPTION_KEY=CHANGE_ME_ENCRYPTION_KEY_32_CHARS
|
||||
|
||||
# API Keys
|
||||
OPENAI_API_KEY=sk-your-production-openai-key
|
||||
ANTHROPIC_API_KEY=sk-ant-your-production-anthropic-key
|
||||
|
||||
# Registry Configuration
|
||||
REGISTRY=gitea.harkon.co.uk
|
||||
REGISTRY_USER=harkon
|
||||
REGISTRY_PASSWORD=CHANGE_ME_GITEA_TOKEN
|
||||
IMAGE_TAG=v1.0.1
|
||||
OWNER=harkon
|
||||
|
||||
BIN
infra/neo4j/plugins/apoc.jar
Executable file
BIN
infra/neo4j/plugins/apoc.jar
Executable file
Binary file not shown.
BIN
infra/neo4j/plugins/graph-data-science.jar
Normal file
BIN
infra/neo4j/plugins/graph-data-science.jar
Normal file
Binary file not shown.
241
infra/scripts/deploy.sh
Executable file
241
infra/scripts/deploy.sh
Executable file
@@ -0,0 +1,241 @@
|
||||
#!/bin/bash
|
||||
|
||||
# AI Tax Agent Infrastructure Deployment Script
|
||||
# Supports multiple environments: local, development, production
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
# Script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
INFRA_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
PROJECT_ROOT="$(dirname "$INFRA_DIR")"
|
||||
|
||||
# Usage
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $0 <environment> <stack> [options]
|
||||
|
||||
Environments:
|
||||
local - Local development (localhost)
|
||||
development - Development server (dev.harkon.co.uk)
|
||||
production - Production server (harkon.co.uk)
|
||||
|
||||
Stacks:
|
||||
all - Deploy all stacks
|
||||
infrastructure - Core infrastructure (Vault, MinIO, DBs, Redis, NATS)
|
||||
monitoring - Monitoring stack (Prometheus, Grafana, Loki)
|
||||
services - Application services
|
||||
external - External services (Traefik, Authentik, Gitea)
|
||||
down - Stop and remove all stacks
|
||||
|
||||
Options:
|
||||
--build - Build images before deploying
|
||||
--pull - Pull images before deploying
|
||||
--force - Force recreate containers
|
||||
|
||||
Examples:
|
||||
$0 local all
|
||||
$0 production infrastructure
|
||||
$0 development services --build
|
||||
$0 production down
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check arguments
|
||||
if [ $# -lt 2 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
ENVIRONMENT=$1
|
||||
STACK=$2
|
||||
shift 2
|
||||
|
||||
# Validate environment
|
||||
case $ENVIRONMENT in
|
||||
local|development|production)
|
||||
;;
|
||||
*)
|
||||
log_error "Invalid environment: $ENVIRONMENT"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
# Paths
|
||||
ENV_FILE="$INFRA_DIR/environments/$ENVIRONMENT/.env"
|
||||
BASE_DIR="$INFRA_DIR/base"
|
||||
|
||||
# Check if environment file exists
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
log_error "Environment file not found: $ENV_FILE"
|
||||
log_info "Copy from template: cp $INFRA_DIR/environments/$ENVIRONMENT/.env.example $ENV_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Load environment variables
|
||||
set -a
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
|
||||
log_info "Deploying AI Tax Agent Infrastructure"
|
||||
echo " Environment: $ENVIRONMENT"
|
||||
echo " Stack: $STACK"
|
||||
echo " Env File: $ENV_FILE"
|
||||
echo ""
|
||||
|
||||
# Docker Compose command builder
|
||||
compose_cmd() {
|
||||
local file=$1
|
||||
shift
|
||||
docker compose -f "$BASE_DIR/$file" --env-file "$ENV_FILE" --project-name "ai-tax-agent-$ENVIRONMENT" "$@"
|
||||
}
|
||||
|
||||
# Deploy infrastructure stack
|
||||
deploy_infrastructure() {
|
||||
log_info "Deploying infrastructure stack..."
|
||||
compose_cmd "infrastructure.yaml" up -d "$@"
|
||||
log_success "Infrastructure stack deployed"
|
||||
}
|
||||
|
||||
# Deploy monitoring stack
|
||||
deploy_monitoring() {
|
||||
log_info "Deploying monitoring stack..."
|
||||
compose_cmd "monitoring.yaml" up -d "$@"
|
||||
log_success "Monitoring stack deployed"
|
||||
}
|
||||
|
||||
# Deploy services stack
|
||||
deploy_services() {
|
||||
log_info "Deploying services stack..."
|
||||
compose_cmd "services.yaml" up -d "$@"
|
||||
log_success "Services stack deployed"
|
||||
}
|
||||
|
||||
# Deploy external services stack
|
||||
deploy_external() {
|
||||
log_info "Deploying external services stack..."
|
||||
|
||||
if [ "$ENVIRONMENT" = "production" ] || [ "$ENVIRONMENT" = "development" ]; then
|
||||
log_warning "External services (Traefik, Authentik, Gitea) may already exist on this server"
|
||||
read -p "Do you want to deploy external services? (y/N) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
log_info "Skipping external services"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
compose_cmd "external.yaml" up -d "$@"
|
||||
log_success "External services stack deployed"
|
||||
}
|
||||
|
||||
# Stop all stacks
|
||||
stop_all() {
|
||||
log_info "Stopping all stacks..."
|
||||
|
||||
if [ -f "$BASE_DIR/services.yaml" ]; then
|
||||
compose_cmd "services.yaml" down
|
||||
fi
|
||||
|
||||
if [ -f "$BASE_DIR/monitoring.yaml" ]; then
|
||||
compose_cmd "monitoring.yaml" down
|
||||
fi
|
||||
|
||||
if [ -f "$BASE_DIR/infrastructure.yaml" ]; then
|
||||
compose_cmd "infrastructure.yaml" down
|
||||
fi
|
||||
|
||||
if [ -f "$BASE_DIR/external.yaml" ]; then
|
||||
log_warning "External services not stopped (may be shared)"
|
||||
fi
|
||||
|
||||
log_success "All stacks stopped"
|
||||
}
|
||||
|
||||
# Deploy all stacks
|
||||
deploy_all() {
|
||||
log_info "Deploying all stacks..."
|
||||
|
||||
# Check if networks exist
|
||||
if ! docker network inspect frontend >/dev/null 2>&1; then
|
||||
log_warning "Network 'frontend' does not exist. Creating..."
|
||||
docker network create frontend
|
||||
fi
|
||||
|
||||
if ! docker network inspect backend >/dev/null 2>&1; then
|
||||
log_warning "Network 'backend' does not exist. Creating..."
|
||||
docker network create backend
|
||||
fi
|
||||
|
||||
# Deploy in order
|
||||
deploy_infrastructure "$@"
|
||||
sleep 5
|
||||
|
||||
deploy_monitoring "$@"
|
||||
sleep 5
|
||||
|
||||
deploy_services "$@"
|
||||
|
||||
log_success "All stacks deployed successfully!"
|
||||
echo ""
|
||||
log_info "Access your services:"
|
||||
echo " - Grafana: https://grafana.$DOMAIN"
|
||||
echo " - Prometheus: https://prometheus.$DOMAIN"
|
||||
echo " - Vault: https://vault.$DOMAIN"
|
||||
echo " - MinIO: https://minio.$DOMAIN"
|
||||
echo " - UI Review: https://ui-review.$DOMAIN"
|
||||
}
|
||||
|
||||
# Main deployment logic
|
||||
case $STACK in
|
||||
all)
|
||||
deploy_all "$@"
|
||||
;;
|
||||
infrastructure)
|
||||
deploy_infrastructure "$@"
|
||||
;;
|
||||
monitoring)
|
||||
deploy_monitoring "$@"
|
||||
;;
|
||||
services)
|
||||
deploy_services "$@"
|
||||
;;
|
||||
external)
|
||||
deploy_external "$@"
|
||||
;;
|
||||
down)
|
||||
stop_all
|
||||
;;
|
||||
*)
|
||||
log_error "Invalid stack: $STACK"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Deployment complete!"
|
||||
|
||||
178
infra/scripts/reorganize-structure.sh
Executable file
178
infra/scripts/reorganize-structure.sh
Executable file
@@ -0,0 +1,178 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to reorganize infrastructure from old structure to new structure
|
||||
# This is a helper script to move files around
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() {
|
||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
# Script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
INFRA_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
PROJECT_ROOT="$(dirname "$INFRA_DIR")"
|
||||
|
||||
log_info "Reorganizing infrastructure structure..."
|
||||
echo " Infra Dir: $INFRA_DIR"
|
||||
echo ""
|
||||
|
||||
# Step 1: Create directory structure (already done by mkdir command)
|
||||
log_info "Step 1: Verifying directory structure..."
|
||||
if [ -d "$INFRA_DIR/base" ] && [ -d "$INFRA_DIR/environments" ]; then
|
||||
log_success "Directory structure exists"
|
||||
else
|
||||
log_error "Directory structure not found. Run: mkdir -p infra/{base,environments/{local,development,production},configs/{traefik,grafana,prometheus,loki,vault,authentik},certs/{local,development,production}}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 2: Move config files
|
||||
log_info "Step 2: Moving configuration files..."
|
||||
|
||||
# Traefik configs
|
||||
if [ -d "$INFRA_DIR/traefik" ] && [ ! -f "$INFRA_DIR/configs/traefik/.moved" ]; then
|
||||
log_info " Moving Traefik configs..."
|
||||
cp -r "$INFRA_DIR/traefik/"* "$INFRA_DIR/configs/traefik/" 2>/dev/null || true
|
||||
touch "$INFRA_DIR/configs/traefik/.moved"
|
||||
log_success " Traefik configs moved"
|
||||
fi
|
||||
|
||||
# Grafana configs
|
||||
if [ -d "$INFRA_DIR/grafana" ] && [ ! -f "$INFRA_DIR/configs/grafana/.moved" ]; then
|
||||
log_info " Moving Grafana configs..."
|
||||
cp -r "$INFRA_DIR/grafana/"* "$INFRA_DIR/configs/grafana/" 2>/dev/null || true
|
||||
touch "$INFRA_DIR/configs/grafana/.moved"
|
||||
log_success " Grafana configs moved"
|
||||
fi
|
||||
|
||||
# Prometheus configs
|
||||
if [ -d "$INFRA_DIR/prometheus" ] && [ ! -f "$INFRA_DIR/configs/prometheus/.moved" ]; then
|
||||
log_info " Moving Prometheus configs..."
|
||||
cp -r "$INFRA_DIR/prometheus/"* "$INFRA_DIR/configs/prometheus/" 2>/dev/null || true
|
||||
touch "$INFRA_DIR/configs/prometheus/.moved"
|
||||
log_success " Prometheus configs moved"
|
||||
fi
|
||||
|
||||
# Loki configs
|
||||
if [ -d "$INFRA_DIR/loki" ] && [ ! -f "$INFRA_DIR/configs/loki/.moved" ]; then
|
||||
log_info " Moving Loki configs..."
|
||||
cp -r "$INFRA_DIR/loki/"* "$INFRA_DIR/configs/loki/" 2>/dev/null || true
|
||||
touch "$INFRA_DIR/configs/loki/.moved"
|
||||
log_success " Loki configs moved"
|
||||
fi
|
||||
|
||||
# Promtail configs
|
||||
if [ -d "$INFRA_DIR/promtail" ] && [ ! -f "$INFRA_DIR/configs/promtail/.moved" ]; then
|
||||
log_info " Moving Promtail configs..."
|
||||
mkdir -p "$INFRA_DIR/configs/promtail"
|
||||
cp -r "$INFRA_DIR/promtail/"* "$INFRA_DIR/configs/promtail/" 2>/dev/null || true
|
||||
touch "$INFRA_DIR/configs/promtail/.moved"
|
||||
log_success " Promtail configs moved"
|
||||
fi
|
||||
|
||||
# Vault configs
|
||||
if [ -d "$INFRA_DIR/vault" ] && [ ! -f "$INFRA_DIR/configs/vault/.moved" ]; then
|
||||
log_info " Moving Vault configs..."
|
||||
cp -r "$INFRA_DIR/vault/"* "$INFRA_DIR/configs/vault/" 2>/dev/null || true
|
||||
touch "$INFRA_DIR/configs/vault/.moved"
|
||||
log_success " Vault configs moved"
|
||||
fi
|
||||
|
||||
# Authentik configs
|
||||
if [ -d "$INFRA_DIR/authentik" ] && [ ! -f "$INFRA_DIR/configs/authentik/.moved" ]; then
|
||||
log_info " Moving Authentik configs..."
|
||||
cp -r "$INFRA_DIR/authentik/"* "$INFRA_DIR/configs/authentik/" 2>/dev/null || true
|
||||
touch "$INFRA_DIR/configs/authentik/.moved"
|
||||
log_success " Authentik configs moved"
|
||||
fi
|
||||
|
||||
# Step 3: Move certificates
|
||||
log_info "Step 3: Moving certificates..."
|
||||
if [ -d "$INFRA_DIR/certs" ] && [ -f "$INFRA_DIR/certs/local.crt" ]; then
|
||||
log_info " Moving local certificates..."
|
||||
cp "$INFRA_DIR/certs/local.crt" "$INFRA_DIR/certs/local/" 2>/dev/null || true
|
||||
cp "$INFRA_DIR/certs/local.key" "$INFRA_DIR/certs/local/" 2>/dev/null || true
|
||||
log_success " Certificates moved"
|
||||
fi
|
||||
|
||||
# Step 4: Update base compose files paths
|
||||
log_info "Step 4: Updating base compose file paths..."
|
||||
|
||||
# Update infrastructure.yaml
|
||||
if [ -f "$INFRA_DIR/base/infrastructure.yaml" ]; then
|
||||
log_info " Updating infrastructure.yaml paths..."
|
||||
# This would require sed commands to update volume paths
|
||||
# For now, just log that manual update may be needed
|
||||
log_warning " Manual review recommended for volume paths"
|
||||
fi
|
||||
|
||||
# Step 5: Create .gitignore for sensitive files
|
||||
log_info "Step 5: Creating .gitignore..."
|
||||
cat > "$INFRA_DIR/.gitignore" << 'EOF'
|
||||
# Environment files (contain secrets)
|
||||
environments/*/.env
|
||||
!environments/*/.env.example
|
||||
|
||||
# Certificates
|
||||
certs/*/
|
||||
!certs/.gitkeep
|
||||
|
||||
# Traefik provider credentials
|
||||
configs/traefik/.provider.env
|
||||
|
||||
# Backup files
|
||||
*.backup
|
||||
*.tmp
|
||||
|
||||
# Docker volumes (if mounted locally)
|
||||
volumes/
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
EOF
|
||||
log_success ".gitignore created"
|
||||
|
||||
# Step 6: Create .gitkeep files
|
||||
log_info "Step 6: Creating .gitkeep files..."
|
||||
touch "$INFRA_DIR/certs/local/.gitkeep"
|
||||
touch "$INFRA_DIR/certs/development/.gitkeep"
|
||||
touch "$INFRA_DIR/certs/production/.gitkeep"
|
||||
log_success ".gitkeep files created"
|
||||
|
||||
# Step 7: Summary
|
||||
echo ""
|
||||
log_success "Reorganization complete!"
|
||||
echo ""
|
||||
log_info "Next steps:"
|
||||
echo " 1. Review moved files in configs/ directory"
|
||||
echo " 2. Update compose file paths if needed"
|
||||
echo " 3. Create environment files:"
|
||||
echo " cp infra/environments/local/.env.example infra/environments/local/.env"
|
||||
echo " cp infra/environments/development/.env.example infra/environments/development/.env"
|
||||
echo " 4. Test deployment:"
|
||||
echo " ./infra/scripts/deploy.sh local infrastructure"
|
||||
echo ""
|
||||
log_warning "Old directories (traefik/, grafana/, etc.) are preserved for safety"
|
||||
log_warning "You can remove them after verifying the new structure works"
|
||||
echo ""
|
||||
|
||||
48
infra/scripts/setup-networks.sh
Executable file
48
infra/scripts/setup-networks.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Setup Docker Networks for AI Tax Agent
|
||||
# Creates frontend and backend networks if they don't exist
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() {
|
||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
log_info "Setting up Docker networks..."
|
||||
|
||||
# Create frontend network
|
||||
if docker network inspect frontend >/dev/null 2>&1; then
|
||||
log_warning "Network 'frontend' already exists"
|
||||
else
|
||||
docker network create frontend
|
||||
log_success "Created network 'frontend'"
|
||||
fi
|
||||
|
||||
# Create backend network
|
||||
if docker network inspect backend >/dev/null 2>&1; then
|
||||
log_warning "Network 'backend' already exists"
|
||||
else
|
||||
docker network create backend
|
||||
log_success "Created network 'backend'"
|
||||
fi
|
||||
|
||||
log_success "Docker networks ready!"
|
||||
echo ""
|
||||
log_info "Networks:"
|
||||
docker network ls | grep -E "frontend|backend"
|
||||
|
||||
Reference in New Issue
Block a user