feat: initialize backend service with Express, SQLite logging, and API utilities
Deploy Backendia / deploy (push) Successful in 5m0s

This commit is contained in:
streaper2
2026-08-26 08:42:16 +02:00
parent 7923d1b2b2
commit 9a429d476d
4 changed files with 102 additions and 60 deletions
+7 -1
View File
@@ -10,10 +10,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
COPY package*.json ./ 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 . . COPY . .
# Build du Dashboard Next.js
RUN cd dashboard && npm run build
# Dossiers nécessaires # Dossiers nécessaires
RUN mkdir -p uploads/images uploads/data exports RUN mkdir -p uploads/images uploads/data exports
+4 -1
View File
@@ -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) { export async function fetchApi(endpoint: string) {
const res = await fetch(`${API_BASE_URL}${endpoint}`, { const res = await fetch(`${API_BASE_URL}${endpoint}`, {
+3
View File
@@ -18,6 +18,9 @@
"dotenv": "^17.4.2", "dotenv": "^17.4.2",
"express": "^5.2.1", "express": "^5.2.1",
"multer": "^2.1.1", "multer": "^2.1.1",
"next": "^16.2.4",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"sharp": "^0.35.3", "sharp": "^0.35.3",
"sqlite3": "^6.0.1" "sqlite3": "^6.0.1"
} }
+88 -58
View File
@@ -36,57 +36,61 @@ const db = new sqlite3.Database(dbPath, (err) => {
console.error('Erreur de connexion à SQLite:', err.message); console.error('Erreur de connexion à SQLite:', err.message);
} else { } else {
console.log('Connecté à la base de données SQLite.'); console.log('Connecté à la base de données SQLite.');
db.run(`CREATE TABLE IF NOT EXISTS user_stats ( db.serialize(() => {
wallet_hash TEXT PRIMARY KEY, db.run(`CREATE TABLE IF NOT EXISTS user_stats (
photo_count INTEGER DEFAULT 0, wallet_hash TEXT PRIMARY KEY,
last_upload DATETIME DEFAULT CURRENT_TIMESTAMP photo_count INTEGER DEFAULT 0,
)`); last_upload DATETIME DEFAULT CURRENT_TIMESTAMP
)`);
db.run(`CREATE TABLE IF NOT EXISTS banned_wallets ( db.run(`CREATE TABLE IF NOT EXISTS banned_wallets (
wallet_hash TEXT PRIMARY KEY, wallet_hash TEXT PRIMARY KEY,
reason TEXT, reason TEXT,
banned_at DATETIME DEFAULT CURRENT_TIMESTAMP, banned_at DATETIME DEFAULT CURRENT_TIMESTAMP,
banned_by TEXT DEFAULT 'Admin' banned_by TEXT DEFAULT 'Admin'
)`); )`);
db.run(`CREATE TABLE IF NOT EXISTS upload_logs ( db.run(`CREATE TABLE IF NOT EXISTS upload_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
session_id TEXT, session_id TEXT,
wallet_hash TEXT, wallet_hash TEXT,
image_filename TEXT, image_filename TEXT,
json_filename TEXT, json_filename TEXT,
file_size INTEGER, file_size INTEGER,
ip_address TEXT, ip_address TEXT,
user_agent TEXT, user_agent TEXT,
device_model TEXT, device_model TEXT,
device_os TEXT, device_os TEXT,
target_type TEXT, target_type TEXT,
weapon TEXT, weapon TEXT,
distance_meters INTEGER, distance_meters INTEGER,
impacts_count INTEGER DEFAULT 0, impacts_count INTEGER DEFAULT 0,
status TEXT DEFAULT 'SUCCESS', status TEXT DEFAULT 'SUCCESS',
target_valid INTEGER DEFAULT 1, target_valid INTEGER DEFAULT 1,
target_status TEXT DEFAULT 'VALID', target_status TEXT DEFAULT 'VALID',
target_confidence REAL DEFAULT 1.0, target_confidence REAL DEFAULT 1.0,
target_rings_count INTEGER DEFAULT 0, target_rings_count INTEGER DEFAULT 0,
target_details TEXT, target_details TEXT,
error_message TEXT, error_message TEXT,
raw_metadata TEXT raw_metadata TEXT
)`); )`);
// Migration safe des colonnes OpenCV si la table existait déjà // Migration safe des colonnes OpenCV si la table existait déjà
const migrations = [ const migrations = [
"ALTER TABLE upload_logs ADD COLUMN target_valid INTEGER DEFAULT 1", "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_status TEXT DEFAULT 'VALID'",
"ALTER TABLE upload_logs ADD COLUMN target_confidence REAL DEFAULT 1.0", "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_rings_count INTEGER DEFAULT 0",
"ALTER TABLE upload_logs ADD COLUMN target_details TEXT" "ALTER TABLE upload_logs ADD COLUMN target_details TEXT"
]; ];
migrations.forEach(sql => db.run(sql, () => {})); 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_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_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' }); res.status(500).json({ error: err.message || 'Une erreur inattendue est survenue' });
}); });
// Démarrer le serveur // Intégration du Dashboard Next.js
app.listen(PORT, () => { const dashboardDir = path.join(__dirname, 'dashboard');
console.log(`=================================`); const dev = process.env.NODE_ENV !== 'production';
console.log(`Serveur Backend IA démarré`);
console.log(`Port: ${PORT}`); let nextApp;
console.log(`Dossiers:`); try {
console.log(` - Images: ${imagesDir}`); const next = require('next');
console.log(` - Data : ${dataDir}`); nextApp = next({ dev, dir: dashboardDir });
console.log(` - Export: ${exportsDir}`); } catch (e) {
console.log(`=================================`); 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();