> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pindeck.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# RustFS storage

> Configure RustFS as persistent storage for Pindeck media

# RustFS storage

Pindeck stores durable media in RustFS. Uploads may land in Convex temporarily, but originals, previews, and derivatives are persisted through the RustFS media API.

## Required environment

Set these in the Convex backend environment:

| Variable                      | Description                                              |
| ----------------------------- | -------------------------------------------------------- |
| `MEDIA_GATEWAY_URL`           | RustFS media API URL, normally `https://media.v1su4.dev` |
| `MEDIA_GATEWAY_TOKEN`         | Bearer token used for writes and deletes                 |
| `MEDIA_GATEWAY_BUCKET`        | RustFS bucket, normally `pindeck`                        |
| `MEDIA_GATEWAY_USER_ID`       | Media API user namespace, normally `pindeck`             |
| `MEDIA_GATEWAY_UPLOAD_PREFIX` | Object prefix, normally `media-uploads`                  |
| `PINDECK_STORAGE_PROVIDER`    | Set to `rustfs`                                          |

## Object layout

Pindeck writes to the `pindeck` bucket with object keys rooted at `media-uploads/`:

```text theme={null}
media-uploads/YYYY/MM_DD/original/<file>
media-uploads/YYYY/MM_DD/preview/<file>-preview.<ext>
media-uploads/YYYY/MM_DD/low/<file>-w320.<ext>
media-uploads/YYYY/MM_DD/high/<file>-w1280.<ext>
media-uploads/YYYY/MM_DD/high/<file>-w1920.<ext>
```

Public URLs should use:

```text theme={null}
https://s3.v1su4.dev/pindeck/media-uploads/...
```

## Color sampling contract

Every image entering the upload review flow must have five sampled colors before tags are rendered or the item is finalized.

* Local uploads sample colors in the browser before metadata is applied.
* RustFS `/process-image` returns `colors` with the original, preview, and derivative URLs.
* Convex server-side palette jobs first try `sharp`; if `sharp` is unavailable on the runtime, they call RustFS `/palette`.
* VLM-provided colors are metadata only and must not replace sampled image colors.

## Discord ingest

Discord imports use the same pipeline. Reacting with the configured pin emoji queues the source image, Convex persists the image through the RustFS media API, then moderation/generation continues from the RustFS-backed URLs.

After a Discord import is approved, it enters the same `Review & Finalize` draft lane as a local upload. At that point the draft row should already have:

* RustFS original, preview, and derivative URLs
* five sampled colors
* AI title, description, tags, category, group, style, shot, and project fields
* the same `Generate Variations` control used by local uploads
