Files
aitbc/docs/reference/bootstrap/marketplace_web.md
oib c8be9d7414 feat: add marketplace metrics, privacy features, and service registry endpoints
- Add Prometheus metrics for marketplace API throughput and error rates with new dashboard panels
- Implement confidential transaction models with encryption support and access control
- Add key management system with registration, rotation, and audit logging
- Create services and registry routers for service discovery and management
- Integrate ZK proof generation for privacy-preserving receipts
- Add metrics instru
2025-12-22 10:33:23 +01:00

238 lines
7.3 KiB
Markdown

# marketplace-web
Web app for listing compute **offers**, placing **bids**, and viewing **market stats** in the AITBC stack.
Stage-aware: works **now** against a mock API, later switches to **coordinator/pool-hub/blockchain** endpoints without touching the UI.
## Goals
1. Browse offers (GPU/CPU, price per token, location, queue, latency).
2. Place/manage bids (instant or scheduled).
3. Watch market stats (price trends, filled volume, miner capacity).
4. Wallet view (balance, recent tx; read-only first).
5. Internationalization (EU langs later), dark theme, 960px layout.
## Tech/Structure (Windsurf-friendly)
- Vanilla **TypeScript + Vite** (no React), separate JS/CSS files.
- File layout (desktop 960px grid, mobile-first CSS, dark theme):
```
marketplace-web/
├─ public/
│ ├─ icons/ # favicons, app icons
│ └─ i18n/ # JSON dictionaries (en/… later)
├─ src/
│ ├─ app.ts # app bootstrap/router
│ ├─ router.ts # hash-router (/, /offer/:id, /bids, /stats, /wallet)
│ ├─ api/
│ │ ├─ http.ts # fetch wrapper + baseURL swap (mock → real)
│ │ └─ marketplace.ts # typed API calls
│ ├─ store/
│ │ ├─ state.ts # global app state (signals or tiny pubsub)
│ │ └─ types.ts # shared types/interfaces
│ ├─ views/
│ │ ├─ HomeView.ts
│ │ ├─ OfferDetailView.ts
│ │ ├─ BidsView.ts
│ │ ├─ StatsView.ts
│ │ └─ WalletView.ts
│ ├─ components/
│ │ ├─ OfferCard.ts
│ │ ├─ BidForm.ts
│ │ ├─ Table.ts
│ │ ├─ Sparkline.ts # minimal chart (no external lib)
│ │ └─ Toast.ts
│ ├─ styles/
│ │ ├─ base.css # reset, variables, dark theme
│ │ ├─ layout.css # 960px grid, sections, header/footer
│ │ └─ components.css
│ └─ util/
│ ├─ format.ts # fmt token, price, time
│ ├─ validate.ts # input validation
│ └─ i18n.ts # simple t() loader
├─ index.html
├─ vite.config.ts
└─ README.md
```
## Routes (Hash router)
- `/` — Offer list + filters
- `/offer/:id` — Offer details + **BidForm**
- `/bids` — User bids (open, filled, cancelled)
- `/stats` — Price/volume/capacity charts
- `/wallet` — Balance + last 10 tx (read-only)
## UI/UX Spec
- **Dark theme**, accent = ice-blue/white outlines (fits OIB style).
- **960px max width** desktop, mobile-first, Nothing Phone 2a as reference.
- **Toast** bottom-center for actions.
- Forms: no animations, clear validation, disable buttons during submit.
## Data Types (minimal)
```ts
type TokenAmount = `${number}`; // keep as string to avoid FP errors
type PricePerToken = `${number}`;
interface Offer {
id: string;
provider: string; // miner or pool label
hw: { gpu: string; vramGB?: number; cpu?: string };
region: string; // e.g., eu-central
queue: number; // jobs waiting
latencyMs: number;
price: PricePerToken; // AIToken per 1k tokens processed
minTokens: number;
maxTokens: number;
updatedAt: string;
}
interface BidInput {
offerId: string;
tokens: number; // requested tokens to process
maxPrice: PricePerToken; // cap
}
interface Bid extends BidInput {
id: string;
status: "open" | "filled" | "cancelled" | "expired";
createdAt: string;
filledTokens?: number;
avgFillPrice?: PricePerToken;
}
interface MarketStats {
ts: string[];
medianPrice: number[]; // per interval
filledVolume: number[]; // tokens
capacity: number[]; // available tokens
}
interface Wallet {
address: string;
balance: TokenAmount;
recent: Array<{ id: string; kind: "mint"|"spend"|"refund"; amount: TokenAmount; at: string }>;
}
```
## Mock API (Stage 0)
Base URL: `/.mock` (served via Vite dev middleware or static JSON)
- `GET /.mock/offers.json``Offer[]`
- `GET /.mock/offers/:id.json``Offer`
- `POST /.mock/bids` (body `BidInput`) → `Bid`
- `GET /.mock/bids.json``Bid[]`
- `GET /.mock/stats.json``MarketStats`
- `GET /.mock/wallet.json``Wallet`
Switch to real endpoints by changing **`BASE_URL`** in `api/http.ts`.
## Real API (Stage 2/3/4 wiring)
When coordinator/pool-hub/blockchain are ready:
- `GET /api/market/offers``Offer[]`
- `GET /api/market/offers/:id``Offer`
- `POST /api/market/bids` → create bid, returns `Bid`
- `GET /api/market/bids?owner=<wallet>``Bid[]`
- `GET /api/market/stats?range=24h|7d|30d``MarketStats`
- `GET /api/wallet/summary?addr=<wallet>``Wallet`
Auth header (later): `Authorization: Bearer <session-or-wallet-token>`.
## State & Caching
- In-memory store (`store/state.ts`) with tiny pub/sub.
- Offer list cached 30s; stats cached 60s; bust on route change if stale.
- Optimistic UI for **Bid** create; reconcile on server response.
## Filters (Home)
- Region (multi)
- HW capability (GPU model, min VRAM, CPU present)
- Price range (slider)
- Latency max (ms)
- Queue max
All filters are client-side over fetched offers (server-side later).
## Validation Rules
- `BidInput.tokens``[offer.minTokens, offer.maxTokens]`.
- `maxPrice >= offer.price` for instant fill hint; otherwise place as limit.
- Warn if `queue > threshold` or `latencyMs > threshold`.
## Security Notes (Web)
- Input sanitize; never eval.
- CSRF not needed for read-only; for POST use standard token once auth exists.
- Rate-limit POST (server).
- Display wallet **read-only** unless signing is integrated (later via wallet-daemon).
## i18n
- `public/i18n/en.json` as root.
- `util/i18n.ts` provides `t(key, params?)`.
- Keys only (no concatenated sentences). EU languages can be added later via your i18n tool.
## Accessibility
- Semantic HTML, label every input, focus states visible.
- Keyboard: Tab order, Enter submits forms, Esc closes dialogs.
- Color contrast AA in dark theme.
## Minimal Styling Rules
- `styles/base.css`: CSS variables for colors, spacing, radius.
- `styles/layout.css`: header, main container (max-width: 960px), grid for cards.
- `styles/components.css`: OfferCard, Table, Buttons, Toast.
## Testing
- Manual first:
- Offers list loads, filters act.
- Place bid with edge values.
- Stats sparkline renders with missing points.
- Later: Vitest for `util/` + `api/` modules.
## Env/Config
- `VITE_API_BASE` → mock or real.
- `VITE_DEFAULT_REGION` → optional default filter.
- `VITE_FEATURE_WALLET=readonly|disabled`.
## Build/Run
```
# dev
npm i
npm run dev
# build
npm run build
npm run preview
```
## Migration Checklist (Mock → Real)
1. Replace `VITE_API_BASE` with coordinator gateway URL.
2. Enable auth header injection when session is present.
3. Wire `/wallet` to wallet-daemon read endpoint.
4. Swap stats source to real telemetry.
5. Keep the same types; server must honor them.
## Open Tasks
- [ ] Create file skeletons per structure above.
- [ ] Add mock JSON under `public/.mock/`.
- [ ] Implement OfferCard + filters.
- [ ] Implement BidForm with validation + optimistic UI.
- [ ] Implement StatsView with `Sparkline` (no external chart lib).
- [ ] Wire `VITE_API_BASE` switch.
- [ ] Basic a11y pass + dark theme polish.
- [ ] Wallet view (read-only).