# 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: `<publicKey>/<checksum>.<ext>`.
- 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 backend upload URL)
   - `PUT /v1/assets/{id}/upload` (backend streams content to object storage)
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.
