Checkpoint: Application complète : deux tableaux de bord (Veille Stratégique + AAP), import Excel quotidien avec déduplication, sources multiples (local/OneDrive/FTP/SharePoint), affichage liste/vignettes, filtres multi-critères, gestion utilisateurs, logs d'import, page paramètres, authentification locale, tâche cron 06h00, 13 tests Vitest passants.
This commit is contained in:
@@ -3,47 +3,72 @@ import express from "express";
|
||||
import { createServer } from "http";
|
||||
import net from "net";
|
||||
import { createExpressMiddleware } from "@trpc/server/adapters/express";
|
||||
import * as cron from "node-cron";
|
||||
import { registerOAuthRoutes } from "./oauth";
|
||||
import { appRouter } from "../routers";
|
||||
import { createContext } from "./context";
|
||||
import { serveStatic, setupVite } from "./vite";
|
||||
import { runFullImport } from "../importer";
|
||||
import { ensureAdminExists } from "../localAuth";
|
||||
import { getSetting } from "../db";
|
||||
|
||||
function isPortAvailable(port: number): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
const server = net.createServer();
|
||||
server.listen(port, () => {
|
||||
server.close(() => resolve(true));
|
||||
});
|
||||
server.listen(port, () => { server.close(() => resolve(true)); });
|
||||
server.on("error", () => resolve(false));
|
||||
});
|
||||
}
|
||||
|
||||
async function findAvailablePort(startPort: number = 3000): Promise<number> {
|
||||
for (let port = startPort; port < startPort + 20; port++) {
|
||||
if (await isPortAvailable(port)) {
|
||||
return port;
|
||||
}
|
||||
if (await isPortAvailable(port)) return port;
|
||||
}
|
||||
throw new Error(`No available port found starting from ${startPort}`);
|
||||
}
|
||||
|
||||
// ─── Tâche d'import quotidien ─────────────────────────────────────────────────
|
||||
|
||||
let cronJob: ReturnType<typeof cron.schedule> | null = null;
|
||||
|
||||
async function scheduleDailyImport() {
|
||||
// Heure configurable, défaut 06:00
|
||||
const importTime = (await getSetting("import_time")) || "06:00";
|
||||
const [hour, minute] = importTime.split(":").map(Number);
|
||||
const cronExpr = `0 ${minute ?? 0} ${hour ?? 6} * * *`;
|
||||
|
||||
if (cronJob) {
|
||||
cronJob.stop();
|
||||
cronJob = null;
|
||||
}
|
||||
|
||||
cronJob = cron.schedule(cronExpr, async () => {
|
||||
console.log(`[Cron] Import automatique démarré à ${new Date().toISOString()}`);
|
||||
try {
|
||||
const result = await runFullImport();
|
||||
console.log(`[Cron] Import terminé — Veille: +${result.veille.newRows} | AAP: +${result.aap.newRows}`);
|
||||
} catch (e) {
|
||||
console.error("[Cron] Erreur lors de l'import:", e);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`[Cron] Import quotidien planifié à ${importTime} (${cronExpr})`);
|
||||
}
|
||||
|
||||
async function startServer() {
|
||||
const app = express();
|
||||
const server = createServer(app);
|
||||
// Configure body parser with larger size limit for file uploads
|
||||
|
||||
app.use(express.json({ limit: "50mb" }));
|
||||
app.use(express.urlencoded({ limit: "50mb", extended: true }));
|
||||
// OAuth callback under /api/oauth/callback
|
||||
|
||||
registerOAuthRoutes(app);
|
||||
// tRPC API
|
||||
|
||||
app.use(
|
||||
"/api/trpc",
|
||||
createExpressMiddleware({
|
||||
router: appRouter,
|
||||
createContext,
|
||||
})
|
||||
createExpressMiddleware({ router: appRouter, createContext })
|
||||
);
|
||||
// development mode uses Vite, production mode uses static files
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
await setupVite(app, server);
|
||||
} else {
|
||||
@@ -57,8 +82,16 @@ async function startServer() {
|
||||
console.log(`Port ${preferredPort} is busy, using port ${port} instead`);
|
||||
}
|
||||
|
||||
server.listen(port, () => {
|
||||
server.listen(port, async () => {
|
||||
console.log(`Server running on http://localhost:${port}/`);
|
||||
|
||||
// Initialisation post-démarrage
|
||||
try {
|
||||
await ensureAdminExists();
|
||||
await scheduleDailyImport();
|
||||
} catch (e) {
|
||||
console.error("[Init] Erreur d'initialisation:", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user