> ## Documentation Index
> Fetch the complete documentation index at: https://docs.poihunter.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Smoke tests — cycle complet par exchange/paire

> Stratégie pour valider NEW → RUNNING → CLOSED par phase, avec cleanup en dernière étape.

# Smoke tests : cycle bout en bout par exchange/paire

Les positions créées en **isTest** servent de **jeu de données** d’une phase à l’autre. Le **cleanup** (suppression des positions isTest) est **isolé à la fin** du run, une fois tout le cycle validé.

## Phases à couvrir

| Phase                              | Objectif                                                 | Données d’entrée / déclencheur                                                                            |
| ---------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| **1. NEW**                         | Création position (BUY1 placé, statut NEW)               | POST /webhooks/tradingview (payload isTest par exchange/paire)                                            |
| **2. Transition NEW → RUNNING**    | BUY1 considéré exécuté → calculs TP1/TP2, statut RUNNING | Même webhook (nouvelle bougie) une fois BUY1 fermé côté exchange, ou endpoint dédié (avancement contrôlé) |
| **3. RUNNING**                     | Vérifier état RUNNING (BUY2, TP1, TP2, PnL)              | Lecture des positions isTest (GET ou endpoint de validation)                                              |
| **4. Transition RUNNING → CLOSED** | Fermeture (tendance ou SL) → statut CLOSED               | Webhook avec bougie “changement tendance”, ou endpoint dédié pour forcer processClose sur isTest          |
| **5. CLOSED**                      | Vérifier position fermée, coûts/frais finaux             | Lecture des positions isTest                                                                              |
| **6. Cleanup**                     | Supprimer toutes les positions isTest                    | GET /tests/cleanup-test-positions (Bearer) — **une seule fois à la fin**                                  |

## Deux approches possibles

### A. Tout via webhook (conditions réelles, timing dépendant)

* **Phase 1** : un POST par paire (comme aujourd’hui) → positions NEW.
* **Phase 2** : re-POST **même paire**, **nouvelle bougie** (SMOKETIME + offset) : le flux traite la position existante ; si BUY1 est déjà fermé côté exchange, transition NEW → RUNNING.
* **Phase 3** : pas d’appel HTTP dédié ; on considère que le rapport de la phase 2 (ou un GET de santé) suffit, ou on ajoute un **GET /tests/smoke/validate** qui retourne l’état des positions isTest (NEW / RUNNING / CLOSED par exchange/paire).
* **Phase 4** : re-POST avec une **bougie qui déclenche le changement de tendance** (`trend` bear pour une position LONG, `trend` bull pour une position SHORT) pour que `swingPositions` appelle `processClose` → CLOSED.
* **Phase 5** : même GET de validation ou rapport phase 4.
* **Phase 6** : **cleanup** (GET cleanup-test-positions).

**Intérêt** : aucun code métier spécifique “test”, tout passe par le vrai webhook.\
**Inconvénient** : dépend de l’exécution réelle des ordres (BUY1 peut ne pas être fermé entre deux runs) et du timing des bougies.

### B. Endpoints dédiés “smoke” (contrôlé, recommandé pour CI) — **implémenté**

Exposer de petits endpoints **protégés (Bearer CI\_TEST\_SECRET)** qui enchaînent la logique métier sur les positions **isTest** uniquement :

| Endpoint                                         | Rôle                                                                                                                                                |
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| **POST /webhooks/tradingview** (existant)        | Phase 1 : création NEW (payload isTest par paire).                                                                                                  |
| **POST /tests/smoke/advance-to-running**         | Phase 2 : pour chaque position isTest en NEW, simuler “BUY1 fermé” en base puis `checkBuy1Completed` → passage RUNNING.                             |
| **GET /tests/smoke/status**                      | Phases 3 et 5 : retourne pour chaque position isTest : exchange, paire, status, orderSide, ids des ordres (buy1, buy2, tp1, tp2, close).            |
| **POST /tests/smoke/advance-to-closed**          | Phase 4 : pour les positions isTest en RUNNING, mise à jour DB uniquement (status CLOSED, closedAt, closedReason TEST\_NEW) — pas d’appel exchange. |
| **GET /tests/cleanup-test-positions** (existant) | Phase 6 : **cleanup unique en fin de run**.                                                                                                         |

La CI enchaînerait :\
`check-exchanges` → **Phase 1** (N curls webhook) → **Phase 2** (POST advance-to-running) → **Phase 3** (GET status, vérifier RUNNING) → **Phase 4** (POST advance-to-closed) → **Phase 5** (GET status, vérifier CLOSED) → **Phase 6** (GET cleanup-test-positions) → génération rapports/badges.

**Intérêt** : exécution déterministe, pas de dépendance au remplissage des ordres en temps réel.

## Implémentation actuelle (option B)

* **GET /tests/smoke/status** : implémenté ; réponse `{ success, positions: [{ id, exchange, pair, status, orderSide, buy1OrderId, … }], generatedAt }`.
* **POST /tests/smoke/advance-to-running** : implémenté ; réponse `{ success, phase, advanced, errors, generatedAt }` (207 si au moins une erreur).
* **POST /tests/smoke/advance-to-closed** : implémenté ; mise à jour DB seule (closedReason TEST\_NEW).
* **GET /tests/cleanup-test-positions** : existant ; à appeler **une seule fois en fin de cycle**.

### Lancer les smoke tests en local

1. **Secret** : exporte `CI_TEST_SECRET` (même valeur que dans GitHub / SST). Optionnel : crée un `.env` à la racine avec `CI_TEST_SECRET=...` puis `source .env`.
2. **Cible** :
   * **Prod** (défaut) : `npm run smoke:local` ou `SMOKE_TARGET=prod npm run smoke:local` → `https://api.poihunter.com`
   * **Dev** : `SMOKE_TARGET=dev npm run smoke:local` → `https://api.dev.poihunter.com`
   * **URL personnalisée** (ex. `sst dev`) : `API=https://xxx.lambda-url....on.aws npm run smoke:local`
3. **Commande** :
   ```bash theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
   source .env   # si CI_TEST_SECRET est dans .env
   npm run smoke:local
   SMOKE_TARGET=dev npm run smoke:local
   ```
   Le script enchaîne check-exchanges, Phase 1 (webhooks), 2 à 6 (advance, status, cleanup) et affiche les réponses. Les rapports sont écrits dans `docs/reports/webhook-smoke/` et `docs/reports/vitest/specs/`.

**Paires exécutées** : la Phase 1 ne lance des webhooks que pour les paires listées dans `scripts/ci/webhook-smoke/pairs-to-run.txt` (une par ligne, nom du fichier sans `.json`). Par défaut seule **kucoinfutures-griffainusdt** est activée ; ajouter `binance-syrupusdc` et `mexc-damusdt` quand nécessaire.

### Comportement en CI

Le nombre de positions créées en Phase 1 (et donc `advanced` en Phase 2, `deletedCount` en Phase 6) peut être **inférieur au nombre de requêtes webhook** : la création d’une position exige une **previousCandle** en base pour la paire/timeframe et le respect des conditions LONG/SHORT (wma50 vs wma50\_htf, rangeFilter). Chaque webhook renvoie 200 avec `eptProcessed: 1` dès que la bougie et les EPT sont traités ; seules les paires qui ont déjà une bougie “précédente” et les conditions remplies déclenchent `processBuy1`. Le cycle (NEW → RUNNING → CLOSED → cleanup) s’applique à **toutes** les positions isTest créées lors du run.

## Rapport unique “cycle” (optionnel)

Un même fichier `docs/reports/webhook-smoke/cycle-report.json` pourrait agréger :

* **phase1** : résultat des POST webhook par paire (déjà en place).
* **phase2** : résultat de l’avancement vers RUNNING (par paire ou global).
* **phase3** : extrait du GET status (positions RUNNING).
* **phase4** : résultat de l’avancement vers CLOSED.
* **phase5** : extrait du GET status (positions CLOSED).
* **phase6** : résultat du cleanup (deletedCount).

Cela permet d’avoir **un seul artefact** “cycle bout en bout par exchange/paire” et de lier les badges ou la doc à ce rapport.
