This adds typed asset APIs to the geo client, covers the 3D/image upload-share flow in integration tests, and introduces a simple Leaflet web demo that places objects on map features and manages sharing visibility via backend links. Made-with: Cursor
This commit is contained in:
@@ -38,12 +38,42 @@ Each `properties.assets` item includes:
|
||||
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:
|
||||
|
||||
@@ -43,3 +43,30 @@ docker compose up --build -d
|
||||
- create asset and get signed upload URL
|
||||
- upload file with PUT
|
||||
- request `/v1/assets/{id}/download`
|
||||
|
||||
## Quick verification script
|
||||
|
||||
Use this as a smoke-check after startup:
|
||||
|
||||
```bash
|
||||
# 1) check API and MinIO UI reachability
|
||||
curl -fsS http://localhost:8122/healthz
|
||||
curl -I http://localhost:8774
|
||||
|
||||
# 2) ensure MinIO S3 API is not exposed on host
|
||||
if curl -fsS http://localhost:9000/minio/health/live >/dev/null 2>&1; then
|
||||
echo "Unexpected: MinIO S3 API is exposed on host"
|
||||
else
|
||||
echo "OK: MinIO S3 API is internal-only"
|
||||
fi
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- If `api` fails with storage config errors, verify `S3_*` variables in compose environment.
|
||||
- If bucket bootstrap fails, inspect:
|
||||
- `docker compose logs minio`
|
||||
- `docker compose logs minio-init`
|
||||
- If signed URLs are generated but upload fails, check:
|
||||
- object key path style (`S3_USE_PATH_STYLE=true` for MinIO)
|
||||
- MinIO credentials (`S3_ACCESS_KEY`, `S3_SECRET_KEY`)
|
||||
|
||||
@@ -1,60 +1,69 @@
|
||||
# Frontend Development
|
||||
|
||||
Development guide for the Momswap Geo demo app (`web/`) and TypeScript client (`libs/geo-api-client`).
|
||||
Development guide for the demo frontend in `web/` and the reusable TypeScript client in `libs/geo-api-client`.
|
||||
|
||||
## Architecture
|
||||
|
||||
- `web/` is a no-bundler Vue + Vuetify app served directly by the Go backend at `/web/`.
|
||||
- `libs/geo-api-client` contains signed auth and API request logic reused by frontend code.
|
||||
- Asset binaries are stored in S3-compatible storage, while frontend works with metadata and service-relative links returned by the API.
|
||||
|
||||
## Demo app (`web/`)
|
||||
|
||||
Vue 3 + Vuetify 3 single-page app, no bundler. Served by the backend at `/web/`.
|
||||
### File map
|
||||
|
||||
### Structure
|
||||
|
||||
```
|
||||
```text
|
||||
web/
|
||||
├── index.html # Entry page, Vue/Vuetify from CDN
|
||||
├── app.js # Vue app, state, handlers
|
||||
├── api.js # GeoApiClient wrapper for browser
|
||||
├── qr.js # QR code generation (pk/pb keys)
|
||||
└── scanner.js # QR scanner from camera (Import pk)
|
||||
├── index.html # Entry page, loads Vue/Vuetify from CDN
|
||||
├── app.js # Main app state and handlers
|
||||
├── api.js # GeoApiClient wrapper for browser usage
|
||||
├── qr.js # QR code generation for key sharing/backup
|
||||
└── scanner.js # Camera QR scanner for key import
|
||||
```
|
||||
|
||||
### Running locally
|
||||
### Local run
|
||||
|
||||
1. Start the API:
|
||||
1. Start backend:
|
||||
```bash
|
||||
go run ./cmd/api
|
||||
# or: docker compose up -d
|
||||
# or
|
||||
docker compose up -d
|
||||
```
|
||||
2. Open `http://localhost:8122/web/`
|
||||
2. Open:
|
||||
- `http://localhost:8122/web/`
|
||||
- `http://localhost:8122/web/leaflet-demo.html` (Leaflet map demo for 3D/image placement + sharing)
|
||||
|
||||
### Dependencies
|
||||
### Runtime dependencies
|
||||
|
||||
- Vue 3 and Vuetify 3 from CDN (no npm install in `web/`)
|
||||
- `libs/geo-api-client/dist/index.js` — built ESM client
|
||||
- `qr.js` — imports `qrcode` from esm.sh
|
||||
- `scanner.js` — imports `jsQR` from esm.sh for camera scan
|
||||
- Vue 3 and Vuetify 3 from CDN (no package manager in `web/`)
|
||||
- `libs/geo-api-client/dist/index.js` (ESM build artifact)
|
||||
- `qrcode` via `esm.sh` in `qr.js`
|
||||
- `jsQR` via `esm.sh` in `scanner.js`
|
||||
|
||||
### Build step for client
|
||||
### Supported UI flows
|
||||
|
||||
The demo app uses the pre-built client. After changing `libs/geo-api-client`:
|
||||
|
||||
```bash
|
||||
cd libs/geo-api-client
|
||||
bun run build
|
||||
```
|
||||
|
||||
With Docker, the image build runs this automatically.
|
||||
|
||||
### Features (use-cases test)
|
||||
|
||||
- Connection & Identity: API URL, key generation, pk/pb display, QR codes (pk shown by default, pb behind toggle), restore pb from pk, **Import pk from camera** (scan QR → restore pb → auto login → refresh collections), register, login
|
||||
- Collections: create, select, rename, remove
|
||||
- Features: add point (lon/lat validation -180..180, -90..90), remove, list
|
||||
- Connection and identity:
|
||||
- API URL configuration
|
||||
- key generation
|
||||
- pk/pb display and QR export
|
||||
- restore/import keypair from QR
|
||||
- register and login
|
||||
- Collection management:
|
||||
- create, select, rename, delete
|
||||
- Feature management:
|
||||
- add/list/delete points
|
||||
- lon/lat validation (`-180..180`, `-90..90`)
|
||||
- Asset-ready feature rendering:
|
||||
- read linked media from `feature.properties.assets`
|
||||
- use relative `link` value (for example `/v1/assets/{id}/download`) for fetch/open
|
||||
- Leaflet map example:
|
||||
- click map to place object coordinates
|
||||
- create feature + upload/link `gltf`/`glb`/image asset
|
||||
- copy/open share link and toggle public/private visibility
|
||||
|
||||
## TypeScript client (`libs/geo-api-client`)
|
||||
|
||||
Reusable API client with Ed25519 signing. See [TypeScript Frontend Integration](typescript-frontend-integration.md) for full API and integration flow.
|
||||
|
||||
### Build & test
|
||||
The TypeScript client centralizes auth signatures and API requests.
|
||||
|
||||
```bash
|
||||
cd libs/geo-api-client
|
||||
@@ -63,10 +72,20 @@ bun test
|
||||
bun run build
|
||||
```
|
||||
|
||||
After client changes, rebuild before loading the demo app. Docker image builds handle this automatically.
|
||||
|
||||
## Frontend implementation notes for assets
|
||||
|
||||
- Treat `properties.assets` as backend-owned metadata. Do not derive URLs in frontend from S3 config.
|
||||
- Always use backend-provided relative `link` for downloads so permission checks remain server-side.
|
||||
- When asset visibility changes (`isPublic`), refresh affected feature list to keep UI in sync.
|
||||
|
||||
## Related docs
|
||||
|
||||
| Document | Description |
|
||||
|----------|-------------|
|
||||
| [TypeScript Frontend Integration](typescript-frontend-integration.md) | API client usage, integration flow, examples |
|
||||
| [Ed25519 Security Use Cases](ed25519-security-use-cases.md) | Auth flows, registration, signatures |
|
||||
| [Geo Auth Backend Plan](geo-auth-backend-plan.md) | Architecture and planning |
|
||||
| [TypeScript Frontend Integration](typescript-frontend-integration.md) | API client usage and integration flow |
|
||||
| [Assets Storage and Sharing](assets-storage-and-sharing.md) | Asset lifecycle, deduplication, visibility, API endpoints |
|
||||
| [Docker MinIO Local Development](docker-minio-local-dev.md) | Local object storage topology and verification |
|
||||
| [Ed25519 Security Use Cases](ed25519-security-use-cases.md) | Auth and signature behavior |
|
||||
| [Geo Auth Backend Plan](geo-auth-backend-plan.md) | Architecture and planning history |
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
This document explains how frontend developers should integrate with the backend through the reusable TypeScript client at `libs/geo-api-client`.
|
||||
|
||||
> **See also:** [Frontend Development](frontend-development.md) — demo app (`web/`), local dev, build steps.
|
||||
>
|
||||
> **Asset docs:** [Assets Storage and Sharing](assets-storage-and-sharing.md) and [Docker MinIO Local Development](docker-minio-local-dev.md).
|
||||
|
||||
Primary backend URL for integration:
|
||||
|
||||
@@ -76,6 +78,16 @@ Key methods:
|
||||
- [`createPointFeature(collectionId, lon, lat, properties)`](https://git.produktor.io/momswap/backend/src/branch/main/libs/geo-api-client/src/GeoApiClient.ts#L156) — Add a Point. lon ∈ [-180,180], lat ∈ [-90,90]. Returns feature id.
|
||||
- [`deleteFeature(featureId)`](https://git.produktor.io/momswap/backend/src/branch/main/libs/geo-api-client/src/GeoApiClient.ts#L172) — Delete a feature.
|
||||
|
||||
## Asset API integration note
|
||||
|
||||
Asset endpoints are currently available at backend API level (`/v1/assets...`) and can be called from frontend apps directly with authenticated `fetch` requests.
|
||||
|
||||
Current frontend contract points:
|
||||
|
||||
- Feature list responses include linked media under `feature.properties.assets`.
|
||||
- Each asset includes a backend-relative download path (`link`) like `/v1/assets/{id}/download`.
|
||||
- Frontend should use this relative path and avoid constructing direct S3 URLs.
|
||||
|
||||
## Recommended integration flow
|
||||
|
||||
1. Create one `GeoApiClient` instance per backend base URL.
|
||||
|
||||
Reference in New Issue
Block a user