import { MongooseModule, currentDate, } from "../helpers"; import { Model } from "mongoose"; import { StatusBeaconType, QueueDepthsType, TCSendHealthType, WriteBackHealthType, SyncHealthType, } from "../types/status-beacon"; export interface StatusBeacon extends StatusBeaconType { } export default async function StatusBeaconModule(mongoose: MongooseModule) { const { Schema } = mongoose; const QueueDepths = new Schema({ incident: { type: Number, default: 0 }, status: { type: Number, default: 0 }, vehicle: { type: Number, default: 0 }, total: { type: Number, default: 0 }, }, { _id: false, id: false }); const TCSendHealth = new Schema({ lastSuccessfulIncidentSend: { type: Date }, lastSuccessfulUnitStatusSend: { type: Date }, sendFailuresDelta: { type: Number, default: 0 }, lastSendError: { type: String, default: "" }, }, { _id: false, id: false }); const WriteBackHealth = new Schema({ attemptsDelta: { type: Number, default: 0 }, failuresDelta: { type: Number, default: 0 }, lastSuccessfulWriteBack: { type: Date }, lastError: { type: String, default: "" }, }, { _id: false, id: false }); const SyncHealth = new Schema({ lastCacheRefresh: { type: Date }, cacheAgeSeconds: { type: Number, default: 0 }, consecutiveEmptyPolls: { type: Number, default: 0 }, lastPollChanges: { type: Number, default: 0 }, incidentCacheGrowthDelta: { type: Number, default: 0 }, }, { _id: false, id: false }); const modelSchema = new Schema({ _id: { type: Schema.Types.ObjectId, auto: true, }, departmentId: { type: String, default: "", required: true, }, // Identity integration: { type: String, default: "", required: true, }, interfaceStartTime: { type: Date, default: currentDate, }, keepAliveIntervalSecs: { type: Number, default: 60, }, // Health State healthState: { type: String, default: "", }, triggerReason: { type: String, default: "", }, consecutiveFailures: { type: Number, default: 0, }, consecutiveSuccesses: { type: Number, default: 0, }, totalFailuresSinceLastHealthy: { type: Number, default: 0, }, outageStartTime: { type: Date, }, // Cycle Metrics pollCycle: { type: Number, default: 0, }, lastPollMs: { type: Number, default: 0, }, activeIncidents: { type: Number, default: 0, }, activeUnits: { type: Number, default: 0, }, // Data Flow Deltas incidentsDelta: { type: Number, default: 0, }, unitStatusDelta: { type: Number, default: 0, }, // Queue Depths queueDepths: { type: QueueDepths, default: () => ({}), }, queueAges: { type: Object, default: () => ({}), }, queueDroppedDelta: { type: Number, default: 0, }, // Auth Token Health tokenAgeSecs: { type: Number, }, tokenExpiresAt: { type: Date, }, // TC Send Health tCSend: { type: TCSendHealth, default: () => ({}), }, // Write-back Health writeBack: { type: WriteBackHealth, default: () => ({}), }, // Sync Health sync: { type: SyncHealth, default: () => ({}), }, // Diagnostics (beacon 1.2+) — free-form while the wire dialect settles channels: { type: Object, default: () => ({}), }, pollers: { type: Object, default: () => ({}), }, auth: { type: Object, default: () => ({}), }, restartPoll: { type: Object, default: () => ({}), }, clockSync: { type: Object, default: () => ({}), }, // Debug & Config debugPushActive: { type: Boolean, default: false, }, lastConfigSave: { type: Date, }, lastConfigSaveFile: { type: String, default: "", }, // Error & Version lastError: { type: String, default: "", }, interfaceVersion: { type: String, default: "", }, cadVersion: { type: String, default: "", }, unifiedVersion: { type: String, default: "", }, beaconVersion: { type: String, default: "", }, }, { autoIndex: false, timestamps: true, }); modelSchema.index({ departmentId: 1, integration: 1 }, { name: "departmentId_1_integration_1", unique: true, }); modelSchema.index({ healthState: 1 }, { name: "healthState_1" }); modelSchema.index({ triggerReason: 1 }, { name: "triggerReason_1" }); modelSchema.index({ "queueDepths.total": 1 }, { name: "queueDepths_total_1" }); modelSchema.index({ "tCSend.sendFailuresDelta": 1 }, { name: "tCSend_sendFailuresDelta_1" }); modelSchema.index({ "writeBack.failuresDelta": 1 }, { name: "writeBack_failuresDelta_1" }); modelSchema.index({ "sync.consecutiveEmptyPolls": 1 }, { name: "sync_consecutiveEmptyPolls_1" }); return mongoose.model("StatusBeacon", modelSchema, "massive_status_beacon", { overwriteModels: true }); } export interface StatusBeaconModel extends Model { }