From f9cdf2aa98b7aaf6bc636dca0001cdc0d8a90462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Gierwia=C5=82o?= Date: Tue, 2 Dec 2025 19:42:24 +0100 Subject: [PATCH] feat(admin): add ActivityLog schema and isAdmin flag Database changes: - Add ActivityLog model for comprehensive activity tracking - Track all user actions (auth, events, matches, admin) - Denormalized username for query performance - JSON metadata for flexibility - Multiple indexes for common filter patterns - Add isAdmin flag to User model for admin access control - Add activityLogs relation to User Schema pushed to database with prisma db push Created initial admin user: spotlight@radziel.com This is Phase 1 of Activity Log System implementation. Next phases: backend service, middleware, API endpoints, frontend UI. --- backend/prisma/schema.prisma | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index 5df5ac4..3f2502b 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -61,6 +61,9 @@ model User { recordingsDone Int @default(0) @map("recordings_done") // How many times this user recorded others recordingsReceived Int @default(0) @map("recordings_received") // How many times others recorded this user + // Admin flag + isAdmin Boolean @default(false) @map("is_admin") + createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@ -73,6 +76,7 @@ model User { eventParticipants EventParticipant[] heats EventUserHeat[] recordingAssignments RecordingSuggestion[] @relation("RecorderAssignments") + activityLogs ActivityLog[] @@map("users") } @@ -322,3 +326,42 @@ model MatchingRun { @@index([eventId, startedAt]) @@map("matching_runs") } + +// Activity logs for admin monitoring +model ActivityLog { + id Int @id @default(autoincrement()) + + // Core identification + userId Int? @map("user_id") // NULL for system actions + username String? @db.VarChar(50) // Denormalized for performance + ipAddress String? @map("ip_address") @db.VarChar(45) // IPv4 or IPv6 + + // Action details + action String @db.VarChar(50) // 'auth.register', 'match.create', etc. + category String @db.VarChar(20) // 'auth', 'event', 'match', 'admin', 'chat' + resource String? @db.VarChar(100) // Resource ID (e.g., 'event:123', 'match:abc') + + // Contextual data + method String? @db.VarChar(10) // HTTP method: GET, POST, PUT, DELETE + path String? @db.VarChar(255) // API path + metadata Json? // Flexible JSON for action-specific data + + // Result tracking + success Boolean @default(true) // Track failures too + errorMessage String? @map("error_message") @db.Text + + // Timestamp + createdAt DateTime @default(now()) @map("created_at") + + // Relations + user User? @relation(fields: [userId], references: [id], onDelete: SetNull) + + // Indexes for performance + @@index([userId, createdAt]) + @@index([action, createdAt]) + @@index([category, createdAt]) + @@index([createdAt(sort: Desc)]) // Most common query pattern + @@index([username, createdAt]) // Search by username + + @@map("activity_logs") +}