---
name: geo-auth-backend-plan
overview: 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.
todos:
  - id: bootstrap-go-api
    content: Create greenfield Go API skeleton with config, routing, and health endpoints
    status: pending
  - id: auth-ed25519
    content: Implement challenge-response auth with Ed25519 verification and token issuance
    status: pending
  - id: hybrid-invitations
    content: Implement hybrid invitation issuance/verification with lineage and replay protection
    status: pending
  - id: geo-storage
    content: Add PostGIS-backed models/migrations for collections and point features
    status: pending
  - id: geo-crud-endpoints
    content: Expose authenticated per-user GeoJSON collection/feature CRUD endpoints
    status: pending
  - id: frontend-static-vue
    content: Build no-bundler Vue+Vuetify static frontend with key generation/import/export in localStorage
    status: pending
  - id: tests-and-hardening
    content: Add tests for auth/invites/geo ownership and enforce validation/security checks
    status: pending
  - id: ts-api-client-lib
    content: Create reusable TypeScript API client library with @noble/ed25519 for key generation, key storage helpers, and signed API communication
    status: pending
  - id: js-frontend-wrapper
    content: Add plain JavaScript wrapper adapter so no-build frontend can consume the TypeScript-built client bundle
    status: pending
isProject: 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.

```mermaid
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.go`
  - `internal/http/routes.go`
  - `internal/config/config.go`
- Auth/invitation domain:
  - `internal/auth/challenge.go`
  - `internal/auth/ed25519_verify.go`
  - `internal/invite/token.go`
  - `internal/invite/service.go`
- Geo domain:
  - `internal/geo/collections_service.go`
  - `internal/geo/features_service.go`
- Database:
  - `migrations/0001_init_users_invites.sql`
  - `migrations/0002_geo_collections_features.sql`
- Frontend (no npm/bundling):
  - `web/index.html`
  - `web/app.js`
  - `web/api.js`
- Reusable TypeScript client library (separate package):
  - `libs/geo-api-client/package.json`
  - `libs/geo-api-client/tsconfig.json`
  - `libs/geo-api-client/src/GeoApiClient.ts`
  - `libs/geo-api-client/src/keys.ts`
  - `libs/geo-api-client/src/storage.ts`
  - `libs/geo-api-client/dist/` (build output consumed by frontend)

## API Surface (v1)

- `POST /v1/auth/challenge` -> nonce
- `POST /v1/auth/login` -> verify signature, issue token
- `POST /v1/auth/register` -> invite validation + pubkey registration
- `POST /v1/invitations` -> inviter creates signed invite payload
- `GET /v1/me/keys` -> registered pubkey metadata
- `POST /v1/collections` / `GET /v1/collections`
- `POST /v1/collections/{id}/features` / `GET /v1/collections/{id}/features`
- `PATCH/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/ed25519` in TS client
  - precreate key material when first profile/session is initialized
  - store key material in `localStorage` through client helper API (with optional encryption passphrase layer)
  - import/export profile key material from user settings page.
- UI pages: Login/Register (invite), Collections list, Mapless Feature editor (Point first), Profile key management.

## TypeScript API Client Library Scope

- Export `GeoApiClient` class 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

1. Auth challenge + login signature verification tests.
2. Invitation token verification + replay/expiry tests.
3. Registration tests (happy path + invalid inviter chain).
4. Geo collection ownership tests.
5. GeoJSON point validation + CRUD tests.
6. TS client unit tests (`@noble/ed25519` flows, storage, API error handling).
7. 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.
