15 KiB
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 organizationproject: Access to specific project only
Unauthorized Response (401):
{
"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
AliasServicewith 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 deleteGenerationService- Full lifecycle management
Endpoints:
POST /api/v1/generations- Create with reference images & dual aliasesGET /api/v1/generations- List with filtersGET /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 flowGET /api/v1/flows- List flows with computed countsGET /api/v1/flows/:id- Get details with generations and imagesPUT /api/v1/flows/:id/aliases- Update flow aliasesDELETE /api/v1/flows/:id/aliases/:alias- Remove specific aliasDELETE /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, metadataGET /api/v1/images- List with filtersGET /api/v1/images/:id- Get details with usage infoGET /api/v1/images/resolve/:alias- Resolve alias with precedencePUT /api/v1/images/:id- Update metadataDELETE /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 generationDELETE /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 statisticsGET /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:
{
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):
{
generation: Generation;
image?: Image; // If generation completed
}
Errors: 400, 401, 404, 422, 429, 500
GET /api/v1/generations
List generations with filtering.
Query Params:
{
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):
{
generations: Generation[];
pagination: PaginationInfo;
}
GET /api/v1/generations/:id
Get generation details.
Response (200):
{
generation: Generation;
image?: Image;
referencedImages: Image[];
flow?: FlowSummary;
}
POST /api/v1/generations/:id/retry
Retry failed generation.
Response (200):
{
generation: Generation; // New generation with incremented retry_count
}
Errors: 404, 422
DELETE /api/v1/generations/:id
Delete generation.
Query Params:
{
hard?: boolean; // Default: false
}
Response (204): No content
IMAGES
POST /api/v1/images/upload
Upload image file.
Request: multipart/form-data
Fields:
{
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):
{
image: Image;
flow?: FlowSummary; // If flowAlias assigned
}
Errors: 400, 409, 422
GET /api/v1/images
List images.
Query Params:
{
flowId?: string;
source?: 'generated' | 'uploaded';
alias?: string;
limit?: number; // Default: 20, max: 100
offset?: number;
sortBy?: 'createdAt' | 'fileSize';
order?: 'asc' | 'desc';
}
Response (200):
{
images: Image[];
pagination: PaginationInfo;
}
GET /api/v1/images/:id
Get image details.
Response (200):
{
image: Image;
generation?: Generation;
usedInGenerations: GenerationSummary[];
}
GET /api/v1/images/resolve/:alias
Resolve alias to image.
Query Params:
{
flowId?: string; // Provide flow context
}
Response (200):
{
image: Image;
scope: 'flow' | 'project' | 'technical';
flow?: FlowSummary;
}
Resolution Order:
- Technical aliases (@last, @first, @upload) if flowId provided
- Flow aliases from flows.aliases if flowId provided
- Project aliases from images.alias
Errors: 404
PUT /api/v1/images/:id
Update image metadata.
Request Body:
{
alias?: string;
description?: string;
tags?: string[];
focalPoint?: { x: number; y: number };
meta?: Record<string, unknown>;
}
Response (200):
{
image: Image;
}
Errors: 404, 409, 422
DELETE /api/v1/images/:id
Delete image.
Query Params:
{
hard?: boolean; // Default: false
}
Response (204): No content
FLOWS
POST /api/v1/flows
Create new flow.
Request Body:
{
meta?: Record<string, unknown>;
}
Response (201):
{
flow: Flow;
}
GET /api/v1/flows
List flows.
Query Params:
{
limit?: number; // Default: 20, max: 100
offset?: number;
sortBy?: 'createdAt' | 'updatedAt';
order?: 'asc' | 'desc';
}
Response (200):
{
flows: Array<Flow & {
generationCount: number; // Computed
imageCount: number; // Computed
}>;
pagination: PaginationInfo;
}
GET /api/v1/flows/:id
Get flow details.
Response (200):
{
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:
{
aliases: Record<string, string>; // { "@hero": "image-uuid" }
}
Response (200):
{
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:
{
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:
- Compute cache key: SHA256(prompt + sorted params)
- Check prompt_url_cache table
- If HIT: increment hit_count, stream from MinIO
- If MISS: generate, cache, stream from MinIO
- Stream image bytes directly (no 302 redirect)
Errors: 400, 404, 500
ANALYTICS
GET /api/v1/analytics/summary
Get project statistics.
Query Params:
{
startDate?: string; // ISO 8601
endDate?: string;
flowId?: string;
}
Response (200):
{
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:
{
startDate?: string;
endDate?: string;
flowId?: string;
groupBy?: 'hour' | 'day' | 'week'; // Default: day
}
Response (200):
{
data: Array<{
timestamp: string;
total: number;
successful: number;
failed: number;
avgProcessingTimeMs: number;
}>;
}
Implementation Guidelines
Alias Resolution Algorithm
Priority Order:
- Technical aliases (@last, @first, @upload) - compute from flow data
- Flow-scoped aliases - from flows.aliases JSONB
- 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/generatedgenerations.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
{
error: string;
message: string;
details?: unknown;
requestId?: string;
}
MinIO Integration
Use streaming for /api/v1/live:
const stream = await minioClient.getObject(bucket, storageKey);
res.set('Content-Type', mimeType);
stream.pipe(res);
Generate presigned URLs for other endpoints:
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