]> git.digitality.be Git - pdw25-26/commitdiff
Ajout des routes pour la stratégie
authorSacheat <sacha.libion@outlook.com>
Sun, 1 Mar 2026 14:03:18 +0000 (15:03 +0100)
committerSacheat <sacha.libion@outlook.com>
Sun, 1 Mar 2026 14:03:18 +0000 (15:03 +0100)
Wallette/server/modules/strategy/repositories/SignalRepo.js
Wallette/server/modules/strategy/repositories/StrategyRepo.js
Wallette/server/modules/strategy/server.js

index b9adfd54737a98fe59a60f99f067de742b58e382..1956a1a0d5b5e1e792cac26c171980136f661ade 100644 (file)
@@ -43,6 +43,36 @@ class SignalRepo {
             throw error;
         }
     }
+
+    /**
+     * Récupère le tout dernier signal généré pour un utilisateur et une paire spécifique.
+     * Appelée par le Dashboard Web (GET /api/signal/current)
+     */
+    async getLatestSignal(userId, pairCode) {
+        const sql = `
+            SELECT 
+                s.signal_id,
+                s.action,
+                s.confidence,
+                s.reason,
+                s.price_at_signal,
+                s.optimal_price,
+                s.stop_loss_price,
+                s.timestamp_ms,
+                us.mode,
+                p.pair_code
+            FROM signals s
+            JOIN user_strategies us ON s.user_strategy_id = us.user_strategy_id
+            JOIN pairs p ON us.pair_id = p.pair_id
+            WHERE us.user_id = ? AND p.pair_code = ?
+            ORDER BY s.timestamp_ms DESC
+            LIMIT 1
+        `;
+
+        const [rows] = await pool.query(sql, [userId, pairCode]);
+
+        return rows.length > 0 ? rows[0] : null;
+    }
 }
 
 const signalRepo = new SignalRepo();
index b0cdc80b23464855ce80d01e0cd6ffa0c88843e7..3432d54036dafc74fac21f854c6b4e3b7fed164f 100644 (file)
@@ -30,6 +30,39 @@ class StrategyRepo {
             throw error;
         }
     }
+
+    /**
+     * Crée ou met à jour la stratégie d'un utilisateur pour une paire donnée.
+     * Appelée par le Frontend / App Mobile (POST /api/strategy/select)
+     */
+    async upsertUserStrategy(userId, pairId, mode, params) {
+        const now = Date.now();
+        const strategyKey = `${mode}_${pairId}`; // Génération d'une clé simple
+
+        // On vérifie si l'utilisateur a déjà une configuration pour cette paire
+        const checkSql = `SELECT user_strategy_id FROM user_strategies WHERE user_id = ? AND pair_id = ?`;
+        const [rows] = await db.query(checkSql, [userId, pairId]); // ⚠️ Remplace 'db' par le nom de ta variable de connexion (souvent 'pool' ou 'db')
+
+        if (rows.length > 0) {
+            // MISE À JOUR : La stratégie existe, on l'écrase avec le nouveau mode
+            const updateSql = `
+                UPDATE user_strategies 
+                SET mode = ?, params = ?, strategy_key = ?, is_active = 1, updated_at_ms = ?
+                WHERE user_id = ? AND pair_id = ?
+            `;
+            await db.query(updateSql, [mode, params, strategyKey, now, userId, pairId]);
+            return { action: 'updated', user_id: userId, pair_id: pairId, mode };
+        } else {
+            // CRÉATION : C'est la première fois qu'il configure cette paire
+            const insertSql = `
+                INSERT INTO user_strategies 
+                (user_strategy_id, user_id, pair_id, strategy_key, mode, params, is_active, created_at_ms, updated_at_ms)
+                VALUES (UUID(), ?, ?, ?, ?, ?, 1, ?, ?)
+            `;
+            await db.query(insertSql, [userId, pairId, strategyKey, mode, params, now, now]);
+            return { action: 'created', user_id: userId, pair_id: pairId, mode };
+        }
+    }
 }
 
 const strategyRepo = new StrategyRepo();
index 7e6d8c7be39755b20c68cc1c4e6558483c6b93fd..251341b225b36d09fea1eda2b141cdefbd8b585c 100644 (file)
@@ -1,16 +1,5 @@
 // =========================================================
-// STRATEGY SERVICE - Serveur standalone (stub)
-// =========================================================
-// Ce fichier est volontairement minimal.
-// Son rôle : avoir un process indépendant sur le port 3002
-// pour que le gateway ne retourne pas 502 sur /api/strategy/*
-// et pour que le health check soit vert au démarrage.
-//
-// USAGE : node modules/strategy/server.js (depuis Wallette/server/)
-// PORT  : process.env.STRATEGY_PORT || 3002
-//
-// QUAND Sacha aura finalisé son module, ce fichier sera
-// remplacé par un vrai serveur avec les routes strategy.
+// STRATEGY SERVICE - Serveur
 // =========================================================
 
 import cors from 'cors';
@@ -19,6 +8,10 @@ import express from 'express';
 import path from 'path';
 import { fileURLToPath } from 'url';
 
+// IMPORT DES REPOSITORIES
+import strategyRepo from './repositories/StrategyRepo.js';
+import signalRepo from './repositories/SignalRepo.js';
+
 const __filename = fileURLToPath(import.meta.url);
 const __dirname  = path.dirname(__filename);
 dotenv.config({ path: path.resolve(__dirname, '../../.env') });
@@ -30,38 +23,85 @@ app.use(cors());
 app.use(express.json());
 
 // =========================================================
-// HEALTH CHECK (requis par le gateway)
+// HEALTH CHECk
 // =========================================================
 app.get('/health', (req, res) => {
   res.json({
     ok:      true,
     service: 'strategy-service',
     port:    PORT,
-    status:  'stub — module Sacha en cours d\'intégration',
+    status:  'ONLINE — Module opérationnel',
   });
 });
 
 // =========================================================
-// STUB ROUTES /api/strategy/*
+// ROUTE 1 : SÉLECTIONNER UNE STRATÉGIE (App Mobile / Web)
+// POST /api/strategy/select
+// =========================================================
+app.post('/api/strategy/select', async (req, res) => {
+  try {
+    const { userId, pairId, mode, params } = req.body;
+
+    if (!userId || !pairId || !mode) {
+      return res.status(400).json({ ok: false, message: "Données incomplètes (userId, pairId, mode requis)." });
+    }
+
+    // Appel au Repository pour insérer/mettre à jour la stratégie
+    const result = await strategyRepo.upsertUserStrategy(userId, pairId, mode, params || '{}');
+
+    return res.status(200).json({
+      ok: true,
+      message: "Stratégie configurée avec succès",
+      data: result
+    });
+  } catch (error) {
+    console.error("Erreur POST /api/strategy/select :", error);
+    return res.status(500).json({ ok: false, message: "Erreur interne du serveur." });
+  }
+});
+
+// =========================================================
+// ROUTE 2 : RÉCUPÉRER LE DERNIER SIGNAL (Dashboard Web)
+// GET /api/signal/current?userId=...&pair=...
+// =========================================================
+app.get('/api/signal/current', async (req, res) => {
+  try {
+    const { userId, pair } = req.query;
+
+    if (!userId || !pair) {
+      return res.status(400).json({ ok: false, message: "Les paramètres userId et pair sont requis." });
+    }
+
+    // Appel au Repository pour chercher le dernier signal
+    const latestSignal = await signalRepo.getLatestSignal(userId, pair);
+
+    if (!latestSignal) {
+      return res.status(404).json({ ok: true, data: null, message: "Aucun signal récent trouvé." });
+    }
+
+    return res.status(200).json({ ok: true, data: latestSignal });
+  } catch (error) {
+    console.error("Erreur GET /api/signal/current :", error);
+    return res.status(500).json({ ok: false, message: "Erreur interne du serveur." });
+  }
+});
+
+// =========================================================
+// FALLBACK POUR LES AUTRES ROUTES STRATEGY (Toujours en 501)
 // =========================================================
-// Répond 501 (Not Implemented) pour toutes les routes
-// au lieu de laisser le gateway retourner 502.
 app.use('/api/strategy', (req, res) => {
   res.status(501).json({
-    ok:    false,
-    error: {
-      code:    'NOT_IMPLEMENTED',
-      message: 'strategy-service non encore disponible',
-    },
+    ok: false,
+    error: { code: 'NOT_IMPLEMENTED', message: 'Cette fonctionnalité arrive bientôt.' },
   });
 });
 
 // =========================================================
-// 404
+// 404 GLOBAL
 // =========================================================
 app.use((req, res) => {
   res.status(404).json({
-    ok:    false,
+    ok: false,
     error: { code: 'NOT_FOUND', message: 'Route non trouvée' },
   });
 });
@@ -72,9 +112,10 @@ app.use((req, res) => {
 app.listen(PORT, () => {
   console.log(`
 ╔══════════════════════════════════════════╗
-║      STRATEGY SERVICE (STUB)             ║
+║      STRATEGY SERVICE (ONLINE)           ║
 ║  HTTP : http://localhost:${PORT}             ║
-║  → /health          = OK                 ║
-║  → /api/strategy/*  = 501                ║
+║  → /health                  = OK         ║
+║  → POST /api/strategy/select = OK         ║
+║  → GET /api/signal/current   = OK         ║
 ╚══════════════════════════════════════════╝`);
-});
+});
\ No newline at end of file