Add asset metadata, sharing, and MinIO-backed signed links.
CI / test (pull_request) Successful in 4s

This introduces deduplicated per-user image/3D asset records linked into feature properties, adds visibility-controlled download routing, and wires local S3-compatible storage with automatic bucket bootstrap in Docker Compose.

Made-with: Cursor
This commit is contained in:
2026-03-02 21:03:08 +00:00
parent 184c5cb59f
commit f6f46f6db1
18 changed files with 1125 additions and 16 deletions
+53
View File
@@ -0,0 +1,53 @@
# 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 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}`
## 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.
## 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.