52 Commits

Author SHA1 Message Date
CTO H3R7Tech
8ab42343aa feat: Token Broker infrastructure (HRT-205)
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
- PostgreSQL dedie Docker (postgres:16-alpine, port 5434)
- 6 tables: api_tokens, refresh_tokens, token_audit_log, clients, providers, token_usage
- Init SQL + Flask init_db() mis a jour
- Systemd service token-broker (port 8783)
- Deploy script infra/scripts/deploy_token_broker.sh
- Docker compose broker (docker-compose.broker.yml)
- Health check OK: status=ok, database=connected

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-24 09:22:12 +02:00
CTO H3R7Tech
cd4cbcfb48 Fix #2+#3: Routes API 404 et conflit blueprint name
Bug #2: portal_server.py importait api_v1_bp depuis saas_api_v1 au lieu
de api_v1/__init__.py. Tous les sous-blueprints api_v1/routes/* (health,
courses, predictions, valuebets, backtest, export, metrics, ml_feedback)
n'etaient jamais enregistres -> 404.
Fix: utiliser register_api_v1(app) depuis api_v1/__init__.py.

Bug #3: Conflit de nom de blueprint entre saas_api_v1 et api_v1 (tous
deux nommes api_v1). Renomme le blueprint de saas_api_v1 en saas_api_v1_bp.
Supprime les record_once handlers de saas_api_v1 qui dupliquaient
l'enregistrement de sous-blueprints (billing, org, user, history) -
desormais geres par register_api_v1(app).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-23 22:57:06 +02:00
CTO H3R7Tech
c072f92794 Fix #1: Ajout job run_ml_cache dans scheduler pour alimenter ml_predictions_cache
- run_ml_cache() lit les partants, genere predictions via predict_v2,
  enrichit avec metadonnees course, calcule risque, ecrit dans cache
- Planifie 4x/jour: 09:30, 11:35, 13:30, 17:35
- Installe dependances: optuna, shap, lightgbm

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-23 22:54:29 +02:00
CTO H3R7Tech
fac498efec fix: test isolation + auth import compatibility + add optuna to requirements (HRT-136)
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
Test isolation fixes:
- auth_db.get_db(): read TURF_SAAS_DB dynamically (not frozen at import)
- api_v1/utils.get_db(): read TURF_SAAS_DB dynamically (not frozen at import)
- api_tokens_db.get_db(): read TURF_SAAS_DB dynamically (not frozen at import)
- tests/test_history.py: enforce _tmp_db.name + call init_auth_tables() in fixtures
- tests/test_user_tokens.py: enforce _tmp_db.name + call migrate_api_tokens_tables() in app fixture

Auth compatibility fixes:
- api_v1/routes/history.py: use auth.jwt_required_middleware (flask_jwt_extended)
  with saas_auth fallback for portal_server context
- api_v1/routes/ml_feedback.py: same auth import strategy
- api_v1/routes/user.py: same auth import strategy

Dependencies:
- requirements.txt: add optuna>=4.0.0 (used in ML ensemble tests and training)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-10 08:45:31 +02:00
CTO H3R7Tech
1ccf9f5cb8 feat: LeadHunter CRUD API + auth fixes + blueprint registrations (HRT-136)
- leadhunter_crm.py: add update_lead(), delete_lead(); expand VALID_STATUSES to 7-step Kanban with legacy migration map
- leadhunter_api.py: add GET/PUT/DELETE /api/leads/<id> endpoints; import update_lead, delete_lead
- portal_server.py: add routes for /leadhunter/clients/le-big-ben/ and /formation/ai102
- saas_api_v1.py: register user blueprint (HRT-79/80) and history blueprint (HRT-81)
- api_v1/routes/user.py: switch auth import to saas_auth.require_auth
- api_v1/routes/history.py: fix auth import + request.current_user fallback
- api_v1/routes/ml_feedback.py: fix auth import + request.current_user fallback

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-10 08:29:44 +02:00
DevOps Engineer
a126941f7f feat(saas): métriques ML + TEST_MODE + compte test pro
- portal_server.py: enregistre metrics_bp (/api/v1/metrics)
- api_v1/routes/metrics.py: switch vers saas_auth.require_auth (compat token opaque)
- dashboard_saas.html: onglet Métriques (KPIs + Chart.js ROI/précision/cumul + table daily)
- dashboard_saas.html: TEST_MODE=true -> plan level pro pour toutes les fonctionnalités
- turf_saas.db: compte admin@h3r7.ai / Test1234! plan=pro (test)
2026-05-02 22:49:59 +02:00
DevOps Engineer
3079c2c6c6 Merge branch 'feature/HRT-96-note-intelligence-ml'
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
2026-05-01 11:43:31 +02:00
DevOps Engineer
52c0c95f22 feat(HRT-93): ml_feedback_saas.py — feedback loop ML pour turf_saas
- Crée ml_feedback_saas.py (adaptation de ml_feedback.py pour turf_saas.db)
  - DB_PATH = /home/h3r7/turf_saas/turf_saas.db
  - Stratégies : xgboost_sg, xgboost_value, xgboost_sp, xgboost_2sur4
  - Idempotent (ne duplique pas les paris existants)
  - Tested : 188 paris insérés en 1ère exécution, 0 en 2ème (idempotence OK)
- Crée api_v1/routes/ml_feedback.py
  - POST /api/v1/ml/feedback/run (admin only via X-Admin-Token ou plan pro)
  - GET /api/v1/ml/feedback/stats (premium+)
- Enregistre ml_feedback_bp dans api_v1/__init__.py

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-30 21:36:21 +02:00
DevOps Engineer
0492f06bfd docs(HRT-96): Note Intelligence ML + documentation API v1 finale
- Création POD/Intelligence/ML_Predictions_SaaS.md : architecture ML complète,
  flow ml_predictions_cache → ml_feedback_saas → paris → ROI dashboard,
  schéma données/jointures, décision duplication vs modification turf_scraper,
  documentation des 4 stratégies XGBoost, idempotence, usage CLI
- Mise à jour DOCUMENTATION.md : ajout section Turf SaaS API v1 complète
  avec tous les endpoints documentés dont /api/v1/roi/* et /api/v1/ml/feedback/*
  (HRT-92 ROI backend + HRT-93 ML feedback loop)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-30 21:28:52 +02:00
91134e2f3f Merge pull request '[HRT-83] feat: Météo & terrain intégrés dans prédictions ML (Premium)' (#10) from feature/HRT-83-meteo-terrain-ml-predictions into master
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
2026-04-30 08:40:16 +02:00
DevOps Engineer
663e0bb149 Merge PR #12 — [HRT-82] Multi-compte / Organisation Pro (max 5 users)
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-30 08:39:59 +02:00
5c6b407f47 Merge pull request '[HRT-80] API Token personnel + Webhook alertes (Pro)' (#13) from feature/HRT-80-api-tokens-webhooks into master
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
2026-04-29 17:31:53 +02:00
DevOps Engineer
f300e44c74 feat(HRT-80): API Token personnel + Webhook alertes (Pro)
- Nouveaux fichiers: api_tokens_db.py, api_v1/routes/user_tokens.py, api_v1/utils_webhook.py
- Migration DB idempotente: tables user_api_tokens + user_webhooks
- Endpoints POST/DELETE /api/v1/user/api-token (Pro only)
- Endpoints POST/DELETE /api/v1/user/webhook (Pro only, HTTPS requis)
- HMAC-SHA256 fire-and-forget dispatch webhook
- auth.py: validate_api_key() + X-API-Key fallback dans jwt_required_middleware
- saas_auth.py: import logging au niveau module, validate_api_key(), X-API-Key fallback
- api_v1/__init__.py: enregistrement user_tokens_bp
- 24 tests pytest — tous passent

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-29 17:25:30 +02:00
DevOps Engineer
946bdc65b6 feat(HRT-82): Multi-compte / Organisation Pro (max 5 users)
- Add org_db.py: SQLite schema with organizations + org_members tables
  PRAGMA foreign_keys=ON, ON DELETE CASCADE, UNIQUE constraints
- Add api_v1/routes/org.py: CRUD org endpoints + invite/accept flow
  POST/GET/DELETE /api/v1/org, POST /api/v1/org/invite,
  GET/DELETE /api/v1/org/members — Pro plan only, max 5 members
- Add tests/test_org.py: 36 unit tests (35/36 pass; 1 test-env issue)
- Update api_v1/__init__.py: register org_bp
- Update saas_api_v1.py: register org_bp on portal_server app via record_once
- Service restarted, /api/v1/org/* endpoints live (401 on unauthenticated)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-29 17:09:13 +02:00
DevOps Engineer
bc5ee3fa1a Merge feature/HRT-81-history-blueprint — Historique limité/illimité selon plan (Free/Premium/Pro)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-29 17:05:01 +02:00
DevOps Engineer
701660ce83 fix(HRT-81): enregistrer history_bp dans api_v1/__init__.py
- Ajouter import de history_bp depuis .routes.history
- Ajouter app.register_blueprint(history_bp) dans register_api_v1()
- Corriger le docstring du module pour lister /api/v1/history
- Tests: 19/19 passed (GET /api/v1/history — auth, free/premium/pro, validation, pagination)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-29 16:56:35 +02:00
b7ed82418f Merge pull request '[HRT-79] Alertes Telegram configurables (Premium)' (#11) from feature/HRT-79-telegram-alerts into master
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
2026-04-29 16:48:46 +02:00
DevOps Engineer
8604dc78b1 feat(HRT-79): alertes Telegram configurables Premium/Pro
- telegram_alerts.py: service envoi alertes via Bot API (send_pre_race_alerts,
  build_race_alert, send_telegram_message) — gestion gracieuse TELEGRAM_BOT_TOKEN absent
- auth_db.py: migrate_telegram_columns() idempotente (ALTER TABLE + try/except OperationalError)
  colonnes: telegram_chat_id, alert_value_bets, alert_top1, alert_quinte_only
- api_v1/routes/user.py: blueprint user_bp GET/POST /api/v1/user/telegram-config
  protégé @jwt_required_middleware + @plan_required('premium','pro')
- api_v1/__init__.py: import + register user_bp
- turf_scheduler.py: run_telegram_alerts() + schedule_dynamic_telegram_alerts()
  planifiées 30min avant course (même pattern que schedule_dynamic_scoring)
  avec try/except Exception + fallback logger

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-29 16:42:15 +02:00
DevOps Engineer
30464fb40c Merge branch 'feature/HRT-84-dashboard-premium-pro' into master
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
[HRT-84] Dashboard SaaS — UI Premium & Pro avec gating plan strict
- Sections Value Bets, Historique, Export CSV raccordées aux vrais endpoints
- Sections Telegram, API Token, Webhook avec mocks (TODO HRT-79, HRT-80)
- Gating plan strict: Free/Premium/Pro non contournable côté client
- Fix: maxDays Pro = 365j (corrige inversion 30j vs 90j)
- Multi-compte Pro: gating UI uniquement (endpoint non défini)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-29 15:49:56 +02:00
DevOps Engineer
31db3a8260 fix(HRT-84): maxDays historique Pro — 365j au lieu de 30j (inversion corrigée)
Pro = 365j (historique le plus long), Premium = 90j, Free = 7j
Corrigé suite au point d'attention CTO dans revue de code.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-29 15:49:25 +02:00
DevOps Engineer
278245cd7c feat(HRT-84): dashboard SaaS — UI Premium & Pro avec gating plan strict
- Ajout sections: Value Bets, Alertes Telegram, API Token, Webhook, Historique, Multi-compte
- Gating plan strict: Free < Premium < Pro (jamais de données réelles derrière plan inférieur)
- Value Bets: raccordé sur endpoint réel /api/v1/valuebets (premium+)
- Historique: raccordé sur endpoint réel /api/v1/history (HRT-81)
- Telegram / API Token / Webhook: mocks structurés avec contrats d'interface
  (TODO: replace mock — HRT-79 pour Telegram, HRT-80 pour API Token/Webhook)
- Multi-compte: gating UI Pro uniquement, endpoint non défini
- Navigation par section avec chargement lazy
- Design cohérent dark theme avec badges, lock icons et CTA upgrade par plan

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-29 15:43:02 +02:00
DevOps Engineer
ec024d8236 feat(HRT-83): intégrer météo & terrain dans prédictions ML (Premium)
- scoring_v2.py : ajout get_terrain_condition() + compute_weather_impact()
  score_cheval_v2() accepte weather_data=None (backward-compat préservée)
  Impact météo/terrain sur [-5, +5] pts selon pénétromètre + vent + temp

- api_v1/routes/predictions.py : _fetch_ml_predictions() avec include_weather=True
  LEFT JOIN pmu_courses (pénétromètre) + pmu_meteo sur date+num_reunion
  /predictions/all → terrain_condition + weather_impact dans chaque row
  /predictions/top3 → inchangé (free tier, pas de champs météo)

- api_v1/routes/valuebets.py : même LEFT JOIN météo/terrain
  /valuebets → terrain_condition + weather_impact dans chaque value bet

Tests : 42/42 passent (pytest tests/test_api_v1.py)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-29 15:35:15 +02:00
DevOps Engineer
225295030b fix(HRT-73): refactor api_proxy — COMBINED_ROUTES tuple + align with turf_scraper fix #23
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
- Replace if/elif chain with COMBINED_ROUTES tuple for maintainability
- Add missing routes to combined_api: races, race/, scores, ask, brave-search,
  execute-sql, send-email, report, ideas
- Functionally equivalent to turf_scraper commit 048b969

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 22:38:32 +02:00
DevOps Engineer
86e85aa1c6 fix(HRT-72): fix Overpass OSM scraper — bounding box + Content-Type + User-Agent
Bug 1: Replace area["name"="..."] query with direct bounding box (50.4,2.8,50.8,3.3)
  — area resolution fails silently on public Overpass API depending on server version.
  — Direct bbox is deterministic and reliable for MEL coverage.
  — Also simplify website filter to use [!"website"] tag negation syntax.

Bug 2: Add explicit Content-Type: application/x-www-form-urlencoded header
  — Some network configs/proxies strip the implicit header set by requests.post(data={}).
  — Explicit header is best practice per Overpass API docs.

Bug 3 (discovered during test): Add User-Agent header
  — overpass-api.de returns 406 Not Acceptable for User-Agent: python-requests/*.
  — Fix: send H3R7Tech-LeadHunter/1.0 as custom User-Agent.
  — Tested: 5 OSM leads returned from Lille center bounding box.

Backup: leadhunter_scraper.py.backup_20260427_221429

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 22:19:10 +02:00
5aa6013c52 Merge pull request '[HRT-66] LeadHunter S1 — Core scraping, scoring, CRM SQLite et API Flask' (#8) from feature/HRT-66-leadhunter-core into master
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
2026-04-27 16:55:00 +02:00
DevOps Engineer
4b4323f707 fix(leadhunter): change port 8770→8775 — port 8770 occupé par turf_scraper/crm_api.py
Port audit sur VPS (27/04/2026) :
- 8769 : depenses_trello/app.py (PID 2287989)
- 8770 : turf_scraper/crm_api.py (PID 2287988) ← port précédemment choisi, aussi occupé
- 8775 : libre (vérifié via ss -tlnp | grep 8775 → vide)

Fichiers modifiés :
- leadhunter_api.py : lignes 5, 295, 303 (port 8770→8775)
- infra/turf-saas-leadhunter.service : Description Port 8770→8775

Issue: HRT-66

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 16:48:12 +02:00
DevOps Engineer
356bdf5bec fix(leadhunter): change port 8769→8770 — conflit avec depenses_trello
Port 8769 était occupé par /home/h3r7/depenses_trello/app.py (pid=2287989).
Mise à jour du port dans :
- leadhunter_api.py (docstring, healthcheck, app.run)
- infra/turf-saas-leadhunter.service (description)

Ref: HRT-66

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 16:42:15 +02:00
DevOps Engineer
f9a45e6deb feat(HRT-66): LeadHunter S1 — core scraping, scoring, CRM SQLite et API Flask
- leadhunter_scraper.py : Google Places Nearby Search + Place Details
  avec compteur quota daily_quota.json (limite 900/jour),
  sleep(0.5) entre requêtes, fallback Overpass OSM boundary MEL,
  filtre website absent, déduplcation, rgpd_ok=True

- leadhunter_scorer.py : moteur de scoring 0-8 pts
  critère n°1 = site web absent (+3), avis ≥50 (+2),
  note ≥4.0 (+2), téléphone (+1), note <3.0 (-1)

- leadhunter_crm.py : CRM SQLite schéma validé CTO
  (id, source, name, address, phone, rating, reviews_count,
   website, score, rgpd_ok, scraped_at, status)
  CRUD : insert_lead, get_leads, update_lead_status, get_stats, export_csv

- leadhunter_api.py : Flask service port 8769
  GET /api/leads, POST /api/leads/scrape, GET /api/leads/stats,
  GET /api/leads/export, PATCH /api/leads/<id>/status, GET /health
  assert GOOGLE_PLACES_API_KEY au démarrage
  scraping asynchrone (thread) avec status endpoint

- infra/turf-saas-leadhunter.service : service systemd
  EnvironmentFile=/home/h3r7/.env pour GOOGLE_PLACES_API_KEY

Tests : py_compile OK, scorer testé, CRM SQLite testé

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 16:33:30 +02:00
DevOps Engineer
cfc0f038f9 Merge remote HRT-43 into local master (sync)
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
Merge remote commit 837a084 (HRT-43 ML cache null test) with local
HRT-62, HRT-63, HRT-54 security commits.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 16:16:31 +02:00
DevOps Engineer
c999285895 Merge HRT-63: Blacklist + validation complexite mots de passe
Fix review: abc12345 -> abc1234 dans test_security.py (TestWeakPasswordRejection)
Valide CTO — coherence blacklist/test confirmee.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 16:14:17 +02:00
DevOps Engineer
e517741c97 fix(tests): replace abc12345 by abc1234 in TestWeakPasswordRejection
abc12345 n'est pas dans WEAK_PASSWORDS de saas_auth.py et satisfait
les règles de complexité → test échouait (attendait 400, obtenait 201).
abc1234 est explicitement dans la blacklist (ligne 84 de saas_auth.py).

Correction demandée par CTO en review PR #7 (HRT-63).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 15:53:39 +02:00
837a0845ec Merge pull request 'HRT-43 — Test intégration ml_predictions_cache : zéro NULL hippodrome' (#5) from feature/HRT-43-ml-cache-null-test into master
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
2026-04-27 15:36:48 +02:00
CTO H3R7Tech
4bf458f1b8 Merge HRT-62: IP-based rate limiting on /auth/login — validated CTO
- In-memory IP rate limiter: 5 attempts / 5min window
- 15 min block on exceed, HTTP 429 + Retry-After header
- Applied rate_limit_middleware on portal_server.py
- Tests: TestLoginRateLimit added (conflict resolved: keep both test classes)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 15:24:07 +02:00
CTO H3R7Tech
099286b078 Merge HRT-63 + HRT-54: password blacklist/complexity + billing JWT fix — validated CTO
- HRT-63: WEAK_PASSWORDS blacklist (50+ entries) + validate_password_strength()
- HRT-54: billing JWT token fix, table name corrections

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 15:22:03 +02:00
CTO H3R7Tech
d39c7d3319 fix(billing): JWT token incompatibility — use saas_auth require_auth + fix table names HRT-54
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 15:21:43 +02:00
DevOps Engineer
8c5fdf1e9c feat(security): blacklist + password strength validation — fix weak passwords HRT-63
- Add WEAK_PASSWORDS set (50+ common passwords) in saas_auth.py
- Add validate_password_strength() function: checks min length, blacklist, digits, letters
- Replace raw len() checks in /register and /change-password with validate_password_strength()
- Add TestWeakPasswordRejection class in test_security.py: parametrized weak pwd test, strong pwd 201 test, no-digit, no-letter tests

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 15:01:57 +02:00
DevOps Engineer
7f5573f076 feat(security): add IP-based rate limiting on /api/v1/auth/login — fix brute force HRT-62
- saas_auth.py: in-memory sliding-window rate limiter (5 attempts/5min, 15min block)
  using collections.defaultdict + threading.Lock, stdlib only, no new deps
- portal_server.py: register rate_limit_middleware + access_log_middleware
  (was missing, leaving global 100req/min limit unApplied on portal routes)
- tests/security/test_security.py: add TestLoginRateLimit class with
  test_login_brute_force_blocked_after_5_attempts and test_login_429_has_retry_after_header

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 14:50:08 +02:00
DevOps Engineer
82d6bdafba HRT-43 — Test intégration ml_predictions_cache : zéro NULL hippodrome
- Ajout tests/test_ml_cache_integrity.py : 7 tests integration vérifiant
  que hippodrome, race_label et heure ne sont pas NULL pour la date courante
- Ajout marqueur 'integration' dans pytest.ini
- Connexion DB en lecture seule (mode=ro) pour protection prod
- Support variable d'env TEST_DATE et TURF_DB_PATH
- Tests skippés proprement si job 19h30 n'a pas encore tourné
- Validé sur les données 2026-04-26 : 7/7 PASSED (1005 lignes, 0 NULL)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-27 14:26:46 +02:00
DevOps Engineer
36d93697bc Merge Sprint 7-8 CI/CD + Docker + Monitoring (HRT-33)
Some checks failed
CD / Deploy → Staging (push) Has been cancelled
CD / Smoke Tests on Staging (push) Has been cancelled
CD / Deploy → Production (push) Has been cancelled
CD / Rollback Production (push) Has been cancelled
2026-04-26 23:12:59 +02:00
2f57719b21 Merge pull request 'Sprint 4-5 — Landing Page + Onboarding (HRT-30)' (#3) from feature/landing-onboarding into master 2026-04-26 23:12:06 +02:00
bffc06c9b1 Merge pull request 'Sprint 3-4 — Refacto API /v1/ (HRT-29)' (#2) from feature/api-v1-refacto into master 2026-04-26 23:12:04 +02:00
f1ef2648b1 Merge pull request 'Sprint 6-7 — ML Upgrade: Ensemble XGBoost+LightGBM+MLP + Optuna' (#1) from feature/ml-upgrade-ensemble into master 2026-04-25 19:15:15 +02:00
DevOps Engineer
6b762068fd feat(ml): train ensemble model and generate benchmark report
Results:
  - XGBoost (Optuna 100 trials): AUC=0.7856, Precision@3=0.5783
  - LightGBM (Optuna 100 trials): AUC=0.7833, Precision@3=0.5736
  - MLP (3 layers 256-128-64): AUC=0.7743, Precision@3=0.5643
  - Ensemble (weighted voting): AUC=0.7840, Precision@3=0.5814

  Baseline XGBoost: Precision@3=0.5287
  Delta: +0.0527 (+5.3%) — DEPLOY threshold met (+5%)
  Latency: 35ms/race, 69ms/full-day (well under 200ms limit)

  SHAP: 31/43 features selected, top features: rang_cote,
  implied_prob, cote_direct, ratio_cote_field

  All 12 regression/latency tests passing.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 19:10:41 +02:00
DevOps Engineer
0e7bcff6b0 feat(ml): add ensemble XGBoost+LightGBM+MLP with Optuna optimization
- train_ensemble.py: full training pipeline with 100-trial Optuna studies
  for XGBoost and LightGBM, MLP (256-128-64), SHAP feature selection,
  weighted soft-voting ensemble, benchmark report generation
- predict_v2.py: production prediction module with model cache invalidation
- combined_api.py: add /api/v1/predictions, /api/v1/model/status,
  /api/v1/model/invalidate-cache endpoints using ensemble model
- tests/test_ml_ensemble.py: regression, latency and API tests

Baseline XGBoost Precision@3: 0.5287 (holdout 20% temporal)
Deploy threshold: +5% = 0.5551

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 18:18:48 +02:00
DevOps Engineer
ce0ee150ec fix(api-v1): add billing_db.py dependency for billing routes
The api_v1 Blueprint includes billing routes (POST/GET /api/v1/billing/*),
which import from billing_db. This module lives in feature/billing-stripe
(HRT-31) but is needed here for tests to pass. Added the file so all
42 integration tests pass without modification.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 18:08:39 +02:00
DevOps Engineer
41a9e36166 feat(sprint4-5): Landing page + onboarding SaaS — HRT-30
Frontend pages:
- landing.html: marketing page — hero, pricing (Free/9.90e/24.90e), features, FAQ, footer, mobile-first responsive, LCP < 2.5s friendly
- login.html: JWT auth login with JS validation, error handling, redirect-after-login
- register.html: registration with plan selection preview sidebar, password strength meter
- dashboard_saas.html: role-based dashboard (Free/Premium/Pro) with locked sections, race prediction cards, detailed table, stats row
- onboarding.html: 3-step wizard — plan confirm + Telegram alerts config + first prediction preview
- account.html: tabbed account management — profile, security (change-password, delete), plan upgrade, notification preferences

Backend:
- saas_auth.py: Flask Blueprint /api/v1/auth/* — register, login, token auth, profile/password/plan/preferences update, logout, delete-account
- saas_api_v1.py: Flask Blueprint /api/v1/* — stats/summary, predictions/today (plan-gated), value-bets (Premium+), CSV export (Pro)

Server:
- portal_server.py: register blueprints, serve all new SaaS routes at /login /register /dashboard /onboarding /account

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 18:04:19 +02:00
DevOps Engineer
b8ef1ed35d feat: Sprint 3-4 — Refacto API /v1/ (HRT-29)
- Blueprint Flask api_v1 avec prefix /api/v1/
- GET /api/v1/health — healthcheck public
- GET /api/v1/courses/today — courses du jour (paginé, filtré)
- GET /api/v1/courses/{id}/predictions — prédictions ML pour une course
- GET /api/v1/predictions/top3 — top 3 global (free tier)
- GET /api/v1/predictions/all — toutes prédictions (premium+)
- GET /api/v1/valuebets — value bets du jour (premium+)
- GET /api/v1/backtest — résultats backtest historiques (pro)
- GET /api/v1/export/csv — export CSV prédictions/paris (pro)
- GET /api/v1/metrics — métriques perf ML (premium+)
- Swagger/OpenAPI via flasgger à /api/v1/docs
- Erreurs uniformes {status, message, code}
- Pagination limit/offset sur toutes les listes
- 42 tests d'intégration passants

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 18:00:54 +02:00
DevOps Engineer
793ee82c29 fix(qa): add /health endpoints to Flask apps for Docker healthchecks
Docker compose healthchecks target /health on combined-api, dashboard-api
and portal, but these endpoints did not exist (returned 404). This caused
all dependent services (condition: service_healthy) to fail startup.

- combined_api.py: GET /health + /turf/health with DB connectivity check
- dashboard_api.py: GET /health + /turf/health with DB connectivity check
- portal_server.py: GET /health (lightweight, no DB)

QA Finding 1 from HRT-34 review of HRT-33 branch feature/devops-cicd.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 17:44:21 +02:00
DevOps Engineer
c8f1bfd478 Merge feature/auth-jwt-multitenant into main — Sprint 2-3 Auth JWT + Multi-tenant (HRT-28)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 17:35:48 +02:00
DevOps Engineer
5a23692ad1 feat: Sprint 2-3 — Auth JWT + Multi-tenant (HRT-28)
- auth_db.py: create users, subscriptions, refresh_tokens tables in turf_saas.db
- auth.py: register/login/refresh/logout endpoints, JWT middleware, plan_required decorator, free daily-limit check
- middleware.py: in-memory rate limiter (100 req/min/IP), timestamped access logs
- saas_api.py: Flask app factory wiring JWT, CORS, blueprints, /api/v1/predictions plan-gating
- tests/test_auth.py: 27 pytest tests, 83% coverage (target >=80%)
- API_AUTH.md: full endpoint documentation

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 17:35:45 +02:00