# Assets Storage and Sharing This backend stores metadata for user-owned image and 3D assets and keeps the binary files in S3-compatible object storage. ## Supported asset types - Images: `jpg`, `jpeg`, `png`, `webp` - 3D objects: `gltf`, `glb` ## Data model - Assets are deduplicated per user by `(owner_key, checksum, ext)`. - Canonical object key: `/.`. - A single asset can be linked to many features. - Feature payloads include linked assets under `properties.assets`. Each `properties.assets` item includes: - `id` - `kind` - `name` - `description` - `checksum` - `ext` - `isPublic` - `link` (service-relative path, for example `/v1/assets/{id}/download`) ## API flow 1. Create or reuse an asset record and link it to a feature: - `POST /v1/assets` 2. Upload the binary to object storage: - `POST /v1/assets/{id}/signed-upload` (returns signed PUT URL) 3. Read linked assets from feature responses: - `GET /v1/collections/{id}/features` (`properties.assets`) 4. Download via service-relative link: - `GET /v1/assets/{id}/download` 5. Change visibility: - `PATCH /v1/assets/{id}` with `{"isPublic": false|true}` ## Example asset payload inside a feature ```json { "id": "feature-id", "type": "Feature", "properties": { "name": "Palm Tree Spot", "assets": [ { "id": "asset-id", "kind": "3d", "name": "Palm Tree", "description": "Low-poly tree", "checksum": "abc123...", "ext": "glb", "isPublic": true, "link": "/v1/assets/asset-id/download" } ] } } ``` ## Visibility rules - Owner can always download their own asset. - Other authenticated users can download only when `isPublic=true`. - Owner can toggle `isPublic` at any time. ## Deduplication behavior - Deduplication is per owner and file identity (`owner_key + checksum + ext`). - If the same user submits the same checksum/extension again, backend reuses existing asset metadata. - One asset can be linked to multiple features without duplicating object storage files. ## Spatial readiness for 3D search Feature storage is prepared for future spatial search: - Features keep GeoJSON `geometry` JSON. - Postgres migration also maintains a 3D-capable PostGIS column (`geom geometry(PointZ, 4326)`). - This enables future cube/sphere search without breaking existing API contracts.