| import { Schema, model, Document, Types } from 'mongoose'; | |
| interface IFieldResponse { | |
| fieldId: string; // References field ID in Form | |
| value: any; // Can be string, number, array, etc. | |
| fileUrl?: string; // If file upload | |
| } | |
| export interface IFormResponse extends Document { | |
| form: Types.ObjectId; | |
| event?: Types.ObjectId; // If form is attached to event | |
| respondent: Types.ObjectId; // User who submitted | |
| // Response Data | |
| responses: IFieldResponse[]; | |
| // Metadata | |
| submittedAt: Date; | |
| lastEditedAt?: Date; | |
| ipAddress?: string; | |
| userAgent?: string; | |
| // Status | |
| isComplete: boolean; | |
| createdAt: Date; | |
| updatedAt: Date; | |
| } | |
| const FormResponseSchema = new Schema<IFormResponse>({ | |
| form: { | |
| type: Schema.Types.ObjectId, | |
| ref: 'Form', | |
| required: true, | |
| index: true | |
| }, | |
| event: { | |
| type: Schema.Types.ObjectId, | |
| ref: 'Event', | |
| index: true | |
| }, | |
| respondent: { | |
| type: Schema.Types.ObjectId, | |
| ref: 'User', | |
| required: true, | |
| index: true | |
| }, | |
| responses: [{ | |
| fieldId: { | |
| type: String, | |
| required: true | |
| }, | |
| value: { | |
| type: Schema.Types.Mixed, | |
| required: true | |
| }, | |
| fileUrl: String | |
| }], | |
| submittedAt: { | |
| type: Date, | |
| default: Date.now, | |
| index: true | |
| }, | |
| lastEditedAt: Date, | |
| ipAddress: String, | |
| userAgent: String, | |
| isComplete: { | |
| type: Boolean, | |
| default: true | |
| } | |
| }, { | |
| timestamps: true | |
| }); | |
| // Compound index: one response per user per form (if oneResponsePerUser is true) | |
| FormResponseSchema.index({ form: 1, respondent: 1 }, { unique: true }); | |
| // Index for querying responses by event | |
| FormResponseSchema.index({ event: 1, submittedAt: -1 }); | |
| export default model<IFormResponse>('FormResponse', FormResponseSchema); |