Add asset metadata, sharing, and MinIO-backed signed links.
CI / test (pull_request) Successful in 4s
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:
@@ -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.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Docker MinIO Local Development
|
||||
|
||||
Local object storage is provided by MinIO in `docker-compose.yml`.
|
||||
|
||||
## Port policy
|
||||
|
||||
- MinIO S3 API (`9000`) is internal-only (not published on host).
|
||||
- MinIO admin UI is exposed on `8774`.
|
||||
|
||||
## Services
|
||||
|
||||
- `minio`: object storage
|
||||
- `minio-init`: one-shot bucket bootstrap using `mc`
|
||||
- `api` / `api-dev`: use MinIO via internal DNS endpoint `minio:9000`
|
||||
|
||||
## Environment variables
|
||||
|
||||
- `S3_ENDPOINT` (default `minio:9000`)
|
||||
- `S3_BUCKET` (default `momswap-assets`)
|
||||
- `S3_REGION` (default `us-east-1`)
|
||||
- `S3_ACCESS_KEY` (default `momswap`)
|
||||
- `S3_SECRET_KEY` (default `momswap-secret`)
|
||||
- `S3_USE_PATH_STYLE` (default `true`)
|
||||
- `S3_USE_TLS` (default `false`)
|
||||
|
||||
## Start stack
|
||||
|
||||
```bash
|
||||
./bin/gen-server-keys.sh
|
||||
docker compose up --build -d
|
||||
```
|
||||
|
||||
## Verify storage setup
|
||||
|
||||
1. Confirm only MinIO UI is published:
|
||||
```bash
|
||||
docker compose ps
|
||||
```
|
||||
2. Open MinIO admin console:
|
||||
- `http://localhost:8774`
|
||||
3. Confirm bucket exists (`momswap-assets` by default).
|
||||
4. Use API flow:
|
||||
- create asset and get signed upload URL
|
||||
- upload file with PUT
|
||||
- request `/v1/assets/{id}/download`
|
||||
Reference in New Issue
Block a user