- Add frozen v2 /v1/prices API contract (docs/api-contract-prices.md) - Add ADR 0011: providers best-effort Yahoo (docs/adr/0011-providers-best-effort-yahoo.md) - Add dedicated ADR table section to docs/architecture.md (rows 0001-0011) Closes #154
89 lines
6.5 KiB
Markdown
89 lines
6.5 KiB
Markdown
# ADR 0011 — Providers de prix : exchanges directs (crypto) + Yahoo Finance best-effort (stocks)
|
||
|
||
- Status: Accepted
|
||
- Date: 2026-04-26
|
||
- Successor of: ADR 0009 (architecture proxy) — précise les providers concrets
|
||
- Milestone: `spec-price-fetching` + `prices-proxy` (maximus-api)
|
||
|
||
## Context
|
||
|
||
ADR 0009 a établi qu'un proxy `maximus-api` mutualisé sert le price-fetching premium pour préserver la privacy (IP cachée, headers strippés). La revue spec du contrat `/v1/prices` (2026-04-26) a soulevé deux risques critiques :
|
||
|
||
1. **Yahoo Finance n'a pas d'API publique officielle.** Les endpoints `query1/query2.finance.yahoo.com` sont non documentés, leur ToS interdit l'usage commercial et la redistribution. Un IP-ban du VPS coupe le feature pour 100% des premium en même temps.
|
||
2. **CoinGecko free tier interdit le proxy commercial.** Seul le plan Demo/Pro payant (~129 $/mo Analyst) le permet contractuellement.
|
||
|
||
Quatre options ont été considérées (cf. revue inline `docs/api-contract-prices.md` §0) :
|
||
|
||
| Option | Coût/mois | Légalité commercial | Stabilité | Couverture |
|
||
|--------|-----------|---------------------|-----------|------------|
|
||
| Polygon.io Starter | 29 $ | ✅ contractuelle | ✅ haute | Stocks NYSE/NASDAQ + crypto |
|
||
| Tiingo Power + exchanges directs (crypto) | 10 $ | ✅ Tiingo, ✅ exchanges (public market data OSS-légal) | ✅ haute | Stocks + crypto |
|
||
| **Exchanges directs (crypto) + Yahoo best-effort (stocks)** | **0 $** | ⚠️ Yahoo ToS risqué (data publique mais redistribution interdite) ; ✅ exchanges | ⚠️ Yahoo fragile, exchanges stables | Stocks + crypto |
|
||
| Polygon Stocks + CoinGecko Pro | 158 $ | ✅ | ✅ | Best-of-both |
|
||
|
||
## Decision
|
||
|
||
**Adopter l'option « tout-OSS / best-effort »** pour le MVP :
|
||
|
||
- **Crypto** : interrogation directe des exchanges majeurs via la lib `ccxt` (MIT). Les données de marché publiques (ticker, OHLC) sont gratuites et explicitement autorisées en commercial par les ToS de Kraken, Coinbase, Binance, etc. Implémentation initiale : Kraken d'abord, Coinbase en fallback si Kraken 404.
|
||
- **Stocks** : interrogation de Yahoo Finance via `query1.finance.yahoo.com/v7/finance/quote` (et v8 chart pour historique) avec un User-Agent navigateur. **Best-effort assumé** : peut échouer ou changer sans préavis.
|
||
|
||
Le client paie pour **l'infrastructure d'anonymisation**, pas pour la donnée. Cette distinction est centrale au modèle économique : la valeur premium = privacy (proxy mutualisé) + commodité (auto-fill), pas la donnée elle-même.
|
||
|
||
### Garde-fous obligatoires
|
||
|
||
1. **Label UX explicite** : sur les catégories de bilan en stocks, le bouton fetch affiche un badge « best-effort » + warning au premier usage. Sur crypto : pas de warning.
|
||
2. **Circuit breaker côté maximus-api** : seuil `5 erreurs Yahoo / 60 sec → breaker ouvert pour 15 min`. Notification automatique Telegram/email à `maxime2tremblay@protonmail.com`.
|
||
3. **Quota baissé** : 200 req/jour/licence (vs 2000 initialement). Suffit pour ~50 actifs × snapshot mensuel. Réduit l'incitation à abuser.
|
||
4. **Saisie manuelle toujours active** : aucun chemin d'erreur ne bloque la saisie d'un snapshot.
|
||
5. **Headers stripping rigoureux** : tous les headers entrants supprimés avant call sortant. Vers Yahoo : UA browser-like (`Mozilla/5.0 ...`). Vers exchanges : UA `maximus-api/<version>`.
|
||
6. **Logs séparés** : pas de log conjoint `(license_id, symbol)`. Implémentation via wrapper logger injectable (`src/logger.ts` pino).
|
||
|
||
### Plan de migration si Yahoo devient inutilisable
|
||
|
||
Triggers de migration vers un provider payant :
|
||
- Plus de 1 incident IP-ban / mois pendant 2 mois consécutifs, OU
|
||
- Plus de 30% des requêtes stocks tombent en circuit-breaker `service_degraded` sur 7 jours, OU
|
||
- Plainte légale formelle de Yahoo / Verizon Media.
|
||
|
||
Provider de bascule prioritaire : **Tiingo plan Power** (~10 $/mo, 1000 req/jour, ToS-clean).
|
||
- Implémentation : ajouter un module `providers/tiingo.ts` parallèle à `providers/yahoo.ts`. Switch via env var `STOCKS_PROVIDER=yahoo|tiingo`.
|
||
- Délai de bascule : ≤ 30 jours après déclenchement d'un trigger.
|
||
- Communication : entrée CHANGELOG explicite + email aux licences premium actives.
|
||
|
||
Si l'audience grandit (>500 licences premium actives), bascule vers Polygon Starter (~29 $/mo) considérée.
|
||
|
||
## Consequences
|
||
|
||
### Positives
|
||
|
||
- **0 $ de coût récurrent au MVP** — pas de cash burn avant que le produit ait validé son marché.
|
||
- **Crypto 100% OSS-légal** — voie pérenne, ne nécessitera jamais de migration.
|
||
- **Justification premium cohérente** — privacy comme valeur, pas la donnée. Aligne avec les principes du projet.
|
||
- **Plan de bascule pré-engagé** — pas pris au dépourvu si Yahoo devient hostile.
|
||
|
||
### Négatives / Risques actés
|
||
|
||
- **ToS Yahoo en zone grise** — le proxy commercial de leur data publique n'est pas formellement autorisé. Yahoo a déjà émis des cease-and-desist contre yfinance (lib Python). Risque légal théorique mais peu probable à petite échelle.
|
||
- **IP-ban probable à un moment ou l'autre** — Yahoo bloque les UA non browser et les patterns de requête trop réguliers. Le circuit breaker absorbe l'événement, mais le feature devient temporairement HS pour tous les premium.
|
||
- **Pas de garantie de stabilité de schéma** — Yahoo peut renommer un champ JSON sans préavis. Tests d'intégration `nock` ne capturent pas ça (mock = donnée figée).
|
||
- **Charge ops accrue** — il faudra surveiller le taux d'erreur Yahoo et réagir vite si dégradation.
|
||
|
||
### Neutre
|
||
|
||
- Première implémentation un peu plus complexe côté serveur (deux providers + circuit breaker), mais le code reste contained dans `src/providers/` et est testable.
|
||
|
||
## Suivi
|
||
|
||
- ADR à reviewer dans 6 mois (2026-10-26) ou plus tôt si trigger de migration déclenché.
|
||
- Métriques à tracker dans le log applicatif maximus-api : `yahoo_success_rate_7d`, `yahoo_breaker_open_count_30d`, `crypto_provider_distribution`.
|
||
- Issue de suivi : créer une issue `ops` dans `maximus-api` pour le monitoring continu une fois deployé.
|
||
|
||
## References
|
||
|
||
- [Yahoo Finance ToS](https://legal.yahoo.com/us/en/yahoo/terms/index.html) — sec. 7-8 sur l'usage commercial
|
||
- [CoinGecko API ToS](https://www.coingecko.com/en/api/terms) — restrictions free tier
|
||
- [Kraken API public market data](https://docs.kraken.com/rest/) — explicite : free public tier, commercial OK pour data publique
|
||
- [CCXT (MIT)](https://github.com/ccxt/ccxt) — abstraction multi-exchange, lib OSS
|
||
- ADR 0009 — Architecture du proxy
|
||
- `docs/api-contract-prices.md` — Contrat figé `/v1/prices`
|