From 9a429d476d1c5fdf268c32779818e54750635ce2 Mon Sep 17 00:00:00 2001 From: streaper2 Date: Wed, 26 Aug 2026 08:42:16 +0200 Subject: [PATCH] feat: initialize backend service with Express, SQLite logging, and API utilities --- backendia/Dockerfile | 8 +- backendia/dashboard/src/lib/api.ts | 5 +- backendia/package.json | 3 + backendia/server.js | 146 +++++++++++++++++------------ 4 files changed, 102 insertions(+), 60 deletions(-) diff --git a/backendia/Dockerfile b/backendia/Dockerfile index dbdd6ef8..60fad693 100644 --- a/backendia/Dockerfile +++ b/backendia/Dockerfile @@ -10,10 +10,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* COPY package*.json ./ -RUN npm ci --omit=dev && npm rebuild sqlite3 --build-from-source +COPY dashboard/package*.json ./dashboard/ + +RUN npm install && npm rebuild sqlite3 --build-from-source +RUN cd dashboard && npm install COPY . . +# Build du Dashboard Next.js +RUN cd dashboard && npm run build + # Dossiers nécessaires RUN mkdir -p uploads/images uploads/data exports diff --git a/backendia/dashboard/src/lib/api.ts b/backendia/dashboard/src/lib/api.ts index 81f915e9..db0b0e0b 100644 --- a/backendia/dashboard/src/lib/api.ts +++ b/backendia/dashboard/src/lib/api.ts @@ -1,4 +1,7 @@ -export const API_BASE_URL = 'http://127.0.0.1:3000'; +const isServer = typeof window === 'undefined'; +export const API_BASE_URL = isServer + ? `http://127.0.0.1:${process.env.PORT || 3000}` + : ''; export async function fetchApi(endpoint: string) { const res = await fetch(`${API_BASE_URL}${endpoint}`, { diff --git a/backendia/package.json b/backendia/package.json index 1858be48..5d0413f6 100644 --- a/backendia/package.json +++ b/backendia/package.json @@ -18,6 +18,9 @@ "dotenv": "^17.4.2", "express": "^5.2.1", "multer": "^2.1.1", + "next": "^16.2.4", + "react": "^19.2.4", + "react-dom": "^19.2.4", "sharp": "^0.35.3", "sqlite3": "^6.0.1" } diff --git a/backendia/server.js b/backendia/server.js index 7ce080a5..5675b271 100644 --- a/backendia/server.js +++ b/backendia/server.js @@ -36,57 +36,61 @@ const db = new sqlite3.Database(dbPath, (err) => { console.error('Erreur de connexion à SQLite:', err.message); } else { console.log('Connecté à la base de données SQLite.'); - db.run(`CREATE TABLE IF NOT EXISTS user_stats ( - wallet_hash TEXT PRIMARY KEY, - photo_count INTEGER DEFAULT 0, - last_upload DATETIME DEFAULT CURRENT_TIMESTAMP - )`); + db.serialize(() => { + db.run(`CREATE TABLE IF NOT EXISTS user_stats ( + wallet_hash TEXT PRIMARY KEY, + photo_count INTEGER DEFAULT 0, + last_upload DATETIME DEFAULT CURRENT_TIMESTAMP + )`); - db.run(`CREATE TABLE IF NOT EXISTS banned_wallets ( - wallet_hash TEXT PRIMARY KEY, - reason TEXT, - banned_at DATETIME DEFAULT CURRENT_TIMESTAMP, - banned_by TEXT DEFAULT 'Admin' - )`); + db.run(`CREATE TABLE IF NOT EXISTS banned_wallets ( + wallet_hash TEXT PRIMARY KEY, + reason TEXT, + banned_at DATETIME DEFAULT CURRENT_TIMESTAMP, + banned_by TEXT DEFAULT 'Admin' + )`); - db.run(`CREATE TABLE IF NOT EXISTS upload_logs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, - session_id TEXT, - wallet_hash TEXT, - image_filename TEXT, - json_filename TEXT, - file_size INTEGER, - ip_address TEXT, - user_agent TEXT, - device_model TEXT, - device_os TEXT, - target_type TEXT, - weapon TEXT, - distance_meters INTEGER, - impacts_count INTEGER DEFAULT 0, - status TEXT DEFAULT 'SUCCESS', - target_valid INTEGER DEFAULT 1, - target_status TEXT DEFAULT 'VALID', - target_confidence REAL DEFAULT 1.0, - target_rings_count INTEGER DEFAULT 0, - target_details TEXT, - error_message TEXT, - raw_metadata TEXT - )`); + db.run(`CREATE TABLE IF NOT EXISTS upload_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + session_id TEXT, + wallet_hash TEXT, + image_filename TEXT, + json_filename TEXT, + file_size INTEGER, + ip_address TEXT, + user_agent TEXT, + device_model TEXT, + device_os TEXT, + target_type TEXT, + weapon TEXT, + distance_meters INTEGER, + impacts_count INTEGER DEFAULT 0, + status TEXT DEFAULT 'SUCCESS', + target_valid INTEGER DEFAULT 1, + target_status TEXT DEFAULT 'VALID', + target_confidence REAL DEFAULT 1.0, + target_rings_count INTEGER DEFAULT 0, + target_details TEXT, + error_message TEXT, + raw_metadata TEXT + )`); - // Migration safe des colonnes OpenCV si la table existait déjà - const migrations = [ - "ALTER TABLE upload_logs ADD COLUMN target_valid INTEGER DEFAULT 1", - "ALTER TABLE upload_logs ADD COLUMN target_status TEXT DEFAULT 'VALID'", - "ALTER TABLE upload_logs ADD COLUMN target_confidence REAL DEFAULT 1.0", - "ALTER TABLE upload_logs ADD COLUMN target_rings_count INTEGER DEFAULT 0", - "ALTER TABLE upload_logs ADD COLUMN target_details TEXT" - ]; - migrations.forEach(sql => db.run(sql, () => {})); + // Migration safe des colonnes OpenCV si la table existait déjà + const migrations = [ + "ALTER TABLE upload_logs ADD COLUMN target_valid INTEGER DEFAULT 1", + "ALTER TABLE upload_logs ADD COLUMN target_status TEXT DEFAULT 'VALID'", + "ALTER TABLE upload_logs ADD COLUMN target_confidence REAL DEFAULT 1.0", + "ALTER TABLE upload_logs ADD COLUMN target_rings_count INTEGER DEFAULT 0", + "ALTER TABLE upload_logs ADD COLUMN target_details TEXT" + ]; + migrations.forEach(sql => { + db.run(sql, () => {}); + }); - db.run(`CREATE INDEX IF NOT EXISTS idx_upload_logs_wallet ON upload_logs(wallet_hash)`); - db.run(`CREATE INDEX IF NOT EXISTS idx_upload_logs_timestamp ON upload_logs(timestamp)`); + db.run(`CREATE INDEX IF NOT EXISTS idx_upload_logs_wallet ON upload_logs(wallet_hash)`); + db.run(`CREATE INDEX IF NOT EXISTS idx_upload_logs_timestamp ON upload_logs(timestamp)`); + }); } }); @@ -814,14 +818,40 @@ app.use((err, req, res, next) => { res.status(500).json({ error: err.message || 'Une erreur inattendue est survenue' }); }); -// Démarrer le serveur -app.listen(PORT, () => { - console.log(`=================================`); - console.log(`Serveur Backend IA démarré`); - console.log(`Port: ${PORT}`); - console.log(`Dossiers:`); - console.log(` - Images: ${imagesDir}`); - console.log(` - Data : ${dataDir}`); - console.log(` - Export: ${exportsDir}`); - console.log(`=================================`); -}); +// Intégration du Dashboard Next.js +const dashboardDir = path.join(__dirname, 'dashboard'); +const dev = process.env.NODE_ENV !== 'production'; + +let nextApp; +try { + const next = require('next'); + nextApp = next({ dev, dir: dashboardDir }); +} catch (e) { + console.warn("Module 'next' non disponible, mode API seule."); +} + +async function startServer() { + if (nextApp) { + try { + await nextApp.prepare(); + const handle = nextApp.getRequestHandler(); + app.all('*', (req, res) => handle(req, res)); + console.log("Dashboard Next.js initialisé avec succès."); + } catch (err) { + console.error("Erreur d'initialisation du Dashboard Next.js:", err); + } + } + + app.listen(PORT, () => { + console.log(`=================================`); + console.log(`Serveur Backend IA & Dashboard démarré`); + console.log(`Port: ${PORT}`); + console.log(`Dossiers:`); + console.log(` - Images: ${imagesDir}`); + console.log(` - Data : ${dataDir}`); + console.log(` - Export: ${exportsDir}`); + console.log(`=================================`); + }); +} + +startServer();