user_id (transactions, goals, profiles, farm_sessions, alert_rules, alerts, recommendations). In SaaS mode every query is scoped by the authenticated user_id; PostgreSQL Row-Level Security enforces it as a second line.sources.commercial_ok gates what may be served publicly.
| Source | Public SaaS use |
|---|---|
| Everloot (CC BY-SA) | ✅ with attribution; derived datasets must be CC BY-SA |
| auctionhouse.fyi | ⛔ until written permission |
| ForeverDB | ⛔ ("don't resell") — user-key, user-only |
| Blizzard API | per Blizzard Developer API Terms (no resale of raw data) |
| Users' addon scans | ✅ only with explicit opt-in consent per user; aggregated, seller names never collected |[Desktop app] --sync (opt-in)--> [API gateway (FastAPI, same routers)] --> [Postgres + TimescaleDB]
| (observations hypertable,
+--> [Worker: collectors, engines] continuous aggregates)
+--> [Notifier: email, webhooks]
+--> [Billing: Stripe] [Auth: OIDC (Battle.net login optional)]
user_id.plans, subscriptions, usage_counters tables): Free (scanner, calculator, 1 portfolio), Premium (predictions, alerts, full history, advanced crafting, strategies), Trader Pro (multi-market, deep research agents, advanced portfolio, reports). Enforcement by a dependency require_plan("premium") on routers + per-plan rate limits (token bucket in Redis — only justified at multi-instance scale)./v1/markets/{m}/items/{id} etc., API keys per user, quotas per plan, only commercial_ok sources.source_health), collector lag, engine latency, model metrics (already in model_registry/predictions) exported to Prometheus/Grafana.api.py into routers/ with a get_user() dependency (local: always 'local').db.connect for SQLAlchemy Core with dialect switch (SQLite local / Postgres SaaS); schema identical, hypertable on observations(observed_at).sync endpoints: desktop pushes ledger deltas (event-sourced, idempotent by client UUID), pulls shared market history.Tiers listed above; prices to be tested with the community as requested — not fixed here.