# Bedrock-API Deployment ## Containerization ### Dockerfile **File**: `Dockerfile` **Strategy**: Multi-stage build (builder + runtime) ```dockerfile # Builder stage FROM golang:1.23-alpine AS builder WORKDIR /app # Install git (required for submodules) RUN apk add --no-cache git # Copy go mod files COPY go.mod go.sum ./ RUN go mod download # Copy source code COPY . . # Initialize submodules RUN git submodule update --init --recursive # Build binary RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o bedrock-server ./bedrock_server # Runtime stage FROM alpine:latest # Install ca-certificates (required for HTTPS requests to provider APIs) RUN apk --no-cache add ca-certificates WORKDIR /root/ # Copy binary from builder COPY --from=builder /app/bedrock-server . # Copy migrations (if needed) COPY --from=builder /app/db/migrations ./db/migrations # Expose ports EXPOSE 50052 8080 # Run server CMD ["./bedrock-server"] ``` **Build Stages**: 1. **Builder** (`golang:1.23-alpine`): - Installs git for submodule support - Downloads Go dependencies - Initializes spotapi-go submodule - Compiles binary with optimizations (`-ldflags="-w -s"`) - CGO disabled for static binary 2. **Runtime** (`alpine:latest`): - Minimal image (~5 MB base) - Installs ca-certificates for HTTPS - Copies binary from builder - Exposes gRPC (50052) and HTTP (8080) ports **Image Size**: ~20 MB (builder stage discarded) **Version Mismatch**: Dockerfile uses Go 1.23, but `go.mod` specifies 1.25 **Fix**: ```dockerfile FROM golang:1.25-alpine AS builder ``` ### Docker Build **Build Command**: ```bash docker build -t bedrock-api:latest . ``` **Build Arguments** (not implemented): ```dockerfile ARG GO_VERSION=1.25 FROM golang:${GO_VERSION}-alpine AS builder ``` **Build Time**: ~2-3 minutes (first build), ~30 seconds (cached) ### Docker Run **Run Command**: ```bash docker run -d \ --name bedrock-api \ -p 50052:50052 \ -p 8080:8080 \ -e DATABASE_URL=postgresql://user:pass@host:5432/bedrock \ -e JWT_SECRET=your-secret \ -e SPOTIFY_CLIENT_ID=your-id \ -e SPOTIFY_CLIENT_SECRET=your-secret \ -e SOUNDCLOUD_CLIENT_IDS=id1,id2,id3 \ -e GENIUS_ACCESS_TOKEN=your-token \ bedrock-api:latest ``` **Environment Variables**: Passed via `-e` flags (no `.env` file in container) **Port Mapping**: - `50052:50052` - gRPC server - `8080:8080` - HTTP proxy **No Volume Mounts**: Binary is stateless (no local file storage) ## Docker Compose ### Compose File **File**: `docker-compose.yml` ```yaml version: '3.8' services: postgres: image: postgres:15-alpine container_name: bedrock-postgres environment: POSTGRES_USER: bedrock POSTGRES_PASSWORD: bedrock POSTGRES_DB: bedrock ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U bedrock"] interval: 10s timeout: 5s retries: 5 networks: - bedrock-network volumes: postgres_data: driver: local networks: bedrock-network: driver: bridge ``` **Services**: PostgreSQL only (application not included) **Missing Services**: - No application service (must be added or run separately) - No Redis (planned for caching) - No reverse proxy (nginx, Caddy) - No monitoring (Prometheus, Grafana) ### Complete Compose File (Recommended) ```yaml version: '3.8' services: postgres: image: postgres:15-alpine container_name: bedrock-postgres environment: POSTGRES_USER: bedrock POSTGRES_PASSWORD: bedrock POSTGRES_DB: bedrock ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data - ./db/migrations:/docker-entrypoint-initdb.d healthcheck: test: ["CMD-SHELL", "pg_isready -U bedrock"] interval: 10s timeout: 5s retries: 5 networks: - bedrock-network bedrock-api: build: . container_name: bedrock-api depends_on: postgres: condition: service_healthy environment: DATABASE_URL: postgresql://bedrock:bedrock@postgres:5432/bedrock?sslmode=disable JWT_SECRET: ${JWT_SECRET} SPOTIFY_CLIENT_ID: ${SPOTIFY_CLIENT_ID} SPOTIFY_CLIENT_SECRET: ${SPOTIFY_CLIENT_SECRET} SOUNDCLOUD_CLIENT_IDS: ${SOUNDCLOUD_CLIENT_IDS} GENIUS_ACCESS_TOKEN: ${GENIUS_ACCESS_TOKEN} YOUTUBE_COOKIES: ${YOUTUBE_COOKIES} ports: - "50052:50052" - "8080:8080" networks: - bedrock-network restart: unless-stopped volumes: postgres_data: networks: bedrock-network: ``` **Improvements**: - Application service added - Health check dependency (waits for PostgreSQL) - Environment variables from `.env` file - Automatic restart policy - Migration initialization via volume mount ### Compose Commands **Start Services**: ```bash docker-compose up -d ``` **View Logs**: ```bash docker-compose logs -f bedrock-api ``` **Stop Services**: ```bash docker-compose down ``` **Rebuild**: ```bash docker-compose up -d --build ``` **Clean Volumes**: ```bash docker-compose down -v ``` ## Local Development ### Prerequisites - Go 1.25+ - PostgreSQL 15+ - Git (for submodules) ### Setup Steps **1. Clone Repository**: ```bash git clone https://github.com/feralbureau/bedrock-api cd bedrock-api ``` **2. Initialize Submodules**: ```bash git submodule update --init --recursive ``` **3. Install Dependencies**: ```bash go mod download ``` **4. Setup Database**: ```bash # Start PostgreSQL (Docker) docker run -d \ --name bedrock-postgres \ -e POSTGRES_USER=bedrock \ -e POSTGRES_PASSWORD=bedrock \ -e POSTGRES_DB=bedrock \ -p 5432:5432 \ postgres:15-alpine # Run migrations psql postgresql://bedrock:bedrock@localhost:5432/bedrock -f db/migrations/001_create_users_table.up.sql ``` **5. Configure Environment**: ```bash cp .env.example .env # Edit .env with your credentials ``` **Example `.env`**: ``` DATABASE_URL=postgresql://bedrock:bedrock@localhost:5432/bedrock?sslmode=disable JWT_SECRET=your-secret-key-change-this-in-production SPOTIFY_CLIENT_ID=your_spotify_client_id SPOTIFY_CLIENT_SECRET=your_spotify_client_secret SOUNDCLOUD_CLIENT_IDS=client_id_1,client_id_2,client_id_3 DEEZER_APP_ID=your_deezer_app_id YOUTUBE_COOKIES=your_youtube_cookies GENIUS_ACCESS_TOKEN=your_genius_access_token ``` **6. Run Server**: ```bash go run ./bedrock_server ``` **7. Verify**: ```bash # gRPC health check (requires grpcurl) grpcurl -plaintext localhost:50052 bedrock.BedrockService/GetServiceStatus # HTTP proxy check curl http://localhost:8080/stream/soundcloud/1234567890 ``` ### Development Workflow **Hot Reload** (not configured): ```bash # Install air go install github.com/cosmtrek/air@latest # Run with hot reload air ``` **Example `.air.toml`**: ```toml root = "." tmp_dir = "tmp" [build] cmd = "go build -o ./tmp/main ./bedrock_server" bin = "tmp/main" include_ext = ["go", "proto"] exclude_dir = ["tmp", "vendor"] delay = 1000 ``` ### Testing **Run Tests**: ```bash go test ./... ``` **Integration Tests** (requires provider credentials): ```bash export SPOTIFY_CLIENT_ID=your_id export SPOTIFY_CLIENT_SECRET=your_secret export SOUNDCLOUD_CLIENT_IDS=your_ids export GENIUS_ACCESS_TOKEN=your_token export BEDROCK_TEST_ADDR=localhost:50052 go test -v ./tests/ ``` **Test Coverage**: ```bash go test -cover ./... ``` ## CI/CD Pipeline ### GitHub Actions **Workflows**: - `test.yml` - Integration tests - `lint.yml` - Code linting ### Test Workflow **File**: `.github/workflows/test.yml` ```yaml name: Tests on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] jobs: test: runs-on: ubuntu-latest services: postgres: image: postgres:15-alpine env: POSTGRES_USER: bedrock POSTGRES_PASSWORD: bedrock POSTGRES_DB: bedrock ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - name: Checkout code uses: actions/checkout@v3 with: submodules: recursive - name: Setup Go uses: actions/setup-go@v4 with: go-version: '1.24' - name: Download dependencies run: go mod download - name: Run migrations run: | psql postgresql://bedrock:bedrock@localhost:5432/bedrock -f db/migrations/001_create_users_table.up.sql - name: Run tests env: DATABASE_URL: postgresql://bedrock:bedrock@localhost:5432/bedrock?sslmode=disable JWT_SECRET: test-secret SPOTIFY_CLIENT_ID: ${{ secrets.SPOTIFY_CLIENT_ID }} SPOTIFY_CLIENT_SECRET: ${{ secrets.SPOTIFY_CLIENT_SECRET }} SOUNDCLOUD_CLIENT_IDS: ${{ secrets.SOUNDCLOUD_CLIENT_IDS }} GENIUS_ACCESS_TOKEN: ${{ secrets.GENIUS_ACCESS_TOKEN }} YOUTUBE_COOKIES: ${{ secrets.YOUTUBE_COOKIES }} run: go test -v -timeout 120s ./tests/ ``` **Features**: - PostgreSQL service container - Submodule initialization - Go 1.24 (should be 1.25 to match go.mod) - Migration execution - Integration tests with provider secrets - 120 second timeout **Required Secrets**: - `SPOTIFY_CLIENT_ID` - `SPOTIFY_CLIENT_SECRET` - `SOUNDCLOUD_CLIENT_IDS` - `GENIUS_ACCESS_TOKEN` - `YOUTUBE_COOKIES` ### Lint Workflow **File**: `.github/workflows/lint.yml` ```yaml name: Lint on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] jobs: golangci-lint: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 with: submodules: recursive - name: Setup Go uses: actions/setup-go@v4 with: go-version: '1.24' - name: Run golangci-lint uses: golangci/golangci-lint-action@v3 with: version: latest comment-lint: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Check for decorative comments run: | # Fail if decorative comments found (e.g., // ========) if grep -r "^[[:space:]]*//[[:space:]]*[=\-*#]\{3,\}" --include="*.go" .; then echo "Decorative comments found" exit 1 fi - name: Check for uppercase-leading comments run: | # Fail if comments start with uppercase (except TODO, FIXME, NOTE) if grep -r "^[[:space:]]*//[[:space:]]*[A-Z]" --include="*.go" . | grep -v "TODO\|FIXME\|NOTE"; then echo "Uppercase-leading comments found" exit 1 fi ``` **Linters**: - `golangci-lint` - Standard Go linting (gofmt, govet, staticcheck, etc.) - Custom comment linter - Enforces comment style (no decorative comments, no uppercase-leading) **Comment Rules**: - No decorative comments (`// ========`, `// --------`, etc.) - No uppercase-leading comments (except `TODO`, `FIXME`, `NOTE`) ## Production Deployment ### Reverse Proxy (TLS Termination) **No Built-in TLS**: Application must be deployed behind reverse proxy **Nginx Example**: ```nginx upstream bedrock_grpc { server localhost:50052; } upstream bedrock_http { server localhost:8080; } server { listen 443 ssl http2; server_name api.example.com; ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem; # gRPC endpoint location /bedrock.BedrockService/ { grpc_pass grpc://bedrock_grpc; grpc_set_header X-Real-IP $remote_addr; grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # HTTP proxy endpoints location /stream/ { proxy_pass http://bedrock_http; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_buffering off; } location /cover/ { proxy_pass http://bedrock_http; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` **Caddy Example** (simpler): ``` api.example.com { reverse_proxy /bedrock.BedrockService/* h2c://localhost:50052 reverse_proxy /stream/* localhost:8080 reverse_proxy /cover/* localhost:8080 } ``` ### Systemd Service **File**: `/etc/systemd/system/bedrock-api.service` ```ini [Unit] Description=Bedrock API Server After=network.target postgresql.service Requires=postgresql.service [Service] Type=simple User=bedrock Group=bedrock WorkingDirectory=/opt/bedrock-api EnvironmentFile=/opt/bedrock-api/.env ExecStart=/opt/bedrock-api/bedrock-server Restart=always RestartSec=10 StandardOutput=journal StandardError=journal SyslogIdentifier=bedrock-api # Security hardening NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true ReadWritePaths=/opt/bedrock-api/logs [Install] WantedBy=multi-user.target ``` **Commands**: ```bash # Enable service sudo systemctl enable bedrock-api # Start service sudo systemctl start bedrock-api # Check status sudo systemctl status bedrock-api # View logs sudo journalctl -u bedrock-api -f ``` ### Environment Variables (Production) **Secure Storage**: Use secrets management (not `.env` file) **AWS Secrets Manager**: ```bash aws secretsmanager get-secret-value --secret-id bedrock-api/production --query SecretString --output text > /tmp/secrets.env source /tmp/secrets.env rm /tmp/secrets.env ``` **HashiCorp Vault**: ```bash vault kv get -format=json secret/bedrock-api/production | jq -r '.data.data | to_entries[] | "\(.key)=\(.value)"' > /tmp/secrets.env source /tmp/secrets.env rm /tmp/secrets.env ``` **Kubernetes Secrets**: ```yaml apiVersion: v1 kind: Secret metadata: name: bedrock-api-secrets type: Opaque stringData: DATABASE_URL: postgresql://user:pass@postgres:5432/bedrock JWT_SECRET: your-secret SPOTIFY_CLIENT_ID: your-id SPOTIFY_CLIENT_SECRET: your-secret SOUNDCLOUD_CLIENT_IDS: id1,id2,id3 GENIUS_ACCESS_TOKEN: your-token ``` ### Database Migrations (Production) **Manual Execution** (current): ```bash psql $DATABASE_URL -f db/migrations/001_create_users_table.up.sql ``` **Automated with golang-migrate** (recommended): ```bash # Install migrate curl -L https://github.com/golang-migrate/migrate/releases/download/v4.16.2/migrate.linux-amd64.tar.gz | tar xvz sudo mv migrate /usr/local/bin/ # Run migrations migrate -path db/migrations -database $DATABASE_URL up # Rollback migrate -path db/migrations -database $DATABASE_URL down 1 ``` **Migration Tracking**: ```sql -- golang-migrate creates this table automatically SELECT * FROM schema_migrations; ``` ### Monitoring (Not Implemented) **Recommended Stack**: - Prometheus (metrics collection) - Grafana (visualization) - Loki (log aggregation) - Jaeger (distributed tracing) **Prometheus Metrics** (to implement): ```go import "github.com/prometheus/client_golang/prometheus" var ( requestsTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "bedrock_requests_total", Help: "Total number of requests", }, []string{"method", "status"}, ) requestDuration = prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: "bedrock_request_duration_seconds", Help: "Request duration in seconds", }, []string{"method"}, ) providerErrors = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "bedrock_provider_errors_total", Help: "Total provider errors", }, []string{"provider"}, ) ) ``` **Grafana Dashboard** (example queries): ```promql # Request rate rate(bedrock_requests_total[5m]) # Error rate rate(bedrock_requests_total{status="error"}[5m]) / rate(bedrock_requests_total[5m]) # P95 latency histogram_quantile(0.95, rate(bedrock_request_duration_seconds_bucket[5m])) # Provider error rate rate(bedrock_provider_errors_total[5m]) ``` ### Logging (Production) **Structured Logging** (to implement): ```go import "go.uber.org/zap" logger, _ := zap.NewProduction() defer logger.Sync() logger.Info("search request", zap.String("query", query), zap.Int32("limit", limit), zap.String("user_id", userID), ) logger.Error("provider failed", zap.String("provider", "spotify"), zap.Error(err), ) ``` **Log Aggregation** (Loki): ```yaml # promtail config clients: - url: http://loki:3100/loki/api/v1/push scrape_configs: - job_name: bedrock-api static_configs: - targets: - localhost labels: job: bedrock-api __path__: /var/log/bedrock-api/*.log ``` ### Backup Strategy **PostgreSQL Backups**: ```bash # Daily backup script #!/bin/bash BACKUP_DIR=/backups/bedrock-api DATE=$(date +%Y%m%d_%H%M%S) pg_dump $DATABASE_URL | gzip > $BACKUP_DIR/bedrock_$DATE.sql.gz # Keep last 30 days find $BACKUP_DIR -name "bedrock_*.sql.gz" -mtime +30 -delete # Upload to S3 aws s3 cp $BACKUP_DIR/bedrock_$DATE.sql.gz s3://backups/bedrock-api/ ``` **Cron Schedule**: ```cron 0 2 * * * /opt/bedrock-api/scripts/backup.sh ``` **Point-in-Time Recovery** (WAL archiving): ```sql -- Enable WAL archiving in postgresql.conf wal_level = replica archive_mode = on archive_command = 'aws s3 cp %p s3://backups/bedrock-api/wal/%f' ``` ### Scaling Strategies **Vertical Scaling**: - Increase CPU/RAM for single instance - Increase PostgreSQL resources - Increase connection pool size **Horizontal Scaling**: - Run multiple application instances behind load balancer - Use read replicas for PostgreSQL (if read-heavy) - Add Redis for caching (reduce provider API calls) **Load Balancer** (nginx): ```nginx upstream bedrock_grpc { server bedrock-api-1:50052; server bedrock-api-2:50052; server bedrock-api-3:50052; } server { listen 443 ssl http2; location /bedrock.BedrockService/ { grpc_pass grpc://bedrock_grpc; } } ``` **Kubernetes Deployment**: ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: bedrock-api spec: replicas: 3 selector: matchLabels: app: bedrock-api template: metadata: labels: app: bedrock-api spec: containers: - name: bedrock-api image: bedrock-api:latest ports: - containerPort: 50052 name: grpc - containerPort: 8080 name: http env: - name: DATABASE_URL valueFrom: secretKeyRef: name: bedrock-api-secrets key: DATABASE_URL resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m" livenessProbe: exec: command: - grpc_health_probe - -addr=:50052 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: exec: command: - grpc_health_probe - -addr=:50052 initialDelaySeconds: 5 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: name: bedrock-api spec: selector: app: bedrock-api ports: - name: grpc port: 50052 targetPort: 50052 - name: http port: 8080 targetPort: 8080 type: LoadBalancer ``` ## Deployment Checklist ### Pre-Deployment - [ ] Update Go version in Dockerfile to match go.mod (1.25) - [ ] Configure environment variables (secrets management) - [ ] Run database migrations - [ ] Test provider credentials - [ ] Configure reverse proxy (TLS) - [ ] Set up monitoring (Prometheus, Grafana) - [ ] Set up logging (structured logs, aggregation) - [ ] Configure backups (PostgreSQL, WAL archiving) - [ ] Load test (ensure performance under load) - [ ] Security audit (JWT secret, database credentials, etc.) ### Post-Deployment - [ ] Verify gRPC endpoint (grpcurl) - [ ] Verify HTTP proxy endpoints (curl) - [ ] Check logs for errors - [ ] Monitor metrics (request rate, error rate, latency) - [ ] Test authentication (register, login, refresh) - [ ] Test search (all providers) - [ ] Test streaming (SoundCloud, YouTube Music) - [ ] Test lyrics (LrcLib, Genius) - [ ] Verify database connection - [ ] Test backup restoration ### Ongoing Maintenance - [ ] Monitor provider API changes - [ ] Rotate JWT secret periodically - [ ] Update dependencies (go mod tidy) - [ ] Review logs for errors - [ ] Monitor disk usage (PostgreSQL, logs) - [ ] Test backup restoration monthly - [ ] Update TLS certificates (Let's Encrypt auto-renewal) - [ ] Review security advisories (Go, dependencies) ## Deployment Environments ### Development **Infrastructure**: Local machine or Docker Compose **Database**: PostgreSQL in Docker **Secrets**: `.env` file **TLS**: No (HTTP only) **Monitoring**: No **Backups**: No ### Staging **Infrastructure**: Single VM or Kubernetes cluster **Database**: Managed PostgreSQL (AWS RDS, Google Cloud SQL) **Secrets**: Secrets manager (AWS Secrets Manager, Vault) **TLS**: Yes (Let's Encrypt) **Monitoring**: Prometheus + Grafana **Backups**: Daily automated backups ### Production **Infrastructure**: Kubernetes cluster (multi-region) **Database**: Managed PostgreSQL with read replicas **Secrets**: Secrets manager with rotation **TLS**: Yes (Let's Encrypt or commercial cert) **Monitoring**: Full observability stack (Prometheus, Grafana, Loki, Jaeger) **Backups**: Hourly backups + WAL archiving + point-in-time recovery **Scaling**: Horizontal pod autoscaling (HPA) **High Availability**: Multi-zone deployment, load balancing ## Cost Estimation (AWS) ### Small Deployment (1000 requests/day) | Resource | Specification | Monthly Cost | |----------|---------------|--------------| | EC2 Instance | t3.small (2 vCPU, 2 GB RAM) | $15 | | RDS PostgreSQL | db.t3.micro (1 vCPU, 1 GB RAM) | $15 | | Load Balancer | Application Load Balancer | $20 | | Data Transfer | 100 GB/month | $9 | | **Total** | | **$59/month** | ### Medium Deployment (100k requests/day) | Resource | Specification | Monthly Cost | |----------|---------------|--------------| | EC2 Instances | 3x t3.medium (2 vCPU, 4 GB RAM) | $90 | | RDS PostgreSQL | db.t3.small (2 vCPU, 2 GB RAM) | $30 | | ElastiCache Redis | cache.t3.micro (1 vCPU, 0.5 GB RAM) | $12 | | Load Balancer | Application Load Balancer | $20 | | Data Transfer | 1 TB/month | $90 | | **Total** | | **$242/month** | ### Large Deployment (1M requests/day) | Resource | Specification | Monthly Cost | |----------|---------------|--------------| | EKS Cluster | Control plane | $73 | | EC2 Instances | 10x t3.large (2 vCPU, 8 GB RAM) | $600 | | RDS PostgreSQL | db.r5.large (2 vCPU, 16 GB RAM) + read replica | $300 | | ElastiCache Redis | cache.r5.large (2 vCPU, 13 GB RAM) | $150 | | Load Balancer | Application Load Balancer | $20 | | Data Transfer | 10 TB/month | $900 | | **Total** | | **$2,043/month** | **Note**: Costs exclude provider API fees (Spotify, Genius, etc.) ## Deployment Recommendations for Metadata Aggregator ### Adopt - Multi-stage Docker build (minimal runtime image) - Docker Compose for local development - GitHub Actions for CI/CD - Reverse proxy for TLS termination - Systemd service for production ### Avoid - Manual migrations (use golang-migrate) - No monitoring (implement Prometheus) - No structured logging (use zap or zerolog) - Go version mismatch (keep Dockerfile and go.mod in sync) ### Enhance - Add health check endpoint (implement GetServiceStatus properly) - Add graceful shutdown (handle SIGTERM) - Add readiness probe (check database connection) - Add metrics endpoint (/metrics for Prometheus) - Add Redis for caching - Add backup automation - Add deployment documentation