CI / test (push) Failing after 35s
Add a cache-optimized multi-stage Dockerfile with non-root runtime, compose service definitions for local/dev execution, CI Go version alignment, and docs/path cleanup updates. Made-with: Cursor
7.3 KiB
7.3 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| geo-auth-backend-plan | Design and implement a Go + PostgreSQL(PostGIS) backend with Ed25519 auth, hybrid invitation onboarding, and per-user GeoJSON feature-collection management; plus a no-build Vue/Vuetify frontend for key lifecycle and API usage. |
|
false |
Geo App Auth + GeoJSON Service Plan
Current Project Context
- No existing backend source files were found in this repository root, so this plan assumes a greenfield implementation.
- Stack confirmed: Go + PostgreSQL (+ PostGIS).
- Invitation model confirmed: Hybrid (signed token + inviter lineage tracking).
- Client scope confirmed: both a reusable TS library and a plain JS frontend integration.
- Build policy confirmed: npm/build allowed for library package only; frontend remains no npm/no bundling.
Architecture
- Auth identity: user identity = Ed25519 public key (
base64url); server never stores private keys. - Login/auth: wallet-style challenge-response:
- client requests nonce
- client signs nonce with private key
- server verifies signature against registered public key
- server returns short-lived access token + optional refresh token.
- Registration via invitation:
- inviter generates signed invitation payload (invitee pubkey optional at creation time)
- invite token includes inviter key, expiry, nonce/jti, usage constraints, and lineage metadata
- invitee submits invite token + own pubkey + signature proof
- server verifies inviter trust chain + token signature + replay protection.
- Data model: users own feature collections; each collection owns GeoJSON Features (initially Point geometry).
- Storage: PostGIS geometry column (
geometry(Point, 4326)) plus raw GeoJSON JSONB for roundtrip fidelity.
flowchart TD
inviter[ExistingUserInviter] -->|"signs invite token"| inviteToken[InviteToken]
invitee[NewUserInvitee] -->|"submits pubkey + signed challenge + token"| api[GoAPI]
api -->|"verify inviter + token + signature"| users[(Users)]
api -->|"issue access token"| session[(Sessions)]
invitee -->|"CRUD collections/features"| api
api --> collections[(FeatureCollections)]
api --> features[(FeaturesPostGIS)]
Planned Files and Components
- Backend bootstrap:
cmd/api/main.gointernal/http/routes.gointernal/config/config.go
- Auth/invitation domain:
internal/auth/challenge.gointernal/auth/ed25519_verify.gointernal/invite/token.gointernal/invite/service.go
- Geo domain:
internal/geo/collections_service.gointernal/geo/features_service.go
- Database:
migrations/0001_init_users_invites.sqlmigrations/0002_geo_collections_features.sql
- Frontend (no npm/bundling):
web/index.htmlweb/app.jsweb/api.js
- Reusable TypeScript client library (separate package):
libs/geo-api-client/package.jsonlibs/geo-api-client/tsconfig.jsonlibs/geo-api-client/src/GeoApiClient.tslibs/geo-api-client/src/keys.tslibs/geo-api-client/src/storage.tslibs/geo-api-client/dist/(build output consumed by frontend)
API Surface (v1)
POST /v1/auth/challenge-> noncePOST /v1/auth/login-> verify signature, issue tokenPOST /v1/auth/register-> invite validation + pubkey registrationPOST /v1/invitations-> inviter creates signed invite payloadGET /v1/me/keys-> registered pubkey metadataPOST /v1/collections/GET /v1/collectionsPOST /v1/collections/{id}/features/GET /v1/collections/{id}/featuresPATCH/DELETE /v1/features/{id}
Security and Validation
- Enforce strict canonical payload format before signature verification.
- Replay protection with nonce/jti tables and TTL.
- Invite expiration + max use + optional binding to target pubkey.
- Per-user row-level authorization in service layer (and optionally DB RLS later).
- Input validation for GeoJSON (
Feature,Point, lon/lat ranges, SRID 4326).
Frontend Constraints Implementation
- Serve Vue + Vuetify from CDN (no npm, no bundling).
- Key lifecycle in browser via client library:
- generate Ed25519 keypair using
@noble/ed25519in TS client - precreate key material when first profile/session is initialized
- store key material in
localStoragethrough client helper API (with optional encryption passphrase layer) - import/export profile key material from user settings page.
- generate Ed25519 keypair using
- UI pages: Login/Register (invite), Collections list, Mapless Feature editor (Point first), Profile key management.
TypeScript API Client Library Scope
- Export
GeoApiClientclass for all API communication:createChallenge(),loginWithSignature(),registerWithInvitation()createInvitation()- collection/feature CRUD methods.
- Export key-management helpers:
generateKeyPair(),signChallenge(),exportKeys(),importKeys()ensureKeysInStorage()for precreate-on-first-use behavior.
- Add request signing conventions compatible with backend challenge/invitation verification.
- Build to browser-consumable ESM/UMD artifacts; frontend uses built JS file directly without bundling.
TDD-first Delivery Slices
- Auth challenge + login signature verification tests.
- Invitation token verification + replay/expiry tests.
- Registration tests (happy path + invalid inviter chain).
- Geo collection ownership tests.
- GeoJSON point validation + CRUD tests.
- TS client unit tests (
@noble/ed25519flows, storage, API error handling). - Frontend key-management smoke tests (manual + scripted API checks via JS wrapper).
Acceptance Criteria
- Only registered public keys can authenticate and access their own data.
- New user registration succeeds only with valid inviter lineage and signed token.
- Users can create/read/update/delete their own feature collections and Point features as GeoJSON.
- Reusable TS API client class handles auth + geo API communication and key lifecycle with
@noble/ed25519. - Frontend runs as static files without build tooling, consuming prebuilt client bundle, and supports key import/export + local persistence.