# 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; } ``` **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; } ``` **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; } ``` **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; 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; } ``` --- #### PUT /api/v1/flows/:id/aliases Update flow aliases. **Request Body:** ```typescript { aliases: Record; // { "@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*