const mongoose = require('mongoose'); const messageSchema = new mongoose.Schema( { role: { type: String, enum: ['user', 'assistant'], required: true }, text: { type: String, required: true }, ts: { type: Date, default: Date.now }, modelId: { type: String, default: null }, inputTokens: { type: Number, default: 0 }, outputTokens: { type: Number, default: 0 }, /** Client-facing id for assistant replies (feedback). */ msgId: { type: String, default: null }, /** Thumb feedback: true = satisfied, false = not satisfied. */ satisfied: { type: Boolean, default: null }, feedbackAt: { type: Date, default: null }, }, { _id: false }, ); const webChatSessionSchema = new mongoose.Schema( { botId: { type: mongoose.Schema.Types.ObjectId, ref: 'ConciergeBot', required: true, index: true }, eventId: { type: mongoose.Schema.Types.ObjectId, ref: 'Event' }, organization: { type: mongoose.Schema.Types.ObjectId, ref: 'Organization' }, sessionId: { type: String, required: true, trim: true, index: true }, history: { type: [messageSchema], default: [] }, lastIntent: { type: String, default: null }, lastSeenAt: { type: Date, default: Date.now }, endedAt: { type: Date, default: null }, inputTokensTotal: { type: Number, default: 0 }, outputTokensTotal: { type: Number, default: 0 }, // Identity / OTP participant: { type: mongoose.Schema.Types.ObjectId, ref: 'Participant', default: null, index: true, }, identityVerifiedAt: { type: Date, default: null }, identityMethod: { type: String, default: null }, authState: { type: String, enum: ['awaiting_email', 'awaiting_otp'], default: undefined, }, authEmail: { type: String, trim: true, lowercase: true, default: null }, otpHash: { type: String, default: null }, otpExpiresAt: { type: Date, default: null }, pendingIntent: { type: String, default: null }, pendingMessage: { type: String, default: null }, pendingEntities: { type: mongoose.Schema.Types.Mixed, default: null }, /** Last session ids shown as cards — used to resolve "add it" / "yes". */ lastSessionIds: { type: [String], default: [] }, /** Rate-limit ticket QR emails from this chat session. */ lastTicketEmailAt: { type: Date, default: null }, /** Rate-limit organizer escalation emails from this chat session. */ lastEscalationEmailAt: { type: Date, default: null }, }, { timestamps: true, collection: 'webchatsessions' }, ); webChatSessionSchema.index({ botId: 1, sessionId: 1 }, { unique: true }); module.exports = mongoose.models.WebChatSession || mongoose.model('WebChatSession', webChatSessionSchema);