import { Schema, model, Document, Types } from 'mongoose'; // Enum for action types export enum ActivityAction { // Authentication LOGIN = 'login', LOGOUT = 'logout', SIGNUP = 'signup', PASSWORD_CHANGE = 'password_change', PASSWORD_RESET = 'password_reset', // Profile Management PROFILE_UPDATE = 'profile_update', PROFILE_PHOTO_UPLOAD = 'profile_photo_upload', LOCATION_UPDATE = 'location_update', // Event Management EVENT_CREATE = 'event_create', EVENT_UPDATE = 'event_update', EVENT_DELETE = 'event_delete', EVENT_JOIN = 'event_join', EVENT_LEAVE = 'event_leave', EVENT_CHECKIN = 'event_checkin', EVENT_VIEW = 'event_view', EVENT_SEARCH = 'event_search', // Form Management FORM_CREATE = 'form_create', FORM_UPDATE = 'form_update', FORM_DELETE = 'form_delete', FORM_SUBMIT = 'form_submit', FORM_VIEW = 'form_view', FORM_EXPORT = 'form_export', // Verification Actions TRAINER_VERIFY = 'trainer_verify', TRAINER_REJECT = 'trainer_reject', ORG_VERIFY = 'organization_verify', ORG_REJECT = 'organization_reject', // Document Actions DOCUMENT_UPLOAD = 'document_upload', DOCUMENT_VIEW = 'document_view', // Analytics ANALYTICS_VIEW = 'analytics_view', REPORT_EXPORT = 'report_export', // API Actions API_ERROR = 'api_error', UNAUTHORIZED_ACCESS = 'unauthorized_access' } export enum ActivityCategory { AUTH = 'authentication', PROFILE = 'profile', EVENT = 'event', FORM = 'form', VERIFICATION = 'verification', ANALYTICS = 'analytics', SYSTEM = 'system' } interface IActivityMetadata { // Request details ipAddress?: string; userAgent?: string; device?: string; browser?: string; // Resource references eventId?: Types.ObjectId; formId?: Types.ObjectId; organizationId?: Types.ObjectId; trainerId?: Types.ObjectId; // Action-specific data changes?: Record; // For updates errorMessage?: string; // For errors statusCode?: number; // Geographic data location?: { type: "Point"; coordinates: [number, number]; }; // Additional context duration?: number; // milliseconds method?: string; // HTTP method endpoint?: string; // API endpoint queryParams?: Record; responseSize?: number; // bytes } export interface IUserActivity extends Document { user: Types.ObjectId; action: ActivityAction; category: ActivityCategory; description: string; metadata: IActivityMetadata; timestamp: Date; sessionId?: string; // Track user sessions success: boolean; createdAt: Date; } const UserActivitySchema = new Schema({ user: { type: Schema.Types.ObjectId, ref: 'User', required: true, index: true }, action: { type: String, enum: Object.values(ActivityAction), required: true, index: true }, category: { type: String, enum: Object.values(ActivityCategory), required: true, index: true }, description: { type: String, required: true }, metadata: { ipAddress: String, userAgent: String, device: String, browser: String, eventId: { type: Schema.Types.ObjectId, ref: 'Event' }, formId: { type: Schema.Types.ObjectId, ref: 'Form' }, organizationId: { type: Schema.Types.ObjectId, ref: 'User' }, trainerId: { type: Schema.Types.ObjectId, ref: 'User' }, changes: Schema.Types.Mixed, errorMessage: String, statusCode: Number, location: { type: { type: String, enum: ['Point'] }, coordinates: [Number] }, duration: Number, method: String, endpoint: String, queryParams: Schema.Types.Mixed, responseSize: Number }, timestamp: { type: Date, default: Date.now, index: true }, sessionId: { type: String, index: true }, success: { type: Boolean, default: true, index: true } }, { timestamps: { createdAt: true, updatedAt: false } }); // Compound indexes for common queries UserActivitySchema.index({ user: 1, timestamp: -1 }); UserActivitySchema.index({ user: 1, category: 1, timestamp: -1 }); UserActivitySchema.index({ user: 1, action: 1, timestamp: -1 }); UserActivitySchema.index({ sessionId: 1, timestamp: -1 }); UserActivitySchema.index({ 'metadata.eventId': 1 }); UserActivitySchema.index({ 'metadata.formId': 1 }); // TTL index - automatically delete logs older than 2 years UserActivitySchema.index({ timestamp: 1 }, { expireAfterSeconds: 63072000 }); export default model('UserActivity', UserActivitySchema);