diff --git a/docs/api/image-generation.md b/docs/api/image-generation.md index 2c8eb60..097eef3 100644 --- a/docs/api/image-generation.md +++ b/docs/api/image-generation.md @@ -238,7 +238,8 @@ Get a single generation with full details. "outputImageId": "7c4ccf47-41ce-4718-afbc-8c553b2c631a", "outputImage": { "id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a", - "storageUrl": "http://localhost:9000/banatie/default/project-id/generated/image.png", + "storageKey": "default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a", + "storageUrl": "https://cdn.banatie.app/default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a", "mimeType": "image/png", "width": 1792, "height": 1024, @@ -305,13 +306,16 @@ Delete a generation and its output image. | Field | Type | Description | |-------|------|-------------| -| `id` | string | Image UUID | -| `storageUrl` | string | Direct URL to image file | +| `id` | string | Image UUID (same as filename in storage) | +| `storageKey` | string | Storage path: `{org}/{project}/img/{imageId}` | +| `storageUrl` | string | CDN URL: `https://cdn.banatie.app/{org}/{project}/img/{imageId}` | | `mimeType` | string | Image MIME type | | `width` | number | Image width in pixels | | `height` | number | Image height in pixels | | `fileSize` | number | File size in bytes | +> **Note:** The image filename in storage equals `image.id` (UUID). No file extension is used - Content-Type is stored in object metadata. + --- ## Error Codes diff --git a/docs/api/images-upload.md b/docs/api/images-upload.md index 26c6d53..65e509a 100644 --- a/docs/api/images-upload.md +++ b/docs/api/images-upload.md @@ -53,8 +53,8 @@ curl -X POST http://localhost:3000/api/v1/images/upload \ "id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a", "projectId": "57c7f7f4-47de-4d70-9ebd-3807a0b63746", "flowId": null, - "storageKey": "default/project-id/uploads/2025-11/logo.png", - "storageUrl": "http://localhost:9000/banatie/default/project-id/uploads/logo.png", + "storageKey": "default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a", + "storageUrl": "https://cdn.banatie.app/default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a", "mimeType": "image/png", "fileSize": 45678, "width": 512, @@ -68,6 +68,8 @@ curl -X POST http://localhost:3000/api/v1/images/upload \ } ``` +> **Note:** The `id` field equals the filename in storage (UUID). Original filename is preserved in object metadata. + ### flowId Behavior | Value | Behavior | @@ -182,8 +184,8 @@ GET /api/v1/images/@hero?flowId=flow-123 "id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a", "projectId": "57c7f7f4-47de-4d70-9ebd-3807a0b63746", "flowId": null, - "storageKey": "default/project-id/uploads/2025-11/logo.png", - "storageUrl": "http://localhost:9000/banatie/.../logo.png", + "storageKey": "default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a", + "storageUrl": "https://cdn.banatie.app/default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a", "mimeType": "image/png", "fileSize": 45678, "width": 512, @@ -304,11 +306,11 @@ Permanently delete an image and its storage file. | Field | Type | Description | |-------|------|-------------| -| `id` | string | Image UUID | +| `id` | string | Image UUID (same as filename in storage) | | `projectId` | string | Project UUID | | `flowId` | string | Associated flow UUID (null if none) | -| `storageKey` | string | Internal storage path | -| `storageUrl` | string | **Direct URL to access image** | +| `storageKey` | string | Storage path: `{org}/{project}/img/{imageId}` | +| `storageUrl` | string | CDN URL: `https://cdn.banatie.app/{org}/{project}/img/{imageId}` | | `mimeType` | string | Image MIME type | | `fileSize` | number | File size in bytes | | `width` | number | Image width in pixels | @@ -325,32 +327,40 @@ Permanently delete an image and its storage file. ### Accessing Images -Use `storageUrl` for direct image access: +Use `storageUrl` for direct CDN access: ```html - + + + + + ``` -For public CDN access, see [Live URLs](live-url.md). +> **Note:** UUID URLs are served directly from MinIO (fast, cacheable). Alias URLs require API resolution. --- ## Storage Organization -Images are organized in MinIO storage: +Images are stored in MinIO with a simplified path structure: ``` bucket/ - {orgId}/ - {projectId}/ - uploads/ # Uploaded images - 2025-11/ - image.png - generated/ # AI-generated images - 2025-11/ - gen_abc123.png + {orgSlug}/ + {projectSlug}/ + img/ + {imageId} # UUID, no file extension + {imageId} # Content-Type in object metadata + ... ``` +**Key points:** +- **Filename = Image ID (UUID)** - No file extensions +- **Content-Type** stored in MinIO object metadata +- **Original filename** preserved in metadata for reference +- **Single `img/` directory** for all images (generated + uploaded) + --- ## Error Codes diff --git a/docs/api/live-url.md b/docs/api/live-url.md index b902eb8..191ce74 100644 --- a/docs/api/live-url.md +++ b/docs/api/live-url.md @@ -4,15 +4,39 @@ Public CDN endpoints for image serving and live URL generation. For authenticate --- +## URL Architecture + +All images are accessible via CDN at `https://cdn.banatie.app`: + +| URL Pattern | Description | Routing | +|-------------|-------------|---------| +| `/{org}/{proj}/img/{uuid}` | Direct image by UUID | Caddy → MinIO (public) | +| `/{org}/{proj}/img/@{alias}` | Image by alias | Caddy → API → MinIO | +| `/{org}/{proj}/live/{scope}?prompt=...` | Live generation | Caddy → API → MinIO | + +**Key points:** +- **UUID URLs** are permanent and directly cacheable (Cloudflare edge cache) +- **Alias URLs** resolve through API (allows dynamic reassignment) +- **Live URLs** generate on-demand with prompt-based caching + +**Example URLs:** +``` +https://cdn.banatie.app/default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a +https://cdn.banatie.app/default/my-project/img/@hero-banner +https://cdn.banatie.app/default/my-project/live/hero?prompt=mountain+sunset +``` + +--- + ## CDN Image Serving ``` -GET /cdn/:orgSlug/:projectSlug/img/:filenameOrAlias +GET /cdn/:orgSlug/:projectSlug/img/:imageIdOrAlias ``` **Authentication:** None - Public endpoint -Serve images by filename or project-scoped alias. +Serve images by UUID (imageId) or project-scoped alias. **Path Parameters:** @@ -20,18 +44,20 @@ Serve images by filename or project-scoped alias. |-----------|-------------| | `orgSlug` | Organization identifier | | `projectSlug` | Project identifier | -| `filenameOrAlias` | Filename or `@alias` | +| `imageIdOrAlias` | Image UUID or `@alias` | **Examples:** ``` -# By filename -GET /cdn/acme/website/img/hero-background.jpg +# By UUID (direct MinIO access, fastest) +GET /cdn/acme/website/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a -# By alias +# By alias (API resolution, then MinIO) GET /cdn/acme/website/img/@hero ``` +> **Note:** UUID requests are served directly from MinIO (Cloudflare cached). Alias requests require API resolution. + **Response:** Raw image bytes (not JSON) **Response Headers:**