# Banatie Service Infrastructure Documentation

## Overview

This document defines the complete containerization and deployment architecture for the Banatie AI image generation service with MinIO object storage and PostgreSQL database integration.

## Architecture Summary

### Core Principles

- **Complete Service Isolation**: Banatie ecosystem is fully isolated from core VPS services
- **Dedicated Database**: Separate PostgreSQL container exclusively for Banatie
- **S3-Compatible Storage**: MinIO for scalable object storage with multi-tenant support
- **Container-First Approach**: All components run as Docker containers
- **Network Segregation**: Internal communication via dedicated Docker networks

### Service Components

```
Banatie Ecosystem (Isolated)
├── Banatie App Container (Node.js/TypeScript/Express)
├── PostgreSQL Container (Dedicated instance)
└── MinIO Container (S3-compatible object storage)
```

## Network Architecture

### Production Networks

```yaml
networks:
  banatie-network:
    driver: bridge
    internal: true # No external internet access

  proxy-network:
    external: true # Existing Caddy reverse proxy network
```

### Network Access Matrix

| Service     | banatie-network | proxy-network   | External Access |
| ----------- | --------------- | --------------- | --------------- |
| Banatie App | ✅ Internal     | ✅ HTTP only    | ❌ Direct       |
| PostgreSQL  | ✅ Internal     | ❌ None         | ❌ None         |
| MinIO       | ✅ Internal     | ✅ Console only | ❌ Direct       |
| Caddy Proxy | ❌ None         | ✅ Routing      | ✅ Internet     |

### VPS Integration Points

**Isolation from Core Services:**

- **NO** shared resources with existing PostgreSQL (`/opt/services/`)
- **NO** access to NextCloud, Gitea, or other core services
- **ONLY** connection point: Caddy reverse proxy for HTTP routing

**Shared Infrastructure:**

- Caddy reverse proxy for SSL termination and routing
- Host filesystem for persistent data storage
- UFW firewall rules and security policies

## Directory Structure

### Development Environment

```
banatie-service/
├── src/                        # Application source code
├── Dockerfile                  # Multi-stage container build
├── docker-compose.yml          # Local development setup
├── .env.example               # Environment template
├── .dockerignore              # Build exclusions
└── data/                      # Local development data
    ├── postgres/              # PostgreSQL data
    └── minio/                 # MinIO data
```

### Production Environment (VPS)

```
/opt/banatie/                  # Isolated deployment directory
├── docker-compose.yml         # Production configuration
├── .env                       # Production environment (secure)
├── Dockerfile                 # Production Dockerfile
├── data/                      # Persistent data storage
│   ├── postgres/              # PostgreSQL data
│   └── minio/                 # MinIO data
├── configs/                   # Service configurations
├── logs/                      # Application logs
└── scripts/                   # Deployment scripts
```

## Container Specifications

### 1. Banatie Application Container

**Base Image**: `node:20-alpine`
**Build Strategy**: Multi-stage for optimization
**Runtime**: Node.js with TypeScript compilation

```dockerfile
# Multi-stage build for production
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build

FROM node:20-alpine
WORKDIR /app
RUN npm install -g pnpm
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/pnpm-lock.yaml ./
RUN pnpm install --prod --frozen-lockfile
EXPOSE 3000
CMD ["node", "dist/server.js"]
```

**Key Features:**

- Hot-reload support in development
- Production-optimized build with dependencies pruning
- Health check endpoints for monitoring
- Structured logging to stdout

### 2. PostgreSQL Container

**Image**: `postgres:15-alpine`
**Purpose**: Metadata storage for user sessions, image metadata, organization data
**Data**: User accounts, image metadata, upload sessions, organization settings

**Database Schema:**

- `users` - User authentication and profiles
- `organizations` - Multi-tenant organization data
- `images` - Generated image metadata and references
- `sessions` - User session management
- `uploads` - Temporary upload tracking

### 3. MinIO Container

**Image**: `minio/minio:latest`
**Purpose**: S3-compatible object storage for images and files
**Ports**: 9000 (S3 API), 9001 (Web Console)

**Storage Strategy:**

- Persistent volumes for data durability
- Bucket-per-organization architecture
- Lifecycle policies for temporary file cleanup
- Presigned URLs for direct browser uploads

## Multi-Tenant Storage Architecture

### MinIO Bucket Organization

```
banatie-{org-id}/              # Organization bucket (e.g., banatie-demo)
├── users/
│   └── {user-id}/             # User-specific namespace
│       ├── generated/         # AI-generated images
│       │   ├── 2024/01/       # Date-based organization
│       │   └── thumbnails/    # Generated thumbnails
│       ├── references/        # User-uploaded reference images
│       └── temp/              # Temporary processing files (7-day TTL)
├── shared/                    # Organization-wide shared resources
│   ├── templates/             # Shared image templates
│   └── public/                # Public organization assets
└── metadata/                  # JSON metadata files
    ├── users.json             # User directory metadata
    └── policies.json          # Access control policies
```

### Demo Organization Setup

**Default Configuration:**

- **Organization**: `demo` (org-id: demo)
- **User**: `guest` (user-id: guest)
- **Bucket**: `banatie-demo`
- **Access**: Public read for demo images

**Demo Bucket Structure:**

```
banatie-demo/
├── users/
│   └── guest/
│       ├── generated/         # Guest user's generated images
│       └── references/        # Guest user's reference uploads
└── shared/
    └── examples/              # Example images for UI
```

## Environment Configuration

### Development Environment (.env)

```env
# Application Configuration
NODE_ENV=development
PORT=3000
LOG_LEVEL=debug

# Database Configuration
DB_HOST=postgres
DB_PORT=5432
DB_NAME=banatie_db
DB_USER=banatie_user
DB_PASSWORD=development_password

# MinIO Configuration
STORAGE_TYPE=minio
MINIO_ENDPOINT=minio:9000
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin
MINIO_USE_SSL=false
MINIO_BUCKET_PREFIX=banatie

# AI Service Configuration
GEMINI_API_KEY=your_gemini_api_key_here

# Multi-tenancy Configuration
DEFAULT_ORG_ID=demo
DEFAULT_USER_ID=guest
```

### Production Environment (.env.production)

```env
# Application Configuration
NODE_ENV=production
PORT=3000
LOG_LEVEL=info

# Database Configuration
DB_HOST=banatie-postgres
DB_PORT=5432
DB_NAME=banatie_db
DB_USER=banatie_user
DB_PASSWORD=${SECURE_DB_PASSWORD}

# MinIO Configuration
STORAGE_TYPE=minio
MINIO_ENDPOINT=banatie-minio:9000
MINIO_ACCESS_KEY=${SECURE_MINIO_ACCESS_KEY}
MINIO_SECRET_KEY=${SECURE_MINIO_SECRET_KEY}
MINIO_USE_SSL=false
MINIO_BUCKET_PREFIX=banatie

# AI Service Configuration
GEMINI_API_KEY=${SECURE_GEMINI_API_KEY}

# Multi-tenancy Configuration
DEFAULT_ORG_ID=demo
DEFAULT_USER_ID=guest

# Security
JWT_SECRET=${SECURE_JWT_SECRET}
SESSION_SECRET=${SECURE_SESSION_SECRET}
```

## Docker Compose Configurations

### Development Configuration

```yaml
# docker-compose.yml (Local Development)
version: '3.8'

services:
  app:
    build:
      context: .
      target: development
    container_name: banatie-app-dev
    ports:
      - '3000:3000'
    volumes:
      - ./src:/app/src # Hot reload
      - ./logs:/app/logs
    networks:
      - banatie-dev
    depends_on:
      - postgres
      - minio
    environment:
      - NODE_ENV=development
    env_file:
      - .env

  postgres:
    image: postgres:15-alpine
    container_name: banatie-postgres-dev
    ports:
      - '5433:5432' # Avoid conflicts with system PostgreSQL
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
      - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql
    networks:
      - banatie-dev
    environment:
      POSTGRES_DB: banatie_db
      POSTGRES_USER: banatie_user
      POSTGRES_PASSWORD: development_password
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U banatie_user -d banatie_db']
      interval: 30s
      timeout: 10s
      retries: 3

  minio:
    image: minio/minio:latest
    container_name: banatie-minio-dev
    ports:
      - '9000:9000' # S3 API
      - '9001:9001' # Web Console
    volumes:
      - ./data/minio:/data
    networks:
      - banatie-dev
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    command: server /data --console-address ":9001"
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live']
      interval: 30s
      timeout: 10s
      retries: 3

networks:
  banatie-dev:
    driver: bridge
```

### Production Configuration

```yaml
# docker-compose.yml (Production on VPS)
version: '3.8'

services:
  banatie-app:
    build:
      context: .
      target: production
    container_name: banatie-app
    restart: unless-stopped
    networks:
      - banatie-network
      - proxy-network
    depends_on:
      banatie-postgres:
        condition: service_healthy
      banatie-minio:
        condition: service_healthy
    environment:
      - NODE_ENV=production
    env_file:
      - .env
    volumes:
      - ./logs:/app/logs
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

  banatie-postgres:
    image: postgres:15-alpine
    container_name: banatie-postgres
    restart: unless-stopped
    networks:
      - banatie-network
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
      - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql
    environment:
      POSTGRES_DB: banatie_db
      POSTGRES_USER: banatie_user
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U banatie_user -d banatie_db']
      interval: 30s
      timeout: 10s
      retries: 3

  banatie-minio:
    image: minio/minio:latest
    container_name: banatie-minio
    restart: unless-stopped
    networks:
      - banatie-network
      - proxy-network
    volumes:
      - ./data/minio:/data
    environment:
      MINIO_ROOT_USER: ${MINIO_ACCESS_KEY}
      MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY}
    command: server /data --console-address ":9001"
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live']
      interval: 30s
      timeout: 10s
      retries: 3

networks:
  banatie-network:
    driver: bridge
    internal: true # No external internet access

  proxy-network:
    external: true # Existing Caddy network
```

## Caddy Integration

### Caddy Configuration Addition

Add to existing Caddyfile in `/opt/services/configs/caddy/Caddyfile`:

```caddy
# Banatie App - Main API
banatie.app {
    reverse_proxy banatie-app:3000

    # Security headers
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        X-XSS-Protection "1; mode=block"
        Referrer-Policy "strict-origin-when-cross-origin"
    }

    # Rate limiting
    rate_limit {
        zone banatie_api {
            key {remote_host}
            events 100
            window 1m
        }
    }

    # Logging
    log {
        output file /opt/services/logs/banatie_access.log
        format json
    }
}

# MinIO Console - Admin Interface
minio.banatie.app {
    reverse_proxy banatie-minio:9001

    # Security headers for console
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
    }

    # Logging
    log {
        output file /opt/services/logs/minio_console_access.log
        format json
    }
}

# MinIO S3 API - Direct file access
s3.banatie.app {
    reverse_proxy banatie-minio:9000

    # CORS for browser uploads
    header {
        Access-Control-Allow-Origin "*"
        Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
        Access-Control-Allow-Headers "Content-Type, Authorization"
    }

    # Rate limiting for uploads
    rate_limit {
        zone banatie_s3 {
            key {remote_host}
            events 50
            window 1m
        }
    }

    # Logging
    log {
        output file /opt/services/logs/minio_s3_access.log
        format json
    }
}
```

## Service Implementation Strategy

### 1. Storage Service Abstraction

Create `src/services/StorageService.ts`:

```typescript
export interface StorageService {
  // Bucket management
  createBucket(orgId: string): Promise<void>;
  deleteBucket(orgId: string): Promise<void>;
  listBuckets(): Promise<string[]>;

  // File operations
  uploadFile(
    orgId: string,
    userId: string,
    fileName: string,
    buffer: Buffer,
    contentType: string,
  ): Promise<string>;
  downloadFile(orgId: string, userId: string, fileName: string): Promise<Buffer>;
  deleteFile(orgId: string, userId: string, fileName: string): Promise<void>;

  // URL generation
  getPresignedUploadUrl(
    orgId: string,
    userId: string,
    fileName: string,
    expirySeconds: number,
  ): Promise<string>;
  getPresignedDownloadUrl(
    orgId: string,
    userId: string,
    fileName: string,
    expirySeconds: number,
  ): Promise<string>;

  // File management
  listUserFiles(orgId: string, userId: string): Promise<FileMetadata[]>;
  moveFile(fromPath: string, toPath: string): Promise<void>;
  copyFile(fromPath: string, toPath: string): Promise<void>;
}
```

### 2. MinIO Implementation

Create `src/services/MinioStorageService.ts`:

```typescript
import { Client as MinioClient } from 'minio';
import { StorageService } from './StorageService';

export class MinioStorageService implements StorageService {
  private client: MinioClient;
  private bucketPrefix: string;

  constructor(
    endpoint: string,
    accessKey: string,
    secretKey: string,
    useSSL: boolean = false,
    bucketPrefix: string = 'banatie',
  ) {
    this.client = new MinioClient({
      endPoint: endpoint.replace(/^https?:\/\//, ''),
      port: useSSL ? 443 : 9000,
      useSSL,
      accessKey,
      secretKey,
    });
    this.bucketPrefix = bucketPrefix;
  }

  private getBucketName(orgId: string): string {
    return `${this.bucketPrefix}-${orgId}`;
  }

  private getFilePath(
    userId: string,
    category: 'generated' | 'references' | 'temp',
    fileName: string,
  ): string {
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0');

    return `users/${userId}/${category}/${year}/${month}/${fileName}`;
  }

  // Implementation methods...
}
```

### 3. Database Schema

Create `scripts/init-db.sql`:

```sql
-- Banatie Database Initialization
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- Organizations table
CREATE TABLE organizations (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    name VARCHAR(255) NOT NULL,
    slug VARCHAR(100) UNIQUE NOT NULL,
    settings JSONB DEFAULT '{}',
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Users table
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
    username VARCHAR(100) NOT NULL,
    email VARCHAR(255),
    role VARCHAR(50) DEFAULT 'user',
    settings JSONB DEFAULT '{}',
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(organization_id, username)
);

-- Images table
CREATE TABLE images (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    filename VARCHAR(255) NOT NULL,
    file_path VARCHAR(500) NOT NULL,
    original_prompt TEXT,
    enhanced_prompt TEXT,
    model_used VARCHAR(100),
    file_size BIGINT,
    content_type VARCHAR(100),
    metadata JSONB DEFAULT '{}',
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Upload sessions table (for tracking multi-part uploads)
CREATE TABLE upload_sessions (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    session_data JSONB NOT NULL,
    expires_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Create indexes
CREATE INDEX idx_users_org_id ON users(organization_id);
CREATE INDEX idx_images_user_id ON images(user_id);
CREATE INDEX idx_images_created_at ON images(created_at);
CREATE INDEX idx_upload_sessions_user_id ON upload_sessions(user_id);
CREATE INDEX idx_upload_sessions_expires_at ON upload_sessions(expires_at);

-- Insert demo organization and user
INSERT INTO organizations (id, name, slug) VALUES
    ('00000000-0000-0000-0000-000000000001', 'Demo Organization', 'demo');

INSERT INTO users (id, organization_id, username, role) VALUES
    ('00000000-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000001', 'guest', 'user');
```

## Development Workflow

### Local Development Setup

1. **Clone Repository**

```bash
git clone <repository-url>
cd banatie-service
```

2. **Environment Configuration**

```bash
cp .env.example .env
# Edit .env with development settings
```

3. **Start Development Environment**

```bash
docker-compose up -d
```

4. **Verify Services**

```bash
# Check service status
docker-compose ps

# View logs
docker-compose logs -f app

# Access services
# App: http://localhost:3000
# MinIO Console: http://localhost:9001 (minioadmin/minioadmin)
# PostgreSQL: localhost:5433
```

5. **Development with Hot Reload**

```bash
# Edit source files in src/
# Changes automatically reload in container
```

### Testing Workflow

```bash
# Run tests in development environment
docker-compose exec app pnpm test

# Run with coverage
docker-compose exec app pnpm test:coverage

# Run linting
docker-compose exec app pnpm lint
```

## Production Deployment

### VPS Deployment Process

1. **Prepare VPS Directory**

```bash
# SSH to VPS
ssh usul-vps

# Create Banatie directory
sudo mkdir -p /opt/banatie
sudo chown usul:usul /opt/banatie
cd /opt/banatie
```

2. **Clone and Configure**

```bash
# Clone repository
git clone <repository-url> .

# Create production environment
cp .env.example .env
# Edit .env with production settings and secure passwords
```

3. **Generate Secure Credentials**

```bash
# Generate secure passwords
DB_PASSWORD=$(openssl rand -base64 32 | tr -d '\n\r ')
MINIO_ACCESS_KEY=$(openssl rand -base64 20 | tr -d '\n\r ')
MINIO_SECRET_KEY=$(openssl rand -base64 40 | tr -d '\n\r ')
JWT_SECRET=$(openssl rand -base64 64 | tr -d '\n\r ')

# Add to .env file
echo "DB_PASSWORD=$DB_PASSWORD" >> .env
echo "MINIO_ACCESS_KEY=$MINIO_ACCESS_KEY" >> .env
echo "MINIO_SECRET_KEY=$MINIO_SECRET_KEY" >> .env
echo "JWT_SECRET=$JWT_SECRET" >> .env

# Secure the file
chmod 600 .env
```

4. **Update Caddy Configuration**

```bash
# Add Banatie routes to Caddyfile
sudo nano /opt/services/configs/caddy/Caddyfile
# Add the Banatie configuration from above

# Reload Caddy
cd /opt/services
./manage-services.sh caddy reload
```

5. **Deploy Services**

```bash
cd /opt/banatie

# Build and start services
docker-compose up -d

# Verify deployment
docker-compose ps
docker-compose logs -f
```

6. **Verify Deployment**

```bash
# Check health endpoints
curl https://banatie.app/health
curl https://minio.banatie.app/minio/health/live

# Check logs
docker-compose logs banatie-app
docker-compose logs banatie-postgres
docker-compose logs banatie-minio
```

### Manual Update Process

```bash
# SSH to VPS
ssh usul-vps
cd /opt/banatie

# Pull latest changes
git pull origin main

# Rebuild and restart
docker-compose build banatie-app
docker-compose up -d

# Verify update
docker-compose logs -f banatie-app
curl https://banatie.app/health
```

## Monitoring and Maintenance

### Health Checks

**Application Health Check** (`/health`):

```json
{
  "status": "healthy",
  "timestamp": "2024-01-01T12:00:00.000Z",
  "services": {
    "database": "connected",
    "minio": "connected",
    "gemini_api": "accessible"
  },
  "version": "1.0.0"
}
```

**MinIO Health Check** (`/minio/health/live`):

- Returns 200 OK when MinIO is operational
- Used by Docker healthcheck and monitoring

### Log Management

**Application Logs**:

- Location: `/opt/banatie/logs/`
- Format: Structured JSON
- Rotation: Daily with 30-day retention

**Access Logs**:

- Caddy logs: `/opt/services/logs/banatie_*.log`
- Format: JSON with request/response details

### Backup Strategy

**Database Backup**:

```bash
# Create backup
docker exec banatie-postgres pg_dump -U banatie_user banatie_db > banatie_db_backup.sql

# Restore backup
docker exec -i banatie-postgres psql -U banatie_user banatie_db < banatie_db_backup.sql
```

**MinIO Data Backup**:

```bash
# Backup MinIO data
sudo tar -czf banatie_minio_backup.tar.gz -C /opt/banatie/data minio/

# Restore MinIO data
sudo tar -xzf banatie_minio_backup.tar.gz -C /opt/banatie/data
```

## Security Considerations

### Container Security

- Non-root users in containers
- Read-only root filesystems where possible
- Resource limits (memory, CPU)
- Health checks for automatic restart

### Network Security

- Internal network isolation
- No direct external access to database or MinIO
- Rate limiting at proxy level
- HTTPS-only external access

### Data Security

- Encrypted environment variables
- Secure secret generation
- Regular credential rotation
- Audit logging

### Access Control

- MinIO bucket policies per organization
- PostgreSQL row-level security
- JWT-based API authentication
- Role-based access control

## Future Scalability

### Horizontal Scaling Options

- Multiple Banatie app containers behind load balancer
- MinIO distributed mode for storage scaling
- PostgreSQL read replicas for read scaling
- Redis for session storage and caching

### Multi-Region Deployment

- Regional MinIO clusters
- Database replication
- CDN integration for static assets
- Geo-distributed deployment

## Troubleshooting

### Common Issues

**Container Won't Start**:

```bash
# Check logs
docker-compose logs [service-name]

# Check resource usage
docker stats

# Rebuild container
docker-compose build [service-name]
docker-compose up -d [service-name]
```

**Database Connection Issues**:

```bash
# Test database connectivity
docker exec banatie-postgres pg_isready -U banatie_user -d banatie_db

# Check environment variables
docker exec banatie-app env | grep DB_

# Restart database
docker-compose restart banatie-postgres
```

**MinIO Access Issues**:

```bash
# Check MinIO status
docker exec banatie-minio mc admin info local

# Test S3 API
curl -f http://localhost:9000/minio/health/live

# Check access keys
docker exec banatie-app env | grep MINIO_
```

**Network Connectivity**:

```bash
# Check networks
docker network ls
docker network inspect banatie_banatie-network

# Test internal connectivity
docker exec banatie-app ping banatie-postgres
docker exec banatie-app ping banatie-minio
```

---

**Document Version**: 1.0
**Last Updated**: 2024-09-26
**Maintained By**: Banatie Development Team
