API-KA — plateforme centrale : collecte quotidienne des 8 services KA, historisation append-only et API publique sur www.api-ka.com
Python 60.9%
HTML 21%
TypeScript 7.3%
JavaScript 5.2%
CSS 4.8%
Shell 0.8%
1# CLAUDE.md — Projet API-KA23## Vision du projet45**API-KA** est la plateforme centrale légendaire de l'écosystème KA. Elle collecte, sauvegarde et centralise **chaque jour** les données de tous les services KA (lou-ka, immo-ka, food-ka, auto-ka, fabri-ka, resto-ka, sorti-ka, crea-ka) dans une base de données unifiée, puis les expose via une API publique accessible sur **www.api-ka.com** (tunnel ngrok).67**Tout le déploiement se fait sur le node `m3u96b`.** Aucun service de production ne tourne ailleurs.89## Auteur — OBLIGATOIRE dans chaque fichier1011Chaque fichier de code (Python, JS, SQL, shell, config, etc.) DOIT commencer par un en-tête d'auteur. Règle non négociable — aucun fichier sans en-tête.1213**Python / Shell / SQL / YAML :**14```15# ============================================16# Projet : API-KA17# Fichier : <nom_du_fichier>18# Node : m3u96b19# Author : Simon-Pierre Boucher20# Contact : contact@spboucher.ai21# Date : <date de création>22# ============================================23```2425**JavaScript / TypeScript :**26```javascript27/**28 * ============================================29 * Projet : API-KA30 * Fichier : <nom_du_fichier>31 * Node : m3u96b32 * Author : Simon-Pierre Boucher33 * Contact : contact@spboucher.ai34 * Date : <date de création>35 * ============================================36 */37```3839## Node de déploiement : m3u96b4041- **Node cible unique** : `m3u96b`. Tous les services (API, scheduler, base de données, tunnel ngrok) tournent sur ce node.42- Répertoire de déploiement : `/opt/api-ka/` sur m3u96b.43- Données et backups : `/opt/api-ka/data/` et `/opt/api-ka/data/backups/`.44- Logs centralisés : `/opt/api-ka/logs/`.45- Les services sont gérés par **systemd** sur m3u96b (voir section "Services systemd").46- Toute commande de déploiement, cron ou service doit référencer explicitement m3u96b dans sa documentation et ses logs (`hostname` vérifié au démarrage : si le hostname n'est pas `m3u96b`, le service refuse de démarrer en mode production et log un avertissement).4748### Vérification du node au démarrage (obligatoire dans chaque service)4950```python51import socket, os5253REQUIRED_NODE = "m3u96b"5455def verify_node():56 hostname = socket.gethostname()57 if os.getenv("APP_ENV") == "production" and hostname != REQUIRED_NODE:58 raise RuntimeError(f"API-KA doit tourner sur {REQUIRED_NODE}, node actuel : {hostname}")59```6061## Sources de données (les 8 services KA)6263| Service | Table | Variable source | Fréquence |64|-----------|------------------|----------------------|-------------|65| lou-ka | `louka_data` | `LOUKA_SOURCE_URL` | Quotidienne |66| immo-ka | `immoka_data` | `IMMOKA_SOURCE_URL` | Quotidienne |67| food-ka | `foodka_data` | `FOODKA_SOURCE_URL` | Quotidienne |68| auto-ka | `autoka_data` | `AUTOKA_SOURCE_URL` | Quotidienne |69| fabri-ka | `fabrika_data` | `FABRIKA_SOURCE_URL` | Quotidienne |70| resto-ka | `restoka_data` | `RESTOKA_SOURCE_URL` | Quotidienne |71| sorti-ka | `sortika_data` | `SORTIKA_SOURCE_URL` | Quotidienne |72| crea-ka | `creaka_data` | `CREAKA_SOURCE_URL` | Quotidienne |7374**RÈGLE CRITIQUE : les données de chaque service DOIVENT être sauvegardées tous les jours, sans exception.**75- Chaque exécution quotidienne est journalisée.76- Tout échec de collecte est détecté, loggé et relancé automatiquement (3 tentatives, backoff exponentiel : 30s → 2min → 10min).77- Si un service échoue après 3 tentatives, une entrée `status=failed` est écrite dans `collection_runs` et une alerte est ajoutée à `logs/alerts.log`. Le lendemain, le job tente automatiquement un rattrapage (backfill) des dates manquées.7879## Architecture8081```82/opt/api-ka/ # sur le node m3u96b83├── CLAUDE.md84├── README.md85├── .env # jamais commité86├── .env.example87├── requirements.txt88├── src/89│ ├── config.py # chargement .env + vérification node m3u96b90│ ├── collectors/91│ │ ├── base_collector.py # classe abstraite : fetch, validate, save, retry92│ │ ├── louka_collector.py93│ │ ├── immoka_collector.py94│ │ ├── foodka_collector.py95│ │ ├── autoka_collector.py96│ │ ├── fabrika_collector.py97│ │ ├── restoka_collector.py98│ │ ├── sortika_collector.py99│ │ └── creaka_collector.py100│ ├── database/101│ │ ├── models.py # SQLAlchemy : 8 tables données + collection_runs102│ │ ├── db.py # engine, session, init, healthcheck103│ │ └── migrations/ # Alembic104│ ├── api/105│ │ ├── main.py # FastAPI, monté derrière ngrok106│ │ ├── routes/107│ │ │ ├── services.py # /api/v1/{service}...108│ │ │ ├── runs.py # /api/v1/runs109│ │ │ └── health.py # /health (inclut node, dernière collecte, db)110│ │ └── middleware/111│ │ ├── logging.py # log de chaque requête112│ │ └── ratelimit.py # protection basique de l'API publique113│ ├── scheduler/114│ │ ├── daily_job.py # orchestre les 8 collecteurs115│ │ └── backfill.py # rattrapage des dates manquées116│ └── utils/117│ ├── logger.py # logs JSON structurés, rotation quotidienne118│ ├── retry.py # décorateur retry avec backoff119│ └── backup.py # dump quotidien horodaté120├── scripts/121│ ├── deploy_m3u96b.sh # déploiement complet sur le node122│ ├── run_daily_backup.sh123│ ├── start_ngrok.sh # tunnel www.api-ka.com avec auto-restart124│ └── healthcheck.sh # utilisé par systemd / monitoring125├── systemd/126│ ├── apika-api.service127│ ├── apika-scheduler.service128│ └── apika-ngrok.service129├── data/130│ └── backups/YYYY-MM-DD/ # dumps quotidiens par service131├── logs/132└── tests/133```134135## Base de données136137- **Moteur** : PostgreSQL 16 sur m3u96b (SQLite acceptable uniquement en dev local).138- Base : `apika`, utilisateur dédié `apika_user`, accès restreint à localhost sur m3u96b.139140### Schéma des tables de données (identique pour les 8 services)141142| Colonne | Type | Détail |143|----------------|-------------|------------------------------------------|144| `id` | BIGSERIAL | Clé primaire |145| `payload` | JSONB | Données brutes du service |146| `source` | TEXT | Nom du service (ex. `louka`) |147| `collected_at` | TIMESTAMPTZ | Horodatage exact de la collecte |148| `date_key` | DATE | Date logique de la collecte (index) |149| `checksum` | TEXT | SHA-256 du payload (déduplication) |150151Index : `(date_key)`, `(source, date_key)`, unique sur `(source, date_key, checksum)`.152153### Table `collection_runs`154155`id`, `service`, `date_key`, `status` (`success` / `failed` / `retried`), `records_count`, `duration_seconds`, `error_message`, `node` (toujours `m3u96b`), `started_at`, `finished_at`.156157### Règles158- **Append-only** : aucune suppression destructive, l'historique complet est conservé.159- **Backup quotidien** : `pg_dump` horodaté par service dans `data/backups/YYYY-MM-DD/`, compressé (`.sql.gz`), conservé 90 jours minimum.160- Vérification d'intégrité hebdomadaire : comparaison du nombre de `date_key` distincts vs jours écoulés — toute journée manquante déclenche un backfill.161162## Collecte quotidienne (scheduler)163164- Job planifié **tous les jours à 02:00 (heure du node m3u96b)** via `apika-scheduler.service` (APScheduler) — cron système en fallback.165- Les 8 collecteurs s'exécutent en parallèle mais de façon **indépendante** : l'échec d'un service ne bloque jamais les autres.166- Pipeline par collecteur : `fetch → validate → checksum → insert → backup → log run`.167- À la fin du run global : résumé dans `collection_runs` + `logs/daily_YYYY-MM-DD.log` + mise à jour de `/health`.168- `backfill.py` s'exécute juste après le job quotidien et rattrape automatiquement toute date manquée des 7 derniers jours.169170## API publique (www.api-ka.com via ngrok)171172- Framework : **FastAPI** (docs auto sur `/docs`, OpenAPI sur `/openapi.json`).173- Serveur : `uvicorn` sur `127.0.0.1:8000` (jamais exposé directement — seul ngrok est public).174- Tunnel : `ngrok http --domain=www.api-ka.com 8000` — le domaine doit être réservé dans le dashboard ngrok (compte payant requis pour un domaine personnalisé) et le `NGROK_AUTHTOKEN` configuré sur m3u96b.175- `apika-ngrok.service` redémarre le tunnel automatiquement en cas de coupure (`Restart=always`).176177### Endpoints178179| Méthode | Route | Description |180|---------|-----------------------------------------|----------------------------------------------------|181| GET | `/` | Statut de la plateforme + version |182| GET | `/health` | Node (m3u96b), état DB, dernière collecte par service |183| GET | `/api/v1/{service}` | Données paginées d'un service |184| GET | `/api/v1/{service}/latest` | Dernière collecte du service |185| GET | `/api/v1/{service}/date/{YYYY-MM-DD}` | Données d'une date précise |186| GET | `/api/v1/{service}/stats` | Nb d'enregistrements par jour, dernière réussite |187| GET | `/api/v1/runs` | Historique des collectes (filtrable par service/statut) |188189- `{service}` ∈ `louka`, `immoka`, `foodka`, `autoka`, `fabrika`, `restoka`, `sortika`, `creaka` — toute autre valeur → 404.190- Versionnement `/api/v1/`, pagination `?page=&limit=` (limit max 500).191- Format de réponse uniforme :192```json193{ "success": true, "data": [...], "meta": { "page": 1, "limit": 100, "total": 4200, "node": "m3u96b" } }194```195- Rate limiting basique (ex. 120 req/min/IP) car l'API est publique via ngrok.196197## Services systemd (sur m3u96b)198199| Service | Rôle | Restart |200|--------------------------|-----------------------------------|----------|201| `apika-api.service` | uvicorn FastAPI :8000 | always |202| `apika-scheduler.service`| Job quotidien 02:00 + backfill | always |203| `apika-ngrok.service` | Tunnel www.api-ka.com | always |204205Commandes : `sudo systemctl enable --now apika-api apika-scheduler apika-ngrok`, statut via `systemctl status apika-*`.206207## Configuration (.env sur m3u96b)208209```210APP_ENV=production211NODE_NAME=m3u96b212DATABASE_URL=postgresql://apika_user:***@localhost:5432/apika213NGROK_AUTHTOKEN=...214NGROK_DOMAIN=www.api-ka.com215API_PORT=8000216DAILY_RUN_HOUR=02217BACKUP_RETENTION_DAYS=90218LOUKA_SOURCE_URL=...219IMMOKA_SOURCE_URL=...220FOODKA_SOURCE_URL=...221AUTOKA_SOURCE_URL=...222FABRIKA_SOURCE_URL=...223RESTOKA_SOURCE_URL=...224SORTIKA_SOURCE_URL=...225CREAKA_SOURCE_URL=...226```227228Ne jamais commiter `.env` — seulement `.env.example` avec des valeurs vides.229230## Standards de code231232- Python 3.11+, type hints partout, `black` + `ruff`, docstrings sur toute fonction publique.233- Logging structuré JSON via `utils/logger.py` avec rotation quotidienne — jamais de `print()` en production.234- Tests `pytest` dans `tests/` : chaque collecteur, chaque route API, la logique de retry et de backfill.235- Gestion d'erreurs explicite : jamais de `except: pass`.236- Commits descriptifs ; branche `main` = état déployé sur m3u96b.237- **Rappel : en-tête d'auteur (Simon-Pierre Boucher / contact@spboucher.ai / Node m3u96b) dans CHAQUE fichier.**238239## Commandes utiles240241```bash242# Déploiement complet sur m3u96b243bash scripts/deploy_m3u96b.sh244245# Initialiser la base246python -m src.database.db --init247248# Collecte manuelle immédiate (tous les services)249python -m src.scheduler.daily_job --now250251# Backfill d'une date manquée252python -m src.scheduler.backfill --date 2026-08-15253254# API en local (dev)255uvicorn src.api.main:app --reload --port 8000256257# Tunnel public258bash scripts/start_ngrok.sh259260# Vérifier la santé261curl http://127.0.0.1:8000/health262```263264## Priorités absolues (dans l'ordre)2652661. **Fiabilité de la sauvegarde quotidienne** — aucune journée sans données pour aucun des 8 services.2672. Intégrité de la base (append-only, checksums, backups horodatés, rétention 90 jours).2683. Tout tourne sur le node **m3u96b** — vérification du hostname au démarrage.2694. Disponibilité de l'API publique sur www.api-ka.com (auto-restart ngrok + uvicorn).2705. En-tête d'auteur présent dans chaque fichier.2716. Logs, alertes et traçabilité de chaque collecte et chaque requête.272273---274275*Plateforme légendaire API-KA — Node m3u96b — créée par Simon-Pierre Boucher (contact@spboucher.ai)*276