banatie-service/banatie-api-requirements.md

841 lines
15 KiB
Markdown

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