import 'dotenv/config'; import express from 'express'; import cors from 'cors'; import helmet from 'helmet'; import morgan from 'morgan'; import rateLimit from 'express-rate-limit'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); import authRouter from './routes/auth.js'; import investisseursRouter from './routes/investisseurs.js'; import plateformesRouter from './routes/plateformes.js'; import categoriesRouter from './routes/categories.js'; import depotsRetraitsRouter from './routes/depotsRetraits.js'; import investissementsRouter from './routes/investissements.js'; import remboursementsRouter from './routes/remboursements.js'; import simulRouter from './routes/simul.js'; import dashboardRouter from './routes/dashboard.js'; import taxreportRouter from './routes/taxreport.js'; import platefomeTaxRouter from './routes/plateforme-tax.js'; import importsRouter from './routes/imports.js'; import pfuRouter from './routes/pfu.js'; import notationRouter from './routes/notation.js'; import garantiesRouter from './routes/garanties.js'; import reinvestissementsRouter from './routes/reinvestissements.js'; import correctionsRouter from './routes/corrections.js'; import comptesRouter from './routes/comptes.js'; import preferencesRouter from './routes/preferences.js'; import iconsRouter from './routes/icons.js'; import { errorHandler } from './middleware/errorHandler.js'; import { requireAuth, requireAdmin } from './middleware/auth.js'; import { startAutoStatutJob } from './jobs/autoStatut.js'; import adminRouter from './routes/admin.js'; import invitationsRouter from './routes/invitations.js'; import auditLogsRouter from './routes/auditLogs.js'; import tauxCreditImpotRouter from './routes/tauxCreditImpot.js'; import referentielRouter from './routes/referentiel.js'; import referentielPublicRouter from './routes/referentielPublic.js'; import refCategoriesRouter from './routes/ref-categories.js'; import refSecteursRouter from './routes/ref-secteurs.js'; import categoriesInvRouter from './routes/categories-inv.js'; import secteursInvRouter from './routes/secteurs-inv.js'; import associationsInvRouter from './routes/associations-inv.js'; import db from './db/index.js'; import { getSmtpConfig } from './utils/mailer.js'; const app = express(); const PORT = process.env.PORT || 4000; app.use(helmet({ crossOriginResourcePolicy: { policy: 'cross-origin' } })); app.use(cors()); app.use(express.json({ limit: '5mb' })); app.use(morgan('dev')); // ── Logos plateformes — servis sans authentification ───────────────────── const _dataDir = process.env.DATA_DIR ? path.resolve(process.env.DATA_DIR) : path.resolve(__dirname, '../../data'); // fallback dev : 2 niveaux au-dessus de src/ const logosDir = path.join(_dataDir, 'logos'); app.use('/api/logos', express.static(logosDir, { maxAge: '1d', fallthrough: false })); const iconsDir2 = path.join(_dataDir, 'icons'); app.use('/api/icons-files', express.static(iconsDir2, { maxAge: '1h', fallthrough: false })); // Basic rate-limit on auth endpoints const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 50, standardHeaders: true, legacyHeaders: false, }); app.get('/api/health', (_, res) => res.json({ ok: true, ts: new Date().toISOString() })); // Informations publiques de la plateforme (utilisées sur la page de login) app.get('/api/app-info', (_, res) => { try { const cfg = getSmtpConfig(); const icon = db.prepare(`SELECT filename FROM app_icons WHERE name = 'logo-app' LIMIT 1`).get(); res.json({ appName: cfg.appName || 'Crowdlending Tracker', iconUrl: icon ? `/api/icons-files/${icon.filename}` : null, }); } catch { res.json({ appName: 'Crowdlending Tracker', iconUrl: null }); } }); app.use('/api/auth', authLimiter, authRouter); // All routes below require authentication app.use('/api/investisseurs', requireAuth, investisseursRouter); app.use('/api/plateformes', requireAuth, plateformesRouter); app.use('/api/categories', requireAuth, categoriesRouter); app.use('/api/depots-retraits', requireAuth, depotsRetraitsRouter); app.use('/api/investissements', requireAuth, investissementsRouter); app.use('/api/remboursements', requireAuth, remboursementsRouter); app.use('/api/simul', requireAuth, simulRouter); app.use('/api/dashboard', requireAuth, dashboardRouter); app.use('/api/taxreport', requireAuth, taxreportRouter); app.use('/api/plateforme-tax', requireAuth, platefomeTaxRouter); app.use('/api/imports', requireAuth, importsRouter); app.use('/api/pfu', requireAuth, pfuRouter); app.use('/api/notation', requireAuth, notationRouter); app.use('/api/garanties', requireAuth, garantiesRouter); app.use('/api/reinvestissements', requireAuth, reinvestissementsRouter); app.use('/api/corrections', requireAuth, correctionsRouter); app.use('/api/comptes', requireAuth, comptesRouter); app.use('/api/preferences', requireAuth, preferencesRouter); app.use('/api/icons', requireAuth, iconsRouter); app.use('/api/admin', requireAuth, requireAdmin, adminRouter); app.use('/api/admin/audit-logs', requireAuth, requireAdmin, auditLogsRouter); // Invitations : routes admin protégées + routes publiques (register/validate) app.use('/api/admin/invitations', requireAuth, requireAdmin, invitationsRouter); app.use('/api/invitations', invitationsRouter); app.use('/api/taux-credit-impot', requireAuth, tauxCreditImpotRouter); app.use('/api/referentiel', requireAuth, requireAdmin, referentielRouter); app.use('/api/referentiel-public', requireAuth, referentielPublicRouter); app.use('/api/ref-categories', requireAuth, requireAdmin, refCategoriesRouter); app.use('/api/ref-secteurs', requireAuth, requireAdmin, refSecteursRouter); app.use('/api/categories-inv', requireAuth, categoriesInvRouter); app.use('/api/secteurs-inv', requireAuth, secteursInvRouter); app.use('/api', requireAuth, associationsInvRouter); app.use(errorHandler); app.listen(PORT, () => { console.log(`Crowdlending API listening on http://localhost:${PORT}`); });