diff --git a/.gitignore b/.gitignore index 0d337a3..4481851 100644 --- a/.gitignore +++ b/.gitignore @@ -13,12 +13,11 @@ apps/*/dist/ apps/*/.next/ .next/ -# Environment files -.env -.env.local -.env.development.local -.env.test.local -.env.production.local +# Environment files - KEEP .env FILES FOR TRACKING +# We commit .env but ignore local overrides and secrets +.env*.local +secrets.env +.env.production # IDE files .vscode/ @@ -73,7 +72,7 @@ jspm_packages/ .yarn-integrity # dotenv environment variables file -.env +# .env # Generated images and uploads data/storage/ diff --git a/.mcp.json b/.mcp.json index 6e1a357..0da2cd6 100644 --- a/.mcp.json +++ b/.mcp.json @@ -30,7 +30,7 @@ "--access-mode=unrestricted" ], "env": { - "DATABASE_URI": "postgresql://banatie_user:banatie_secure_password@localhost:5434/banatie_db" + "DATABASE_URI": "postgresql://banatie_user:banatie_secure_password@localhost:5460/banatie_db" } }, "mastra": { diff --git a/CLAUDE.md b/CLAUDE.md index bbecfea..630d667 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,6 +2,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +**IMPORTANT**: Always refer to [docs/environment.md](docs/environment.md) for detailed environment configuration, runtime modes, and known issues. Keep that document updated when making infrastructure or configuration changes. + ## Project Overview Banatie is a comprehensive monorepo for AI-powered image generation platform featuring multiple applications: @@ -15,34 +17,37 @@ The project uses MinIO for object storage and PostgreSQL for data persistence, a ## Development Commands -Use `docker compose` command for Docker services (v3 version). +The project has **two separate environments**: -### Infrastructure +### Development Mode (Local API + Docker Infrastructure) -- `docker compose up -d postgres minio storage-init` - Start database and storage services -- `docker compose up -d` - Start all services including the API app container -- `docker compose down` - Stop all services +From `apps/api-service/`: + +```bash +pnpm dev # Start infrastructure + API with hot reload +pnpm infra:up # Start only infrastructure (postgres, minio) +pnpm infra:down # Stop infrastructure +pnpm infra:logs # View infrastructure logs +``` + +### Production Mode (All Services in Docker) + +From `prod-env/`: + +```bash +docker compose up -d # Start all services +docker compose up -d --build # Rebuild and start +docker compose down # Stop all services +docker compose logs -f app # API logs +docker compose logs -f landing # Landing logs +``` ### Monorepo Commands (from root) -- `pnpm dev` - Start all applications in development mode -- `pnpm dev:api` - Start API service only (`apps/api-service`) -- `pnpm dev:landing` - Start landing page only (`apps/landing`) -- `pnpm dev:studio` - Start studio platform only (`apps/studio`) -- `pnpm dev:admin` - Start admin dashboard only (`apps/admin`) - -### Build & Production - - `pnpm build` - Build all applications -- `pnpm build:api` - Build API service only -- `pnpm start:api` - Start API service in production mode -- `pnpm start:landing` - Start landing page in production mode - -### Code Quality (runs across all apps) - - `pnpm lint` - Run ESLint on all applications - `pnpm typecheck` - Run TypeScript checking on all applications -- `pnpm test` - Run tests (currently API service only) +- `pnpm test` - Run tests - `pnpm clean` - Clean all build outputs and dependencies ## Architecture @@ -52,16 +57,25 @@ Use `docker compose` command for Docker services (v3 version). ``` banatie-service/ ├── apps/ -│ ├── api-service/ # Express.js REST API (TypeScript) -│ ├── landing/ # Next.js landing page -│ ├── studio/ # Next.js SaaS platform -│ └── admin/ # Next.js admin dashboard +│ ├── api-service/ # Express.js REST API (TypeScript) +│ │ ├── docker-compose.yml # Dev infrastructure only +│ │ ├── .env # Dev config (localhost) +│ │ └── Dockerfile # Production build +│ ├── landing/ # Next.js landing page +│ │ └── Dockerfile # Production build +│ ├── studio/ # Next.js SaaS platform +│ └── admin/ # Next.js admin dashboard ├── packages/ -│ └── database/ # Shared database package (Drizzle ORM) -├── data/ # Docker volume data (postgres, minio) -├── docker-compose.yml # Infrastructure services -├── pnpm-workspace.yaml # Workspace configuration -└── package.json # Root workspace scripts +│ └── database/ # Shared database package (Drizzle ORM) +├── prod-env/ # Production environment +│ ├── docker-compose.yml # All services (api, landing, infra) +│ ├── .env # Prod config (Docker hostnames) +│ └── README.md # Deployment instructions +├── data/ # Docker volume data (postgres, minio) +├── docs/ +│ └── environment.md # Environment configuration guide +├── pnpm-workspace.yaml # Workspace configuration +└── package.json # Root workspace scripts ``` ### API Service Architecture (`apps/api-service/`) @@ -101,7 +115,7 @@ banatie-service/ ### Storage & Data - **MinIO**: Object storage for generated images and uploads (port 9000) -- **PostgreSQL**: Database for API keys, user data, and metadata (port 5434) +- **PostgreSQL**: Database for API keys, user data, and metadata (port 5460) - Database name: `banatie_db` - User: `banatie_user` - Tables: `api_keys`, `organizations`, `projects`, `users`, `images`, `upload_sessions` @@ -125,6 +139,8 @@ Key table: `api_keys` ## Environment Configuration +**CRITICAL**: See [docs/environment.md](docs/environment.md) for complete configuration details, known issues, and solutions. + **Important**: We use TWO `.env` files with different purposes: ### Root `.env` (Docker Compose Infrastructure) @@ -136,13 +152,30 @@ Used by Docker Compose services (MinIO, Postgres, API container). Key difference - `MINIO_ROOT_USER` and `MINIO_ROOT_PASSWORD` - MinIO admin credentials - All variables are passed to the app container via docker-compose.yml environment section -### API Service `.env` (Local Development Only) +### Development `.env` (`apps/api-service/.env`) -Located at `apps/api-service/.env` - used ONLY when running `pnpm dev:api` locally: +Used when running `pnpm dev` locally (connects to Docker via port forwarding): -- `DATABASE_URL=postgresql://banatie_user:banatie_secure_password@localhost:5434/banatie_db` (port-forwarded) -- `MINIO_ENDPOINT=localhost:9000` (port-forwarded) -- **NOTE**: This file is excluded from Docker builds (see Dockerfile.mono) +- `DATABASE_URL=postgresql://banatie_user:banatie_secure_password@localhost:5460/banatie_db` +- `MINIO_ENDPOINT=localhost:9000` +- **NOTE**: This file is excluded from Docker builds + +### Production `.env` (`prod-env/.env`) + +Used when running `docker compose` in prod-env (internal Docker hostnames): + +- `DATABASE_URL=postgresql://banatie_user:banatie_secure_password@postgres:5432/banatie_db` +- `MINIO_ENDPOINT=minio:9000` +- `IS_DOCKER=true` environment variable is set + +### Secrets (`secrets.env`) + +Sensitive values stored separately (NOT in git): + +- `GEMINI_API_KEY` - Required for image generation +- `MASTER_KEY`, `API_KEY` - Optional testing keys + +See `secrets.env.example` in each directory for template. ### Required Environment Variables @@ -195,7 +228,7 @@ Located at `apps/api-service/.env` - used ONLY when running `pnpm dev:api` local | Landing Page | 3001 | Public website | | Studio Platform | 3002 | SaaS application | | Admin Dashboard | 3003 | Administration | -| PostgreSQL | 5434 | Database | +| PostgreSQL | 5460 | Database | | MinIO API | 9000 | Object storage | | MinIO Console | 9001 | Storage management | @@ -275,4 +308,6 @@ curl -X POST http://localhost:3000/api/upload \ - ESLint configured with TypeScript and Prettier integration - Jest for testing with ts-jest preset (API service) - Each app can be developed and deployed independently -- **Docker**: Uses monorepo-aware Dockerfile (`Dockerfile.mono`) that includes workspace packages +- **Docker**: Uses monorepo-aware Dockerfiles in each app directory +- **Environment**: Two separate configs (dev: `apps/api-service/`, prod: `prod-env/`) +- **Secrets**: Stored in `secrets.env` (not tracked in git) diff --git a/README.md b/README.md index d6d1a63..315f78d 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ See individual app README files for specific environment variables. | Landing Page | 3001 | Public website | | Studio Platform | 3002 | SaaS application | | Admin Dashboard | 3003 | Administration | -| PostgreSQL | 5434 | Database | +| PostgreSQL | 5460 | Database | | MinIO API | 9000 | Object storage | | MinIO Console | 9001 | Storage admin | diff --git a/apps/admin/.env.example b/apps/admin/.env.example index 3584dfe..208cc17 100644 --- a/apps/admin/.env.example +++ b/apps/admin/.env.example @@ -2,7 +2,7 @@ BANATIE_API_URL=http://localhost:3000 # Database Configuration (Direct admin access) -POSTGRES_URL=postgresql://banatie_user:banatie_secure_password@localhost:5434/banatie +POSTGRES_URL=postgresql://banatie_user:banatie_secure_password@localhost:5460/banatie # MinIO Storage Configuration MINIO_ENDPOINT=http://localhost:9000 diff --git a/apps/admin/README.md b/apps/admin/README.md index 45587f2..69948d8 100644 --- a/apps/admin/README.md +++ b/apps/admin/README.md @@ -40,7 +40,7 @@ pnpm dev BANATIE_API_URL=http://localhost:3000 # Database (Direct admin access) -POSTGRES_URL=postgresql://user:password@localhost:5434/banatie +POSTGRES_URL=postgresql://user:password@localhost:5460/banatie # Storage MINIO_ENDPOINT=http://localhost:9000 diff --git a/apps/api-service/.env b/apps/api-service/.env new file mode 100644 index 0000000..eebfd65 --- /dev/null +++ b/apps/api-service/.env @@ -0,0 +1,50 @@ +# Server Configuration +PORT=3000 +NODE_ENV=development + +# CORS Configuration +CORS_ORIGIN=* + +# Database Configuration (connects to Docker via port forwarding) +DATABASE_URL=postgresql://banatie_user:banatie_secure_password@localhost:5460/banatie_db + +# IMPORTANT: Sensitive values should be in secrets.env (not tracked in git) +# See secrets.env.example for required variables like GEMINI_API_KEY + +# MinIO Storage Configuration +STORAGE_TYPE=minio +MINIO_ENDPOINT=localhost:9000 +MINIO_ACCESS_KEY=banatie_service +MINIO_SECRET_KEY=banatie_service_key_2024 +MINIO_USE_SSL=false +MINIO_BUCKET_NAME=banatie +MINIO_PUBLIC_URL=http://localhost:9000 + +# MinIO Admin Configuration (for initialization) +MINIO_ROOT_USER=banatie_admin +MINIO_ROOT_PASSWORD=banatie_storage_secure_key_2024 + +# Multi-tenancy Configuration +DEFAULT_ORG_ID=default +DEFAULT_PROJECT_ID=main +DEFAULT_USER_ID=system + +# API Configuration +API_BASE_URL=http://localhost:3000 +PRESIGNED_URL_EXPIRY=86400 + +# File Upload Configuration +MAX_FILE_SIZE=5242880 +MAX_FILES=3 + +# Directory Configuration +RESULTS_DIR=./results +UPLOADS_DIR=./uploads/temp + +# Logging Configuration +LOG_LEVEL=info +TTI_LOG=logs/tti-log.md +ENH_LOG=logs/enhancing.md + +# REMOVED: Sensitive keys moved to secrets.env +# MASTER_KEY, API_KEY, and GEMINI_API_KEY should be in secrets.env diff --git a/apps/api-service/Dockerfile b/apps/api-service/Dockerfile index 55d2923..a36867c 100644 --- a/apps/api-service/Dockerfile +++ b/apps/api-service/Dockerfile @@ -1,76 +1,90 @@ -# Development stage - for docker-compose development with hot reload -FROM node:20-alpine AS development +# Multi-stage Dockerfile for API Service + +# Stage 1: Dependencies +FROM node:20-alpine AS deps WORKDIR /app -# Install pnpm globally -RUN npm install -g pnpm +# Install pnpm +RUN npm install -g pnpm@10.11.0 -# Copy package files for dependency installation -COPY package*.json pnpm-lock.yaml ./ +# Copy workspace configuration +COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./ + +# Copy package.json files +COPY apps/api-service/package.json ./apps/api-service/ +COPY packages/database/package.json ./packages/database/ + +# Install dependencies RUN pnpm install --frozen-lockfile -# Copy source code -COPY . . - -# Expose port -EXPOSE 3000 - -# Use development command with hot reload -CMD ["pnpm", "dev"] - -# Builder stage - for production build +# Stage 2: Builder FROM node:20-alpine AS builder WORKDIR /app -# Install pnpm globally -RUN npm install -g pnpm +# Install pnpm +RUN npm install -g pnpm@10.11.0 -# Copy package files -COPY package*.json pnpm-lock.yaml ./ +# Copy dependencies from deps stage +COPY --from=deps /app/node_modules ./node_modules +COPY --from=deps /app/apps/api-service/node_modules ./apps/api-service/node_modules +COPY --from=deps /app/packages/database/node_modules ./packages/database/node_modules -# Install all dependencies (including dev dependencies for build) -RUN pnpm install --frozen-lockfile +# Copy workspace files +COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./ -# Copy source code -COPY . . +# Copy database package +COPY packages/database ./packages/database -# Build TypeScript to JavaScript +# Copy API service source (exclude .env - it's for local dev only) +COPY apps/api-service/package.json ./apps/api-service/ +COPY apps/api-service/tsconfig.json ./apps/api-service/ +COPY apps/api-service/src ./apps/api-service/src + +# Set working directory to API service +WORKDIR /app/apps/api-service + +# Build TypeScript RUN pnpm build -# Production stage - optimized final image +# Stage 3: Production Runner FROM node:20-alpine AS production WORKDIR /app -# Create non-root user for security -RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001 +# Install pnpm +RUN npm install -g pnpm@10.11.0 -# Install pnpm globally -RUN npm install -g pnpm +ENV NODE_ENV=production -# Copy package files -COPY --from=builder /app/package*.json ./ +# Create non-root user +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 apiuser + +# Copy workspace configuration +COPY --from=builder /app/pnpm-workspace.yaml ./ +COPY --from=builder /app/package.json ./ COPY --from=builder /app/pnpm-lock.yaml ./ -# Install only production dependencies -RUN pnpm install --prod --frozen-lockfile +# Copy database package +COPY --from=builder /app/packages/database ./packages/database -# Copy built application -COPY --from=builder /app/dist ./dist +# Copy built API service +COPY --from=builder --chown=apiuser:nodejs /app/apps/api-service/dist ./apps/api-service/dist +COPY --from=builder /app/apps/api-service/package.json ./apps/api-service/ -# Create required directories and set ownership -RUN mkdir -p logs && chown -R nodejs:nodejs /app +# Copy node_modules for runtime +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/apps/api-service/node_modules ./apps/api-service/node_modules +COPY --from=builder /app/packages/database/node_modules ./packages/database/node_modules -# Switch to non-root user -USER nodejs +# Create directories for logs and data +RUN mkdir -p /app/apps/api-service/logs /app/results /app/uploads/temp +RUN chown -R apiuser:nodejs /app/apps/api-service/logs /app/results /app/uploads + +USER apiuser -# Expose port EXPOSE 3000 -# Health check -HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ - CMD node -e "require('http').request('http://localhost:3000/health', (res) => { \ - process.exit(res.statusCode === 200 ? 0 : 1) \ - }).on('error', () => process.exit(1)).end()" +WORKDIR /app/apps/api-service -# Start the application -CMD ["node", "dist/server.js"] \ No newline at end of file +# Run production build +CMD ["node", "dist/server.js"] diff --git a/apps/api-service/Dockerfile.mono b/apps/api-service/Dockerfile.mono deleted file mode 100644 index e4d3376..0000000 --- a/apps/api-service/Dockerfile.mono +++ /dev/null @@ -1,30 +0,0 @@ -# Monorepo-aware Dockerfile for API Service -# Development stage - for docker-compose development with hot reload -FROM node:20-alpine AS development -WORKDIR /app - -# Install pnpm globally -RUN npm install -g pnpm@10.11.0 - -# Copy workspace configuration from root -COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./ - -# Copy all workspace packages -COPY packages/ ./packages/ - -# Copy API service (exclude .env file - it's for local dev only) -COPY apps/api-service/package.json ./apps/api-service/ -COPY apps/api-service/tsconfig.json ./apps/api-service/ -COPY apps/api-service/src/ ./apps/api-service/src/ - -# Install all dependencies (workspace-aware) -RUN pnpm install --frozen-lockfile - -# Set working directory to API service -WORKDIR /app/apps/api-service - -# Expose port -EXPOSE 3000 - -# Use development command with hot reload -CMD ["pnpm", "dev"] \ No newline at end of file diff --git a/apps/api-service/docker-compose.yml b/apps/api-service/docker-compose.yml new file mode 100644 index 0000000..2a7020c --- /dev/null +++ b/apps/api-service/docker-compose.yml @@ -0,0 +1,111 @@ +# Development Infrastructure +# This docker-compose.yml starts only infrastructure services (postgres, minio) +# The API service runs locally via `pnpm dev` for hot reload + +services: + # PostgreSQL Database + postgres: + image: postgres:15-alpine + container_name: banatie-postgres-dev + ports: + - "5460:5432" + volumes: + - ../../data/postgres:/var/lib/postgresql/data + - ../../scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql + networks: + - banatie-dev-network + environment: + POSTGRES_DB: banatie_db + POSTGRES_USER: banatie_user + POSTGRES_PASSWORD: banatie_secure_password + healthcheck: + test: ["CMD-SHELL", "pg_isready -U banatie_user -d banatie_db"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + + # MinIO Object Storage - SNMD Mode + minio: + image: quay.io/minio/minio:latest + container_name: banatie-storage-dev + ports: + - "9000:9000" # S3 API + - "9001:9001" # Web Console + volumes: + # SNMD: 4 drives for full S3 compatibility + - ../../data/storage/drive1:/data1 + - ../../data/storage/drive2:/data2 + - ../../data/storage/drive3:/data3 + - ../../data/storage/drive4:/data4 + networks: + - banatie-dev-network + environment: + MINIO_ROOT_USER: banatie_admin + MINIO_ROOT_PASSWORD: banatie_storage_secure_key_2024 + MINIO_BROWSER_REDIRECT_URL: http://localhost:9001 + MINIO_SERVER_URL: http://localhost:9000 + MINIO_DOMAIN: localhost + command: server /data{1...4} --console-address ":9001" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + + # MinIO Storage Initialization + storage-init: + image: minio/mc:latest + container_name: banatie-storage-init-dev + networks: + - banatie-dev-network + depends_on: + minio: + condition: service_healthy + entrypoint: + - /bin/sh + - -c + - | + echo 'Setting up MinIO alias...' + mc alias set storage http://minio:9000 banatie_admin banatie_storage_secure_key_2024 + + echo 'Creating main bucket...' + mc mb --ignore-existing storage/banatie + + echo 'Creating service user...' + mc admin user add storage banatie_service banatie_service_key_2024 + + echo 'Attaching readwrite policy to service user...' + mc admin policy attach storage readwrite --user=banatie_service + + echo 'Setting up lifecycle policy...' + cat > /tmp/lifecycle.json <<'LIFECYCLE' + { + "Rules": [ + { + "ID": "temp-cleanup", + "Status": "Enabled", + "Filter": { + "Prefix": "temp/" + }, + "Expiration": { + "Days": 7 + } + } + ] + } + LIFECYCLE + mc ilm import storage/banatie < /tmp/lifecycle.json + + echo 'Storage initialization completed!' + echo 'Bucket: banatie' + echo 'Dev mode: API service will connect via localhost:9000' + exit 0 + restart: "no" + +networks: + banatie-dev-network: + driver: bridge diff --git a/apps/api-service/package.json b/apps/api-service/package.json index 7c95e8a..399226d 100644 --- a/apps/api-service/package.json +++ b/apps/api-service/package.json @@ -4,7 +4,9 @@ "description": "Nano Banana Image Generation Service - REST API for AI-powered image generation using Gemini Flash Image model", "main": "dist/server.js", "scripts": { - "infra:up": "cd ../.. && docker compose up -d postgres minio storage-init", + "infra:up": "docker compose up -d postgres minio storage-init", + "infra:down": "docker compose down", + "infra:logs": "docker compose logs -f", "dev": "npm run infra:up && echo 'Logs will be saved to api-dev.log' && tsx --watch src/server.ts 2>&1 | tee api-dev.log", "start": "node dist/server.js", "build": "tsc", diff --git a/apps/api-service/secrets.env.example b/apps/api-service/secrets.env.example new file mode 100644 index 0000000..f58cc13 --- /dev/null +++ b/apps/api-service/secrets.env.example @@ -0,0 +1,11 @@ +# secrets.env.example +# Copy this file to secrets.env and fill with real values +# secrets.env is NOT tracked in git for security + +# REQUIRED: Google Gemini API Key for image generation +GEMINI_API_KEY=your_gemini_api_key_here + +# OPTIONAL: For testing purposes (usually generated via API bootstrap) +# These keys will be generated when you first run the API +# MASTER_KEY=will_be_generated_on_bootstrap +# API_KEY=will_be_generated_by_admin_endpoint diff --git a/apps/api-service/src/db.ts b/apps/api-service/src/db.ts index 9e05247..91cb9b9 100644 --- a/apps/api-service/src/db.ts +++ b/apps/api-service/src/db.ts @@ -1,14 +1,24 @@ import { createDbClient } from '@banatie/database'; import { config } from 'dotenv'; import path from 'path'; +import { existsSync } from 'fs'; -// Load .env from api-service directory and OVERRIDE shell env vars -// This is needed because docker-compose sets DATABASE_URL for Docker network -config({ path: path.join(__dirname, '../.env'), override: true }); +// Load .env from api-service directory only if exists and not in Docker +// In Docker (IS_DOCKER=true), environment variables are injected via docker-compose +const envPath = path.join(__dirname, '../.env'); +if (existsSync(envPath) && !process.env['IS_DOCKER']) { + config({ path: envPath }); +} + +// Also load secrets.env if exists (for both dev and docker) +const secretsPath = path.join(__dirname, '../secrets.env'); +if (existsSync(secretsPath)) { + config({ path: secretsPath }); +} const DATABASE_URL = process.env['DATABASE_URL'] || - 'postgresql://banatie_user:banatie_secure_password@localhost:5434/banatie_db'; + 'postgresql://banatie_user:banatie_secure_password@localhost:5460/banatie_db'; export const db = createDbClient(DATABASE_URL); diff --git a/apps/landing/Dockerfile b/apps/landing/Dockerfile new file mode 100644 index 0000000..c26301b --- /dev/null +++ b/apps/landing/Dockerfile @@ -0,0 +1,90 @@ +# Multi-stage Dockerfile for Next.js Landing Page + +# Stage 1: Dependencies +FROM node:20-alpine AS deps +WORKDIR /app + +# Install pnpm +RUN npm install -g pnpm@10.11.0 + +# Copy workspace configuration +COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./ + +# Copy landing package.json +COPY apps/landing/package.json ./apps/landing/ + +# Copy database package (workspace dependency) +COPY packages/database/package.json ./packages/database/ + +# Install dependencies +RUN pnpm install --frozen-lockfile + +# Stage 2: Builder +FROM node:20-alpine AS builder +WORKDIR /app + +# Install pnpm +RUN npm install -g pnpm@10.11.0 + +# Copy dependencies from deps stage +COPY --from=deps /app/node_modules ./node_modules +COPY --from=deps /app/apps/landing/node_modules ./apps/landing/node_modules +COPY --from=deps /app/packages/database/node_modules ./packages/database/node_modules + +# Copy workspace files +COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./ + +# Copy database package +COPY packages/database ./packages/database + +# Copy landing app +COPY apps/landing ./apps/landing + +# Set working directory to landing +WORKDIR /app/apps/landing + +# Build Next.js application +ENV NEXT_TELEMETRY_DISABLED=1 +RUN pnpm build + +# Stage 3: Production Runner +FROM node:20-alpine AS runner +WORKDIR /app + +# Install pnpm +RUN npm install -g pnpm@10.11.0 + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +# Create non-root user +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Copy workspace configuration +COPY --from=builder /app/pnpm-workspace.yaml ./ +COPY --from=builder /app/package.json ./ +COPY --from=builder /app/pnpm-lock.yaml ./ + +# Copy database package +COPY --from=builder /app/packages/database ./packages/database + +# Copy built Next.js application +COPY --from=builder --chown=nextjs:nodejs /app/apps/landing/.next ./apps/landing/.next +COPY --from=builder /app/apps/landing/package.json ./apps/landing/ +COPY --from=builder /app/apps/landing/public ./apps/landing/public + +# Copy node_modules for runtime +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/apps/landing/node_modules ./apps/landing/node_modules +COPY --from=builder /app/packages/database/node_modules ./packages/database/node_modules + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 + +WORKDIR /app/apps/landing + +CMD ["pnpm", "start"] diff --git a/apps/landing/src/lib/db/client.ts b/apps/landing/src/lib/db/client.ts index 0060860..26f43ef 100644 --- a/apps/landing/src/lib/db/client.ts +++ b/apps/landing/src/lib/db/client.ts @@ -4,7 +4,7 @@ import * as schema from '@banatie/database'; const connectionString = process.env.DATABASE_URL || - 'postgresql://banatie_user:banatie_secure_password@localhost:5434/banatie_db'; + 'postgresql://banatie_user:banatie_secure_password@localhost:5460/banatie_db'; // Create postgres client const client = postgres(connectionString); diff --git a/docs/environment.md b/docs/environment.md new file mode 100644 index 0000000..f87d06b --- /dev/null +++ b/docs/environment.md @@ -0,0 +1,398 @@ +# Environment Configuration Guide + +## Overview + +Banatie uses a monorepo structure with **two separate environment configurations**: +- **Development** (`apps/api-service/`) - Infrastructure in Docker, API runs locally +- **Production** (`prod-env/`) - All services run in Docker containers + +--- + +## Services & Ports + +| Service | Port(s) | Description | Container Name | +|-----------------|--------------|------------------------------|----------------------------| +| PostgreSQL | 5460 → 5432 | Database | banatie-postgres(-dev) | +| MinIO API | 9000 → 9000 | Object storage (S3) | banatie-storage(-dev) | +| MinIO Console | 9001 → 9001 | Storage management UI | banatie-storage(-dev) | +| API Service | 3000 → 3000 | REST API (prod only) | banatie-app | +| Landing Page | 3001 → 3000 | Public website (prod only) | banatie-landing | +| Studio Platform | 3002 | SaaS (future) | - | +| Admin Dashboard | 3003 | Administration (future) | - | + +**Port Format**: `host:container` (e.g., `5460:5432` means host port 5460 maps to container port 5432) + +--- + +## Runtime Modes + +### Development Mode (`apps/api-service/`) + +**Use Case**: Active development with hot reload + +**Structure**: +``` +apps/api-service/ +├── docker-compose.yml # Infrastructure only (postgres, minio) +├── .env # Dev config (localhost endpoints) +└── secrets.env # API keys (not in git) +``` + +**Launch**: +```bash +cd apps/api-service +pnpm dev +``` + +**What happens**: +1. Starts infrastructure: postgres, minio (Docker) +2. API runs locally with `tsx --watch` (hot reload) +3. Connects via port forwarding: `localhost:5460`, `localhost:9000` + +**Configuration**: +- Database: `localhost:5460` +- MinIO: `localhost:9000` +- Hot reload enabled +- Uses local `.env` + `secrets.env` + +--- + +### Production Mode (`prod-env/`) + +**Use Case**: Production deployment, local testing + +**Structure**: +``` +prod-env/ +├── docker-compose.yml # All services (postgres, minio, api, landing) +├── .env # Prod config (Docker hostnames) +├── secrets.env # API keys (not in git) +└── README.md # Deployment instructions +``` + +**Launch**: +```bash +cd prod-env +docker compose up -d +``` + +**What happens**: +1. All services run in Docker containers +2. Internal Docker network: `postgres:5432`, `minio:9000` +3. Host access via port forwarding +4. Production-optimized builds + +**Configuration**: +- Database: `postgres:5432` (internal) +- MinIO: `minio:9000` (internal) +- Production build (TypeScript compiled) +- Uses prod `.env` + `secrets.env` + +--- + +## Environment Files + +### Development `.env` (`apps/api-service/.env`) + +**Purpose**: Local development configuration + +```env +# Connects to Docker via port forwarding +DATABASE_URL=postgresql://banatie_user:banatie_secure_password@localhost:5460/banatie_db +MINIO_ENDPOINT=localhost:9000 +``` + +✅ **Committed to git** (no secrets) + +--- + +### Production `.env` (`prod-env/.env`) + +**Purpose**: Production Docker configuration + +```env +# Internal Docker network hostnames +DATABASE_URL=postgresql://banatie_user:banatie_secure_password@postgres:5432/banatie_db +MINIO_ENDPOINT=minio:9000 +``` + +✅ **Committed to git** (no secrets) + +--- + +### Secrets (`secrets.env`) + +**Purpose**: Sensitive API keys and credentials + +```env +# Required +GEMINI_API_KEY=your_key_here + +# Optional (generated by API) +MASTER_KEY=will_be_generated +API_KEY=will_be_generated +``` + +❌ **NOT committed to git** +✅ Template available: `secrets.env.example` + +--- + +## Key Configuration Differences + +| Variable | Dev (`apps/api-service/.env`) | Prod (`prod-env/.env`) | +|----------|-------------------------------|------------------------| +| `DATABASE_URL` | `localhost:5460` | `postgres:5432` | +| `MINIO_ENDPOINT` | `localhost:9000` | `minio:9000` | +| `RESULTS_DIR` | `./results` | `/app/results` | +| `UPLOADS_DIR` | `./uploads/temp` | `/app/uploads/temp` | +| `IS_DOCKER` | not set | `true` | + +--- + +## How db.ts Loads Config + +The `apps/api-service/src/db.ts` file has smart loading: + +```typescript +// 1. Load .env only if NOT in Docker +if (existsSync(envPath) && !process.env['IS_DOCKER']) { + config({ path: envPath }); +} + +// 2. Always load secrets.env if exists +if (existsSync(secretsPath)) { + config({ path: secretsPath }); +} +``` + +- **Dev mode**: Loads `apps/api-service/.env` + `secrets.env` +- **Prod mode**: Uses Docker env vars + `secrets.env` + +--- + +## Docker Network + +- **Network Name**: `banatie-network` (prod), `banatie-dev-network` (dev) +- **Internal DNS**: Containers reach each other by service name +- **Host Access**: Use `localhost` with mapped ports + +--- + +## Database Credentials + +**PostgreSQL**: +- Host (dev): `localhost:5460` +- Host (prod): `postgres:5432` +- Database: `banatie_db` +- User: `banatie_user` +- Password: `banatie_secure_password` + +**MinIO**: +- Endpoint (dev): `http://localhost:9000` +- Endpoint (prod): `http://minio:9000` +- Console: `http://localhost:9001` +- Root User: `banatie_admin` +- Root Password: `banatie_storage_secure_key_2024` +- Service Account: `banatie_service` / `banatie_service_key_2024` +- Bucket: `banatie` + +--- + +## Storage Layout + +**MinIO Structure**: +``` +banatie/ +├── {orgSlug}/ +│ └── {projectSlug}/ +│ ├── generated/ +│ │ └── {year-month}/ +│ │ └── {filename}.{ext} +│ └── uploads/ +│ └── {year-month}/ +│ └── {filename}.{ext} +``` + +**Local Volumes** (both modes): +- Database: `data/postgres/` +- MinIO: `data/storage/drive{1-4}/` (SNMD mode) +- Results: `data/results/` +- Uploads: `data/uploads/` + +--- + +## Quick Commands + +### Development + +```bash +# Start dev environment +cd apps/api-service +pnpm dev + +# Stop infrastructure +pnpm infra:down + +# View logs +pnpm infra:logs +``` + +### Production + +```bash +# Start all services +cd prod-env +docker compose up -d + +# View logs +docker compose logs -f app # API +docker compose logs -f landing # Landing +docker compose logs -f postgres # DB + +# Stop all +docker compose down + +# Rebuild after code changes +docker compose up -d --build +``` + +### Database Access + +```bash +# From host (both modes) +psql -h localhost -p 5460 -U banatie_user -d banatie_db + +# From Docker container (prod only) +docker exec -it banatie-postgres psql -U banatie_user -d banatie_db +``` + +--- + +## Health Checks + +All services have health checks: + +- **PostgreSQL**: `pg_isready -U banatie_user -d banatie_db` +- **MinIO**: `curl -f http://localhost:9000/minio/health/live` + +Intervals: 30s, timeout: 10s, retries: 3, start period: 40s + +--- + +## Troubleshooting + +### Port Already in Use + +Check what's using the port: +```bash +lsof -i :5460 # PostgreSQL +lsof -i :9000 # MinIO +lsof -i :3000 # API +``` + +### Database Connection Refused + +1. Check containers are running: + ```bash + docker ps | grep banatie + ``` + +2. Check health status: + ```bash + docker compose ps # In respective directory + ``` + +3. Verify port in `.env` matches mode: + - Dev: `localhost:5460` + - Prod: `postgres:5432` + +### MinIO Connection Refused + +1. Check MinIO is healthy: + ```bash + docker logs banatie-storage(-dev) + ``` + +2. Verify endpoint in `.env`: + - Dev: `localhost:9000` + - Prod: `minio:9000` + +3. Check storage-init completed: + ```bash + docker logs banatie-storage-init(-dev) + ``` + +### "No such file or directory" for secrets.env + +Create from template: +```bash +# Dev +cd apps/api-service +cp secrets.env.example secrets.env +# Edit with your GEMINI_API_KEY + +# Prod +cd prod-env +cp secrets.env.example secrets.env +# Edit with your GEMINI_API_KEY +``` + +--- + +## Migration Guide + +### From Old Structure to New + +The project was reorganized to separate dev/prod configs: + +**Before**: +``` +/.env # Confusing mix of localhost/docker +/docker-compose.yml # Unclear if dev or prod +``` + +**After**: +``` +/apps/api-service/ + ├── docker-compose.yml # Dev infrastructure + └── .env # Dev config (localhost) + +/prod-env/ + ├── docker-compose.yml # Prod all services + └── .env # Prod config (docker hostnames) +``` + +**Changes**: +1. Port: `5434` → `5460` (everywhere) +2. Secrets: Moved to `secrets.env` (not in git) +3. `db.ts`: Removed `override: true`, added `IS_DOCKER` check +4. Dockerfile: `Dockerfile.mono` → `Dockerfile` + +--- + +## Best Practices + +1. **Never commit `secrets.env`** - Use templates +2. **Use correct config for mode** - Dev vs Prod `.env` +3. **Test locally before deploy** - Use `prod-env` locally +4. **Monitor health checks** - Ensure services are healthy +5. **Backup data directory** - Especially `data/postgres/` + +--- + +## Next Steps + +- ✅ Document environment configuration +- ✅ Separate dev/prod configurations +- ✅ Update port from 5434 to 5460 +- ✅ Move secrets to separate file +- 🔜 Test dev mode +- 🔜 Test prod mode locally +- 🔜 Deploy to VPS + +--- + +**Last Updated**: 2025-01-12 +**Author**: Claude Code +**Version**: 2.0 (Post-reorganization) diff --git a/package.json b/package.json index 3a63764..1bb2655 100644 --- a/package.json +++ b/package.json @@ -10,39 +10,16 @@ "pnpm": ">=8.0.0" }, "scripts": { - "dev": "pnpm --parallel run dev", - "dev:api": "pnpm --filter @banatie/api-service dev", - "dev:landing": "pnpm --filter @banatie/landing dev", - "dev:studio": "pnpm --filter @banatie/studio dev", - "dev:admin": "pnpm --filter @banatie/admin dev", "build": "pnpm -r build", - "build:api": "pnpm --filter @banatie/api-service build", - "build:landing": "pnpm --filter @banatie/landing build", - "build:studio": "pnpm --filter @banatie/studio build", - "build:admin": "pnpm --filter @banatie/admin build", - "start:api": "pnpm --filter @banatie/api-service start", - "start:landing": "pnpm --filter @banatie/landing start", - "start:studio": "pnpm --filter @banatie/studio start", - "start:admin": "pnpm --filter @banatie/admin start", "lint": "pnpm -r lint", - "lint:api": "pnpm --filter @banatie/api-service lint", - "lint:landing": "pnpm --filter @banatie/landing lint", - "lint:studio": "pnpm --filter @banatie/studio lint", - "lint:admin": "pnpm --filter @banatie/admin lint", "typecheck": "pnpm -r typecheck", - "typecheck:api": "pnpm --filter @banatie/api-service typecheck", - "typecheck:landing": "pnpm --filter @banatie/landing typecheck", - "typecheck:studio": "pnpm --filter @banatie/studio typecheck", - "typecheck:admin": "pnpm --filter @banatie/admin typecheck", "test": "vitest", "test:ui": "vitest --ui", "test:run": "vitest run", "test:coverage": "vitest run --coverage", - "test:api": "pnpm --filter @banatie/api-service test", "format": "prettier --write \"apps/**/*.{ts,tsx,js,jsx,json,css,md}\" \"packages/**/*.{ts,tsx,js,jsx,json,css,md}\" \"*.{ts,tsx,js,jsx,json,css,md}\" --ignore-unknown", "format:check": "prettier --check \"apps/**/*.{ts,tsx,js,jsx,json,css,md}\" \"packages/**/*.{ts,tsx,js,jsx,json,css,md}\" \"*.{ts,tsx,js,jsx,json,css,md}\" --ignore-unknown", - "clean": "pnpm -r clean && rm -rf node_modules", - "install:all": "pnpm install" + "clean": "pnpm -r clean && rm -rf node_modules" }, "keywords": [ "monorepo", diff --git a/packages/database/drizzle.config.ts b/packages/database/drizzle.config.ts index 0ffb82a..d375a6d 100644 --- a/packages/database/drizzle.config.ts +++ b/packages/database/drizzle.config.ts @@ -7,6 +7,6 @@ export default { dbCredentials: { url: process.env.DATABASE_URL || - 'postgresql://banatie_user:banatie_secure_password@localhost:5434/banatie_db', + 'postgresql://banatie_user:banatie_secure_password@localhost:5460/banatie_db', }, } satisfies Config; diff --git a/prod-env/.env b/prod-env/.env new file mode 100644 index 0000000..819eeef --- /dev/null +++ b/prod-env/.env @@ -0,0 +1,53 @@ +# Production Environment Configuration +# This file is used when running docker compose in prod-env/ + +# Application Configuration +NODE_ENV=production +PORT=3000 +LOG_LEVEL=info +API_BASE_URL=http://localhost:3000 + +# CORS Configuration +CORS_ORIGIN=* + +# Database Configuration (Docker internal network) +DB_HOST=postgres +DB_PORT=5432 +DB_NAME=banatie_db +DB_USER=banatie_user +DB_PASSWORD=banatie_secure_password +DATABASE_URL=postgresql://banatie_user:banatie_secure_password@postgres:5432/banatie_db + +# MinIO Storage Configuration (Docker internal network) +MINIO_ROOT_USER=banatie_admin +MINIO_ROOT_PASSWORD=banatie_storage_secure_key_2024 +STORAGE_TYPE=minio +MINIO_ENDPOINT=minio:9000 +MINIO_ACCESS_KEY=banatie_service +MINIO_SECRET_KEY=banatie_service_key_2024 +MINIO_USE_SSL=false +MINIO_BUCKET_NAME=banatie +MINIO_PUBLIC_URL=http://localhost:9000 + +# Multi-tenancy Configuration +DEFAULT_ORG_ID=default +DEFAULT_PROJECT_ID=main +DEFAULT_USER_ID=system + +# Presigned URL Configuration +PRESIGNED_URL_EXPIRY=86400 # 24 hours + +# File Upload Configuration +MAX_FILE_SIZE=5242880 # 5MB +MAX_FILES=3 + +# Directory Configuration (Docker paths) +RESULTS_DIR=/app/results +UPLOADS_DIR=/app/uploads/temp + +# Logging Configuration +TTI_LOG=logs/tti-log.md +ENH_LOG=logs/enhancing.md + +# IMPORTANT: Sensitive values should be in secrets.env (not tracked in git) +# See secrets.env.example for required variables diff --git a/prod-env/README.md b/prod-env/README.md new file mode 100644 index 0000000..4d4f554 --- /dev/null +++ b/prod-env/README.md @@ -0,0 +1,191 @@ +# Production Environment + +This directory contains the production Docker Compose configuration for running all Banatie services in containers. + +## Services + +- **API Service** (port 3000) - REST API for image generation +- **Landing Page** (port 3001) - Public website +- **PostgreSQL** (port 5460→5432) - Database +- **MinIO** (ports 9000-9001) - Object storage with S3 compatibility + +## Quick Start + +### 1. Setup Secrets + +```bash +cp secrets.env.example secrets.env +# Edit secrets.env with real values +``` + +Required secrets: +- `GEMINI_API_KEY` - Your Google Gemini API key + +### 2. Start Services + +```bash +# From prod-env directory +docker compose up -d +``` + +### 3. Check Status + +```bash +docker compose ps +docker compose logs -f app # API logs +docker compose logs -f landing # Landing logs +``` + +### 4. Stop Services + +```bash +docker compose down +``` + +## Deployment to VPS + +### Initial Setup + +```bash +# On VPS +cd /path/to/banatie-service +git pull +cd prod-env +cp secrets.env.example secrets.env +# Edit secrets.env with production values +docker compose up -d --build +``` + +### Updates + +```bash +# On VPS +cd /path/to/banatie-service/prod-env +git pull +docker compose up -d --build +``` + +## Environment Variables + +Configuration is split into two files: + +- **`.env`** - Base configuration (committed to git) + - Service endpoints (Docker internal: `postgres:5432`, `minio:9000`) + - Database credentials (development values) + - Storage configuration + - Application settings + +- **`secrets.env`** - Sensitive secrets (NOT committed) + - API keys (Gemini) + - Production passwords (if different) + - Testing keys (optional) + +## Port Mappings + +| Service | Host Port | Container Port | Description | +|------------|-----------|----------------|-----------------------| +| API | 3000 | 3000 | REST API | +| Landing | 3001 | 3000 | Landing page | +| PostgreSQL | 5460 | 5432 | Database | +| MinIO API | 9000 | 9000 | S3-compatible storage | +| MinIO UI | 9001 | 9001 | Web console | + +## Data Persistence + +All data is stored in the parent `data/` directory: + +``` +../data/ +├── postgres/ # Database files +├── storage/ # MinIO storage (4 drives for SNMD) +├── results/ # Generated images +└── uploads/ # Uploaded files +``` + +## Accessing Services + +- **API**: http://localhost:3000 +- **Landing**: http://localhost:3001 +- **MinIO Console**: http://localhost:9001 + - Username: `banatie_admin` + - Password: (from MINIO_ROOT_PASSWORD in .env) + +## Database Access + +Connect to PostgreSQL from host: + +```bash +psql -h localhost -p 5460 -U banatie_user -d banatie_db +``` + +From another Docker container (same network): + +```bash +psql -h postgres -p 5432 -U banatie_user -d banatie_db +``` + +## Troubleshooting + +### Check service health + +```bash +docker compose ps +``` + +### View logs + +```bash +docker compose logs -f # All services +docker compose logs -f app # API only +docker compose logs -f postgres # Database only +``` + +### Restart specific service + +```bash +docker compose restart app +``` + +### Rebuild after code changes + +```bash +docker compose up -d --build +``` + +### Reset everything + +```bash +docker compose down -v # ⚠️ This deletes volumes! +``` + +## Production Considerations + +1. **Secrets Management** + - Never commit `secrets.env` + - Use strong passwords in production + - Rotate API keys regularly + +2. **Database Backups** + - Set up automated backups of `data/postgres/` + - Test restore procedures + +3. **Resource Limits** + - Add memory/CPU limits to docker-compose.yml if needed + - Monitor with `docker stats` + +4. **SSL/TLS** + - Use reverse proxy (nginx/traefik) for HTTPS + - Enable MinIO SSL for production + +5. **Monitoring** + - Set up health check endpoints + - Configure alerts for service failures + +## Development vs Production + +This configuration is for **production** (all services in Docker). + +For **development** (local API, Docker infrastructure): +- Use `apps/api-service/docker-compose.yml` +- Run `pnpm dev` from api-service directory +- Connects to Docker services via `localhost:5460` and `localhost:9000` diff --git a/docker-compose.yml b/prod-env/docker-compose.yml similarity index 67% rename from docker-compose.yml rename to prod-env/docker-compose.yml index 583e79a..e9f2e4f 100644 --- a/docker-compose.yml +++ b/prod-env/docker-compose.yml @@ -1,17 +1,17 @@ - services: + # API Service app: build: - context: . - dockerfile: ./apps/api-service/Dockerfile.mono - target: development + context: .. + dockerfile: apps/api-service/Dockerfile + target: production container_name: banatie-app ports: - "3000:3000" volumes: - - ./apps/api-service/src:/app/apps/api-service/src - - ./apps/api-service/logs:/app/apps/api-service/logs - - ./packages:/app/packages + - ../apps/api-service/logs:/app/apps/api-service/logs + - ../data/results:/app/results + - ../data/uploads:/app/uploads networks: - banatie-network depends_on: @@ -19,40 +19,43 @@ services: condition: service_healthy minio: condition: service_healthy + env_file: + - .env + - secrets.env environment: - - NODE_ENV=development - - DATABASE_URL=${DATABASE_URL} - - GEMINI_API_KEY=${GEMINI_API_KEY} - - STORAGE_TYPE=${STORAGE_TYPE} - - MINIO_ENDPOINT=${MINIO_ENDPOINT} - - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY} - - MINIO_SECRET_KEY=${MINIO_SECRET_KEY} - - MINIO_USE_SSL=${MINIO_USE_SSL} - - MINIO_BUCKET_NAME=${MINIO_BUCKET_NAME} - - MINIO_PUBLIC_URL=${MINIO_PUBLIC_URL} - - API_BASE_URL=${API_BASE_URL} - - DEFAULT_ORG_ID=${DEFAULT_ORG_ID} - - DEFAULT_PROJECT_ID=${DEFAULT_PROJECT_ID} - - DEFAULT_USER_ID=${DEFAULT_USER_ID} - - PRESIGNED_URL_EXPIRY=${PRESIGNED_URL_EXPIRY} - - MAX_FILE_SIZE=${MAX_FILE_SIZE} - - MAX_FILES=${MAX_FILES} - - RESULTS_DIR=${RESULTS_DIR} - - UPLOADS_DIR=${UPLOADS_DIR} - - LOG_LEVEL=${LOG_LEVEL} - - PORT=${PORT} - - CORS_ORIGIN=${CORS_ORIGIN} - - TTI_LOG=${TTI_LOG} + - IS_DOCKER=true + - NODE_ENV=production restart: unless-stopped + # Landing Page + landing: + build: + context: .. + dockerfile: apps/landing/Dockerfile + container_name: banatie-landing + ports: + - "3001:3000" + networks: + - banatie-network + depends_on: + - postgres + env_file: + - .env + - secrets.env + environment: + - IS_DOCKER=true + - NODE_ENV=production + restart: unless-stopped + + # PostgreSQL Database postgres: image: postgres:15-alpine container_name: banatie-postgres ports: - - "5434:5432" + - "5460:5432" volumes: - - ./data/postgres:/var/lib/postgresql/data - - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql + - ../data/postgres:/var/lib/postgresql/data + - ../scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql networks: - banatie-network environment: @@ -67,19 +70,19 @@ services: start_period: 40s restart: unless-stopped - # SNMD MinIO Setup - Production Ready + # MinIO Object Storage - Production Ready with SNMD minio: image: quay.io/minio/minio:latest container_name: banatie-storage ports: - "9000:9000" # S3 API - - "9001:9001" # Console + - "9001:9001" # Web Console volumes: # SNMD: 4 drives for full S3 compatibility and erasure coding - - ./data/storage/drive1:/data1 - - ./data/storage/drive2:/data2 - - ./data/storage/drive3:/data3 - - ./data/storage/drive4:/data4 + - ../data/storage/drive1:/data1 + - ../data/storage/drive2:/data2 + - ../data/storage/drive3:/data3 + - ../data/storage/drive4:/data4 networks: - banatie-network environment: @@ -98,6 +101,7 @@ services: start_period: 40s restart: unless-stopped + # MinIO Storage Initialization storage-init: image: minio/mc:latest container_name: banatie-storage-init @@ -156,4 +160,4 @@ volumes: postgres-data: driver: local storage-data: - driver: local \ No newline at end of file + driver: local diff --git a/prod-env/secrets.env.example b/prod-env/secrets.env.example new file mode 100644 index 0000000..d8e741d --- /dev/null +++ b/prod-env/secrets.env.example @@ -0,0 +1,10 @@ +# secrets.env.example +# Copy this file to secrets.env and fill with real values +# secrets.env is NOT tracked in git for security + +# REQUIRED: Google Gemini API Key for image generation +GEMINI_API_KEY=your_gemini_api_key_here + +# OPTIONAL: For testing purposes (usually generated via API) +# MASTER_KEY=will_be_generated_on_bootstrap +# API_KEY=will_be_generated_by_admin_endpoint