# CLAUDE.md

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:

- **API Service** (`apps/api-service`) - Core REST API using Express.js and TypeScript for image generation with Gemini AI
- **Landing Page** (`apps/landing`) - Next.js public website with demo functionality
- **Studio Platform** (`apps/studio`) - Next.js SaaS application with authentication, billing, and subscriptions. Based on https://github.com/nextjs/saas-starter
- **Admin Dashboard** (`apps/admin`) - Next.js administration interface for monitoring and management

The project uses MinIO for object storage and PostgreSQL for data persistence, all orchestrated with Docker Compose.

## Development Commands

The project has **two separate environments**:

### Development Mode (Local API + Docker Infrastructure)

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 build` - Build all applications
- `pnpm lint` - Run ESLint on all applications
- `pnpm typecheck` - Run TypeScript checking on all applications
- `pnpm test` - Run tests
- `pnpm clean` - Clean all build outputs and dependencies

## Architecture

### Monorepo Structure

```
banatie-service/
├── apps/
│   ├── 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)
├── 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/`)

- **Express App**: Configured in `src/app.ts` with middleware, CORS, and route mounting
- **Server Entry**: `src/server.ts` starts the HTTP server
- **Database Client**: `src/db.ts` - Drizzle ORM connection to PostgreSQL
- **Authentication**: `src/services/ApiKeyService.ts` - API key management and validation
- **Image Generation**: `src/services/ImageGenService.ts` - Gemini AI integration
- **Storage**: `src/services/MinioStorageService.ts` - File uploads to MinIO
- **Route Handling**:
  - `src/routes/bootstrap.ts` - Bootstrap initial master key (one-time)
  - `src/routes/admin/keys.ts` - API key management (master key required)
  - `src/routes/textToImage.ts` - Image generation endpoint (API key required)
  - `src/routes/upload.ts` - File upload endpoint (project key required)
  - `src/routes/images.ts` - Image serving endpoint (public)

### Middleware Stack (API Service)

- `src/middleware/upload.ts` - Multer configuration for file uploads (max 3 reference images, 5MB each; single file upload for `/api/upload`)
- `src/middleware/validation.ts` - Express-validator for request validation
- `src/middleware/errorHandler.ts` - Centralized error handling and 404 responses
- `src/middleware/auth/validateApiKey.ts` - API key authentication
- `src/middleware/auth/requireMasterKey.ts` - Master key authorization
- `src/middleware/auth/rateLimiter.ts` - Rate limiting per API key (100 req/hour)

### TypeScript Configuration (API Service)

- Path aliases configured in `apps/api-service/tsconfig.json`:
  - `@/*` maps to `src/*`
  - `@/types/*` maps to `src/types/*`
  - `@/services/*` maps to `src/services/*`
  - `@/middleware/*` maps to `src/middleware/*`
  - `@/routes/*` maps to `src/routes/*`
  - `@/utils/*` maps to `src/utils/*`

### Storage & Data

- **MinIO**: Object storage for generated images and uploads (port 9000)
- **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`
- **File Organization**: `orgId/projectId/category/year-month/filename.ext`

### Database Package (`packages/database/`)

Shared Drizzle ORM package used by API service and future apps:

- **Schema**: `src/schema/apiKeys.ts` - API keys table definition
- **Client Factory**: `src/client.ts` - Database connection creator
- **Migrations**: `migrations/` - SQL migration files
- **Configuration**: `drizzle.config.ts` - Drizzle Kit configuration

Key table: `api_keys`

- Stores hashed API keys (SHA-256)
- Two types: `master` (admin, never expires) and `project` (90-day expiration)
- Soft delete via `is_active` flag
- Audit trail with `createdBy`, `lastUsedAt`, `createdAt`

## 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)

Used by Docker Compose services (MinIO, Postgres, API container). Key differences from local:

- `DATABASE_URL=postgresql://banatie_user:banatie_secure_password@postgres:5432/banatie_db` (Docker network hostname)
- `MINIO_ENDPOINT=minio:9000` (Docker network hostname)
- `MINIO_ROOT_USER` and `MINIO_ROOT_PASSWORD` - MinIO admin credentials
- All variables are passed to the app container via docker-compose.yml environment section

### Development `.env` (`apps/api-service/.env`)

Used when running `pnpm dev` locally (connects to Docker via port forwarding):

- `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

- `DATABASE_URL` - PostgreSQL connection string
- `GEMINI_API_KEY` - Google Gemini API key (required)
- `MINIO_ENDPOINT` - MinIO endpoint
- `MINIO_ACCESS_KEY` - MinIO service account key (`banatie_service`)
- `MINIO_SECRET_KEY` - MinIO service account secret (`banatie_service_key_2024`)
- `MINIO_BUCKET_NAME` - Storage bucket name (default: `banatie`)
- `MINIO_ROOT_USER` - MinIO admin user (`banatie_admin`)
- `MINIO_ROOT_PASSWORD` - MinIO admin password
- `PORT` - Server port (default: 3000)
- `NODE_ENV` - Environment mode
- `CORS_ORIGIN` - CORS origin setting

## Key Dependencies

### API Service

- **@banatie/database** - Shared database package (workspace dependency)
- **@google/genai** - Google Gemini AI client
- **drizzle-orm** - TypeScript ORM (via database package)
- **postgres** - PostgreSQL client for Node.js (via database package)
- **express** v5 - Web framework
- **multer** - File upload handling
- **minio** - MinIO client for object storage
- **express-validator** - Request validation
- **winston** - Logging
- **helmet** - Security middleware

### Database Package

- **drizzle-orm** - TypeScript ORM for SQL databases
- **drizzle-kit** - CLI tools for migrations
- **postgres** - PostgreSQL client for Node.js

### Frontend Apps (Next.js)

- **next** - React framework
- **tailwindcss** - Utility-first CSS framework
- **typescript** - Type safety
- **supabase** - Authentication and database (studio app)
- **stripe** - Payment processing (studio app)

## Service Ports

| Service         | Port | Description        |
| --------------- | ---- | ------------------ |
| API Service     | 3000 | REST API endpoints |
| Landing Page    | 3001 | Public website     |
| Studio Platform | 3002 | SaaS application   |
| Admin Dashboard | 3003 | Administration     |
| PostgreSQL      | 5460 | Database           |
| MinIO API       | 9000 | Object storage     |
| MinIO Console   | 9001 | Storage management |

## API Endpoints (API Service)

### Public Endpoints (No Authentication)

- `GET /health` - Health check with uptime and status
- `GET /api/info` - API information and limits
- `POST /api/bootstrap/initial-key` - Create first master key (one-time only)

### Admin Endpoints (Master Key Required)

- `POST /api/admin/keys` - Create new API keys (master or project)
- `GET /api/admin/keys` - List all API keys
- `DELETE /api/admin/keys/:keyId` - Revoke an API key

### Protected Endpoints (API Key Required)

- `POST /api/text-to-image` - Generate images from text only (JSON)
- `POST /api/upload` - Upload single image file to project storage
- `GET /api/images/generated` - List generated images

**Authentication**: All protected endpoints require `X-API-Key` header

## Authentication Setup

### First-Time Setup

1. **Start Services**: `docker compose up -d`
2. **Create Master Key**:

   ```bash
   curl -X POST http://localhost:3000/api/bootstrap/initial-key
   ```

   Save the returned key securely!

3. **Create Project Key** (for testing):
   ```bash
   curl -X POST http://localhost:3000/api/admin/keys \
     -H "X-API-Key: YOUR_MASTER_KEY" \
     -H "Content-Type: application/json" \
     -d '{"type": "project", "projectId": "test", "name": "Test Key"}'
   ```

### Using API Keys

```bash
# Image generation with project key
curl -X POST http://localhost:3000/api/text-to-image \
  -H "X-API-Key: YOUR_PROJECT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a sunset",
    "filename": "test_image"
  }'

# File upload with project key
curl -X POST http://localhost:3000/api/upload \
  -H "X-API-Key: YOUR_PROJECT_KEY" \
  -F "file=@image.png"
```

### Key Management

- **Master Keys**: Never expire, can create/revoke other keys, admin access
- **Project Keys**: Expire in 90 days, for image generation only
- **Rate Limits**: 100 requests per hour per key
- **Revocation**: Soft delete via `is_active` flag

## Production Deployment

### VPS Infrastructure

Banatie is deployed as an isolated ecosystem on VPS at `/opt/banatie/`:

| Service | URL | Container |
|---------|-----|-----------|
| Landing | https://banatie.app | banatie-landing |
| API | https://api.banatie.app | banatie-api |
| MinIO Console | https://storage.banatie.app | banatie-minio |
| MinIO CDN | https://cdn.banatie.app | banatie-minio |

### Deploy Scripts

```bash
# From project root
./scripts/deploy-landing.sh           # Deploy landing
./scripts/deploy-landing.sh --no-cache # Force rebuild (when deps change)
./scripts/deploy-api.sh               # Deploy API
./scripts/deploy-api.sh --no-cache    # Force rebuild
```

### Production Configuration Files

```
infrastructure/
├── docker-compose.production.yml  # VPS docker-compose
├── .env.example                   # Environment variables template
└── secrets.env.example            # Secrets template
```

### Key Production Learnings

1. **NEXT_PUBLIC_* variables** - Must be set at build time AND runtime for Next.js client-side code
2. **pnpm workspaces in Docker** - Symlinks break between stages; use single-stage install with `pnpm --filter`
3. **Docker User NS Remapping** - VPS uses UID offset 165536; container UID 1001 → host UID 166537
4. **DATABASE_URL encoding** - Special characters like `=` must be URL-encoded (`%3D`)

### Known Production Issues (Non-Critical)

1. **Healthcheck showing "unhealthy"** - Alpine images lack curl; services work correctly
2. **Next.js cache permission** - `.next/cache` may show EACCES; non-critical for functionality

See [docs/deployment.md](docs/deployment.md) for full deployment guide.

## Development Notes

- Uses pnpm workspaces for monorepo management (required >= 8.0.0)
- Node.js >= 18.0.0 required
- TypeScript with strict mode enabled across all apps
- 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 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)
