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