2.8 KiB
Implementation Plan: M2 Market Web
Branch: 002-market-web | Date: 2026-07-02 | Spec: spec.md
Summary
One Coolify-deployed container: FastAPI backend that proxies the three live rails (memory-api catalog, m2-ledger, Forgejo registry) with keys server-side, serving a React/Vite SPA. Read-only + install handoff. Rides the proven CI/CD (push → deploy), http-scheme domain market.machinemachine.ai.
Technical Context
Language: Python 3.12 (FastAPI, httpx) + TypeScript React 18/Vite
Storage: none (stateless proxy; session cookie is signed, in-memory secret)
Testing: pytest for the backend proxy (httpx MockTransport per upstream, secrets-
leak test asserting no key strings in any response); vitest optional for components
Deploy: web/Dockerfile multi-stage (node build → python runtime), Coolify app
m2-market-web, env: FLEET_PASSCODE, SESSION_SECRET, MEMORY_API_URL/KEY,
LEDGER_URL/LEDGER_SERVICE_KEY, FORGEJO_URL/FORGEJO_TOKEN, REGISTRY_REPO
Constraints: constitution I (assembly: existing APIs only, no new rails), II (web is
a surface, never truth), IV (tenant filter server-side, same semantics as CLI reader), VI
(no secrets in image; runtime env)
Constitution Check
Passes: no new services beyond the (sanctioned-as-surface) web app itself; all data derived from registry/ledger/catalog; keys never leave the backend; read-only economy. Deviation: none.
Project Structure
web/
├── backend/
│ ├── src/m2_market_web/
│ │ ├── main.py # FastAPI app: static serve + /api/* + /health
│ │ ├── auth.py # FLEET_PASSCODE login -> signed session cookie
│ │ ├── catalog.py # /api/search, /api/listing/{id} (memory-api proxy,
│ │ │ # tenant filter — mirror cli catalog.py semantics)
│ │ ├── ledger.py # /api/wallet/{op}, /api/economy (balances+audit links)
│ │ └── registry.py # /api/governance (open PRs+labels, listings+status)
│ ├── tests/
│ └── pyproject.toml # uv workspace member
├── frontend/ # Vite + React + TS, dark navy/cyan (mm brand)
│ ├── src/{pages,components,api.ts}
│ └── package.json
└── Dockerfile
Sequencing
- Backend proxy + tests [P with 2] → 2. Frontend SPA [P with 1] (against a typed /api contract defined in contracts/web-api.md) → 3. Dockerfile + Coolify app + domain + webhook → 4. Live verification vs SC-101..105.
Contract
contracts/web-api.md (written with tasks): /api/login {passcode}; /api/search?q=&limit=;
/api/listing/{id}; /api/wallet/{operator}; /api/economy; /api/governance; /health.
Every /api/* except /health and /login requires the session cookie. Responses are
minimal DTOs — never raw upstream bodies (leak surface).