/dashboard2/market-watch. Each panel is either a preset (one of eight pre-built fetchers) or a screen (filter expressed over a single read-only source).
These endpoints are session-authenticated only (Supabase cookie), not Bearer-API. They power the dashboard UI; external automation should use the public/agent APIs.
- Per-route rate limit — same
withRequestLogwrapper as the rest of the dashboard. RPM + monthly hard cap per tier. - Tier panel caps — number of panels you can keep is
market_watch_panel_capfromtier_config. Screen panels have a tighter cap (market_watch_screen_panel_cap). - Per-panel refresh floor — server clamps any
schedule.cadenceMinutestomarket_watch_min_refresh_secondsand a manual refresh has its own per-panel cooldown.
Hydration
private, max-age=60, stale-while-revalidate=300.
Panel fan-out is bounded at pMap(concurrency=4) so even an institutional tier with 200 panels only runs 4 factory calls at a time. Cache hits never reach Postgres.
Create a panel
201 with { "panel": { id, title, kind, status, sortIdx, refreshFloorSeconds } }.
Failures use a stable reason enum:
Presets (v1)
Passpreset.id from this list:
Screen sources
Forkind: "screen", pass sources as an array containing exactly one of:
latest_market_prices; other sources validate but execute as empty.
Update / delete / reorder
{ title, spec, status, sortIdx }. Spec PATCH replaces the full spec — no JSON merge. Cache for the panel is invalidated after commit.
Reorder body: { "order": [{ "id": "...", "sortIdx": 0 }, ...] }. All ids must be owned by the caller, else 404 panel_not_found_or_not_owned.
Manual refresh
SET NX EX, runs the panel with allowStale=false, returns the fresh envelope.
429 with Retry-After:
Tier-gate headers
Every route inherits the dashboard rate-limit headers fromwithRequestLog:
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset— minute window.- On block:
429withRetry-AfterandX-SF-Block-Reason.
Errors and recovery
- Redis outage —
runPanelWithCachefalls through tobypass(factory runs inline, no cache write). Cooldown bypass is graceful too: the panel’srefresh_floor_secondsfloor still gates the cache window once Redis recovers. - Validator failure — never persists. The
reasonenum is stable and safe to surface. - Factory error — recorded in
market_watch_panel_runs.errorplusmarket_watch_panels.last_error. Replays still work via the next refresh.
Admin observability
ADMIN_EMAILS). Returns four aggregates: