# Banatie REST API Implementation Plan

**Version:** 2.0
**Status:** Ready for Implementation
**Executor:** Claude Code
**Database Schema:** v2.0 (banatie-database-design.md)

---

## Overview

REST API for Banatie image generation service. All endpoints use `/api/v1/` prefix for versioning.

**Core Features:**
- AI image generation with Google Gemini Flash
- Dual alias system (project-scoped + flow-scoped)
- Technical aliases (@last, @first, @upload)
- Flow-based generation chains
- Live generation endpoint with caching
- Upload and reference images

**Authentication:** API keys only (`bnt_` prefix)

---

## Authentication

All endpoints require API key in header:

```
X-API-Key: bnt_xxx...
```

**API Key Types:**
- `master`: Full access to all projects in organization
- `project`: Access to specific project only

**Unauthorized Response (401):**
```json
{
  "error": "Unauthorized",
  "message": "Invalid or missing API key"
}
```

---

## Implementation Phases

### Phase 1: Foundation
**Goal:** Core utilities and services

**Tasks:**
- Create TypeScript type definitions for all models
- Build validation utilities (alias format, pagination, query params)
- Build helper utilities (pagination, hash, query helpers)
- Create `AliasService` with 3-tier resolution (technical → flow → project)

**Git Commit:**
```
feat: add foundation utilities and alias service
```

---

### Phase 2: Core Generation Flow
**Goal:** Main generation endpoints

**Services:**
- `ImageService` - CRUD operations with soft delete
- `GenerationService` - Full lifecycle management

**Endpoints:**
- `POST /api/v1/generations` - Create with reference images & dual aliases
- `GET /api/v1/generations` - List with filters
- `GET /api/v1/generations/:id` - Get details with related data

**Git Commit:**
```
feat: implement core generation endpoints
```

---

### Phase 3: Flow Management
**Goal:** Flow operations

**Services:**
- `FlowService` - CRUD with computed counts & alias management

**Endpoints:**
- `POST /api/v1/flows` - Create flow
- `GET /api/v1/flows` - List flows with computed counts
- `GET /api/v1/flows/:id` - Get details with generations and images
- `PUT /api/v1/flows/:id/aliases` - Update flow aliases
- `DELETE /api/v1/flows/:id/aliases/:alias` - Remove specific alias
- `DELETE /api/v1/flows/:id` - Delete flow

**Git Commit:**
```
feat: implement flow management endpoints
```

---

### Phase 4: Enhanced Image Management
**Goal:** Complete image operations

**Endpoints:**
- `POST /api/v1/images/upload` - Upload with alias, flow, metadata
- `GET /api/v1/images` - List with filters
- `GET /api/v1/images/:id` - Get details with usage info
- `GET /api/v1/images/resolve/:alias` - Resolve alias with precedence
- `PUT /api/v1/images/:id` - Update metadata
- `DELETE /api/v1/images/:id` - Soft/hard delete

**Git Commit:**
```
feat: implement image management endpoints
```

---

### Phase 5: Generation Refinements
**Goal:** Additional generation operations

**Endpoints:**
- `POST /api/v1/generations/:id/retry` - Retry failed generation
- `DELETE /api/v1/generations/:id` - Delete generation

**Git Commit:**
```
feat: add generation retry and delete endpoints
```

---

### Phase 6: Live Generation
**Goal:** URL-based generation with caching

**Services:**
- `PromptCacheService` - SHA-256 caching with hit tracking

**Endpoints:**
- `GET /api/v1/live` - Generate image via URL with streaming proxy

**Important:** Stream image directly from MinIO (no 302 redirect) for better performance.

**Git Commit:**
```
feat: implement live generation endpoint with caching
```

---

### Phase 7: Analytics
**Goal:** Project statistics and metrics

**Services:**
- `AnalyticsService` - Aggregation queries

**Endpoints:**
- `GET /api/v1/analytics/summary` - Project statistics
- `GET /api/v1/analytics/generations/timeline` - Time-series data

**Git Commit:**
```
feat: add analytics endpoints
```

---

### Phase 8: Testing & Documentation
**Goal:** Quality assurance

**Tasks:**
- Unit tests for all services (target >80% coverage)
- Integration tests for critical flows
- Error handling consistency review
- Update API documentation

**Git Commit:**
```
test: add comprehensive test coverage and documentation
```

---

## API Endpoints Specification

### GENERATIONS

#### POST /api/v1/generations

Create new image generation.

**Request Body:**
```typescript
{
  prompt: string;                    // Required: 1-2000 chars
  aspectRatio?: string;              // Optional: '16:9', '1:1', '4:3', '9:16'
  width?: number;                    // Optional: 1-8192
  height?: number;                   // Optional: 1-8192
  referenceImages?: string[];        // Optional: ['@logo', '@product', '@last']
  flowId?: string;                   // Optional: Add to existing flow
  assignAlias?: string;              // Optional: Project-scoped alias '@brand'
  assignFlowAlias?: string;          // Optional: Flow-scoped alias '@hero' (requires flowId)
  meta?: Record<string, unknown>;
}
```

**Response (200):**
```typescript
{
  generation: Generation;
  image?: Image;                     // If generation completed
}
```

**Errors:** 400, 401, 404, 422, 429, 500

---

#### GET /api/v1/generations

List generations with filtering.

**Query Params:**
```typescript
{
  flowId?: string;
  status?: 'pending' | 'processing' | 'success' | 'failed';
  limit?: number;                    // Default: 20, max: 100
  offset?: number;                   // Default: 0
  sortBy?: 'createdAt' | 'updatedAt';
  order?: 'asc' | 'desc';            // Default: desc
}
```

**Response (200):**
```typescript
{
  generations: Generation[];
  pagination: PaginationInfo;
}
```

---

#### GET /api/v1/generations/:id

Get generation details.

**Response (200):**
```typescript
{
  generation: Generation;
  image?: Image;
  referencedImages: Image[];
  flow?: FlowSummary;
}
```

---

#### POST /api/v1/generations/:id/retry

Retry failed generation.

**Response (200):**
```typescript
{
  generation: Generation;            // New generation with incremented retry_count
}
```

**Errors:** 404, 422

---

#### DELETE /api/v1/generations/:id

Delete generation.

**Query Params:**
```typescript
{
  hard?: boolean;                    // Default: false
}
```

**Response (204):** No content

---

### IMAGES

#### POST /api/v1/images/upload

Upload image file.

**Request:** multipart/form-data

**Fields:**
```typescript
{
  file: File;                        // Required, max 5MB
  alias?: string;                    // Project-scoped: '@logo'
  flowAlias?: string;                // Flow-scoped: '@hero' (requires flowId)
  flowId?: string;
  description?: string;
  tags?: string[];                   // JSON array as string
  focalPoint?: string;               // JSON: '{"x":0.5,"y":0.5}'
  meta?: string;                     // JSON object as string
}
```

**Response (201):**
```typescript
{
  image: Image;
  flow?: FlowSummary;                // If flowAlias assigned
}
```

**Errors:** 400, 409, 422

---

#### GET /api/v1/images

List images.

**Query Params:**
```typescript
{
  flowId?: string;
  source?: 'generated' | 'uploaded';
  alias?: string;
  limit?: number;                    // Default: 20, max: 100
  offset?: number;
  sortBy?: 'createdAt' | 'fileSize';
  order?: 'asc' | 'desc';
}
```

**Response (200):**
```typescript
{
  images: Image[];
  pagination: PaginationInfo;
}
```

---

#### GET /api/v1/images/:id

Get image details.

**Response (200):**
```typescript
{
  image: Image;
  generation?: Generation;
  usedInGenerations: GenerationSummary[];
}
```

---

#### GET /api/v1/images/resolve/:alias

Resolve alias to image.

**Query Params:**
```typescript
{
  flowId?: string;                   // Provide flow context
}
```

**Response (200):**
```typescript
{
  image: Image;
  scope: 'flow' | 'project' | 'technical';
  flow?: FlowSummary;
}
```

**Resolution Order:**
1. Technical aliases (@last, @first, @upload) if flowId provided
2. Flow aliases from flows.aliases if flowId provided
3. Project aliases from images.alias

**Errors:** 404

---

#### PUT /api/v1/images/:id

Update image metadata.

**Request Body:**
```typescript
{
  alias?: string;
  description?: string;
  tags?: string[];
  focalPoint?: { x: number; y: number };
  meta?: Record<string, unknown>;
}
```

**Response (200):**
```typescript
{
  image: Image;
}
```

**Errors:** 404, 409, 422

---

#### DELETE /api/v1/images/:id

Delete image.

**Query Params:**
```typescript
{
  hard?: boolean;                    // Default: false
}
```

**Response (204):** No content

---

### FLOWS

#### POST /api/v1/flows

Create new flow.

**Request Body:**
```typescript
{
  meta?: Record<string, unknown>;
}
```

**Response (201):**
```typescript
{
  flow: Flow;
}
```

---

#### GET /api/v1/flows

List flows.

**Query Params:**
```typescript
{
  limit?: number;                    // Default: 20, max: 100
  offset?: number;
  sortBy?: 'createdAt' | 'updatedAt';
  order?: 'asc' | 'desc';
}
```

**Response (200):**
```typescript
{
  flows: Array<Flow & {
    generationCount: number;         // Computed
    imageCount: number;              // Computed
  }>;
  pagination: PaginationInfo;
}
```

---

#### GET /api/v1/flows/:id

Get flow details.

**Response (200):**
```typescript
{
  flow: Flow;
  generations: Generation[];         // Ordered by created_at ASC
  images: Image[];
  resolvedAliases: Record<string, Image>;
}
```

---

#### PUT /api/v1/flows/:id/aliases

Update flow aliases.

**Request Body:**
```typescript
{
  aliases: Record<string, string>;   // { "@hero": "image-uuid" }
}
```

**Response (200):**
```typescript
{
  flow: Flow;
}
```

**Validation:**
- Keys must match `^@[a-zA-Z0-9_-]+$`
- Values must be valid image UUIDs
- Cannot use reserved: @last, @first, @upload

**Errors:** 404, 422

---

#### DELETE /api/v1/flows/:id/aliases/:alias

Remove specific alias from flow.

**Response (204):** No content

**Errors:** 404

---

#### DELETE /api/v1/flows/:id

Delete flow.

**Response (204):** No content

**Note:** Cascades to images, sets NULL on generations.flow_id

---

### LIVE GENERATION

#### GET /api/v1/live

Generate image via URL with caching and streaming.

**Query Params:**
```typescript
{
  prompt: string;                    // Required
  aspectRatio?: string;
  width?: number;
  height?: number;
  reference?: string | string[];     // '@logo' or ['@logo','@style']
}
```

**Response:** Image stream with headers

**Headers:**
```
Content-Type: image/jpeg
Cache-Control: public, max-age=31536000
X-Cache-Status: HIT | MISS
```

**Implementation:**
1. Compute cache key: SHA256(prompt + sorted params)
2. Check prompt_url_cache table
3. If HIT: increment hit_count, stream from MinIO
4. If MISS: generate, cache, stream from MinIO
5. Stream image bytes directly (no 302 redirect)

**Errors:** 400, 404, 500

---

### ANALYTICS

#### GET /api/v1/analytics/summary

Get project statistics.

**Query Params:**
```typescript
{
  startDate?: string;                // ISO 8601
  endDate?: string;
  flowId?: string;
}
```

**Response (200):**
```typescript
{
  period: { startDate: string; endDate: string };
  metrics: {
    totalGenerations: number;
    successfulGenerations: number;
    failedGenerations: number;
    successRate: number;
    totalImages: number;
    uploadedImages: number;
    generatedImages: number;
    avgProcessingTimeMs: number;
    totalCacheHits: number;
    cacheHitRate: number;
    totalCost: number;
  };
  flows: FlowSummary[];
}
```

---

#### GET /api/v1/analytics/generations/timeline

Get generation statistics over time.

**Query Params:**
```typescript
{
  startDate?: string;
  endDate?: string;
  flowId?: string;
  groupBy?: 'hour' | 'day' | 'week'; // Default: day
}
```

**Response (200):**
```typescript
{
  data: Array<{
    timestamp: string;
    total: number;
    successful: number;
    failed: number;
    avgProcessingTimeMs: number;
  }>;
}
```

---

## Implementation Guidelines

### Alias Resolution Algorithm

**Priority Order:**
1. Technical aliases (@last, @first, @upload) - compute from flow data
2. Flow-scoped aliases - from flows.aliases JSONB
3. Project-scoped aliases - from images.alias column

**Technical Aliases:**
- `@last`: Latest generation output in flow (any status)
- `@first`: First generation output in flow
- `@upload`: Latest uploaded image in flow

### Dual Alias Assignment

When creating generation or uploading image:
- `assignAlias` → set images.alias (project scope)
- `assignFlowAlias` → add to flows.aliases (flow scope)
- Both can be assigned simultaneously

### Flow Updates

Update `flows.updated_at` on:
- New generation created with flowId
- New image uploaded with flowId
- Flow aliases modified

### Audit Trail

Track `api_key_id` in:
- `images.api_key_id` - who uploaded/generated
- `generations.api_key_id` - who requested

### Rate Limiting

In-memory rate limiting (defer Redis for MVP):
- Master key: 1000 req/hour, 100 generations/hour
- Project key: 500 req/hour, 50 generations/hour

**Headers:**
```
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 487
X-RateLimit-Reset: 1698765432
```

### Error Response Format

```typescript
{
  error: string;
  message: string;
  details?: unknown;
  requestId?: string;
}
```

### MinIO Integration

Use streaming for `/api/v1/live`:
```typescript
const stream = await minioClient.getObject(bucket, storageKey);
res.set('Content-Type', mimeType);
stream.pipe(res);
```

Generate presigned URLs for other endpoints:
```typescript
const url = await minioClient.presignedGetObject(bucket, storageKey, 24 * 60 * 60);
```

---

## Validation Rules

**Alias Format:**
- Pattern: `^@[a-zA-Z0-9_-]+$`
- Reserved: @last, @first, @upload
- Length: 3-100 chars

**File Upload:**
- Max size: 5MB
- MIME types: image/jpeg, image/png, image/webp
- Max dimensions: 8192x8192

**Prompt:**
- Min: 1 char
- Max: 2000 chars

**Aspect Ratio:**
- Pattern: `^\d+:\d+$`
- Examples: 16:9, 1:1, 4:3, 9:16

---

## Service Architecture

### Core Services

**AliasService:**
- Resolve aliases with 3-tier precedence
- Compute technical aliases
- Validate alias format

**ImageService:**
- CRUD operations
- Soft delete support
- Usage tracking

**GenerationService:**
- Generation lifecycle
- Status transitions
- Error handling
- Retry logic

**FlowService:**
- Flow CRUD
- Alias management
- Computed counts

**PromptCacheService:**
- Cache key computation (SHA-256)
- Hit tracking
- Cache lookup

**AnalyticsService:**
- Aggregation queries
- Time-series grouping

### Reusable Utilities

**Validators:**
- Alias format
- Pagination params
- Query filters

**Helpers:**
- Pagination builder
- SHA-256 hashing
- Query helpers

---

## Testing Requirements

**Unit Tests:**
- All services must have unit tests
- Target coverage: >80%
- Mock database calls

**Integration Tests:**
- Critical flows end-to-end
- Real database transactions
- API endpoint testing with supertest

**Test Scenarios:**
- Alias resolution precedence
- Flow-scoped vs project-scoped aliases
- Technical alias computation
- Dual alias assignment
- Cache hit/miss behavior
- Error handling
- Rate limiting

---

## Success Criteria

✅ All endpoints functional per specification
✅ >80% test coverage on services
✅ Consistent error handling across all endpoints
✅ All validation rules implemented
✅ Rate limiting working
✅ Documentation updated
✅ Git commits after each phase

---

*Document Version: 2.0*
*Created: 2025-11-09*
*Target: Claude Code Implementation*
*Database Schema: v2.0*
