Spaces:
Paused
Paused
| const path = require("path"); | |
| const { config } = require("./config/env"); | |
| const { createLogger } = require("./config/logger"); | |
| const { createApp } = require("./app"); | |
| const { createRuntimeState } = require("./services/runtimeState"); | |
| const { createDbPool, verifyDbConnection } = require("./db/pool"); | |
| const { runMigrations, runSeeds } = require("./db/migrator"); | |
| const { createMqttConsumer } = require("./mqtt/client"); | |
| const { createTelemetryIngestService } = require("./services/telemetryIngestService"); | |
| const { createAlertEngineService } = require("./services/alertEngineService"); | |
| const { createFleetService } = require("./services/fleetService"); | |
| const { createAlertsService } = require("./services/alertsService"); | |
| const { createReportsService } = require("./services/reportsService"); | |
| const { createAdminService } = require("./services/adminService"); | |
| const { createAuthService } = require("./services/authService"); | |
| const { createTripsService } = require("./services/tripsService"); | |
| const { createTripSummaryAiService } = require("./services/tripSummaryAiService"); | |
| const { startOfflineScannerJob } = require("./jobs/offlineScannerJob"); | |
| const telemetryRepository = require("./repositories/telemetryRepository"); | |
| const assetRepository = require("./repositories/assetRepository"); | |
| const alertRulesRepository = require("./repositories/alertRulesRepository"); | |
| const alertsRepository = require("./repositories/alertsRepository"); | |
| const reportsRepository = require("./repositories/reportsRepository"); | |
| const adminRepository = require("./repositories/adminRepository"); | |
| const authRepository = require("./repositories/authRepository"); | |
| const auditRepository = require("./repositories/auditRepository"); | |
| const tripsRepository = require("./repositories/tripsRepository"); | |
| const telemetryValidator = require("./validators/telemetryValidator"); | |
| async function main() { | |
| const logger = createLogger(config.logLevel); | |
| const runtimeState = createRuntimeState(); | |
| const pool = createDbPool(config, logger); | |
| let mqttConsumer = null; | |
| let offlineScannerJob = null; | |
| let server = null; | |
| let shuttingDown = false; | |
| async function shutdown(signal) { | |
| if (shuttingDown) { | |
| return; | |
| } | |
| shuttingDown = true; | |
| logger.info("Shutdown started", { signal }); | |
| try { | |
| if (offlineScannerJob) { | |
| offlineScannerJob.stop(); | |
| } | |
| if (mqttConsumer) { | |
| mqttConsumer.stop(); | |
| } | |
| if (server) { | |
| await new Promise((resolve) => server.close(resolve)); | |
| } | |
| await pool.end(); | |
| logger.info("Shutdown complete"); | |
| process.exit(0); | |
| } catch (error) { | |
| logger.error("Shutdown failed", { error: error.message }); | |
| process.exit(1); | |
| } | |
| } | |
| process.on("SIGINT", () => shutdown("SIGINT")); | |
| process.on("SIGTERM", () => shutdown("SIGTERM")); | |
| try { | |
| await verifyDbConnection(pool); | |
| runtimeState.markDbHealthy(); | |
| logger.info("PostgreSQL connection established"); | |
| if (config.db.runMigrationsOnBoot) { | |
| const migrationsDir = path.resolve(__dirname, "../migrations"); | |
| await runMigrations(pool, migrationsDir, logger); | |
| } | |
| if (config.db.runSeedsOnBoot) { | |
| const seedsDir = path.resolve(__dirname, "../seeds"); | |
| await runSeeds(pool, seedsDir, logger); | |
| } | |
| const alertEngineService = createAlertEngineService({ | |
| config, | |
| alertsRepository, | |
| alertRulesRepository, | |
| }); | |
| const telemetryIngestService = createTelemetryIngestService({ | |
| pool, | |
| logger, | |
| runtimeState, | |
| telemetryRepository, | |
| assetRepository, | |
| alertEngineService, | |
| telemetryValidator, | |
| }); | |
| const tripSummaryAiService = createTripSummaryAiService({ | |
| config, | |
| logger, | |
| }); | |
| const services = { | |
| authService: createAuthService({ | |
| config, | |
| pool, | |
| authRepository, | |
| }), | |
| fleetService: createFleetService({ | |
| pool, | |
| config, | |
| telemetryRepository, | |
| }), | |
| alertsService: createAlertsService({ | |
| pool, | |
| config, | |
| alertsRepository, | |
| }), | |
| reportsService: createReportsService({ | |
| pool, | |
| config, | |
| reportsRepository, | |
| }), | |
| tripsService: createTripsService({ | |
| pool, | |
| tripsRepository, | |
| assetRepository, | |
| auditRepository, | |
| alertsRepository, | |
| tripSummaryAiService, | |
| }), | |
| adminService: createAdminService({ | |
| pool, | |
| adminRepository, | |
| auditRepository, | |
| }), | |
| }; | |
| mqttConsumer = createMqttConsumer({ | |
| config, | |
| logger, | |
| runtimeState, | |
| onTelemetryMessage: telemetryIngestService.handleIncomingTelemetry, | |
| }); | |
| offlineScannerJob = startOfflineScannerJob({ | |
| pool, | |
| config, | |
| logger, | |
| runtimeState, | |
| telemetryRepository, | |
| alertEngineService, | |
| }); | |
| const app = createApp(config, logger, services, runtimeState); | |
| server = app.listen(config.server.port, () => { | |
| logger.info("Backend started", { | |
| port: config.server.port, | |
| apiPrefix: config.server.apiPrefix, | |
| mqttTopicFilter: config.mqtt.topicFilter, | |
| }); | |
| }); | |
| } catch (error) { | |
| runtimeState.markDbError(error); | |
| logger.error("Backend startup failed", { error: error.message }); | |
| await pool.end(); | |
| process.exit(1); | |
| } | |
| } | |
| main(); | |