feat(activity-log): integrate logging across all endpoints (Phase 3)

Added comprehensive activity logging to 14 integration points:

Auth Controller (4 actions):
- AUTH_REGISTER: User registration
- AUTH_LOGIN: User login
- AUTH_VERIFY_EMAIL: Email verification (token & code)
- AUTH_PASSWORD_RESET: Password reset

Events Routes (2 actions):
- EVENT_CHECKIN: User checks into event
- EVENT_LEAVE: User leaves event

Socket Handlers (3 actions):
- EVENT_JOIN_CHAT: User joins event chat room
- EVENT_LEAVE_CHAT: User leaves event chat room
- CHAT_JOIN_ROOM: User joins private match chat

Matches Routes (3 actions):
- MATCH_CREATE: Match request created
- MATCH_ACCEPT: Match request accepted
- MATCH_REJECT: Match request rejected/cancelled

Admin Routes (1 action + security):
- ADMIN_MATCHING_RUN: Admin runs matching algorithm
- Added requireAdmin middleware to all admin routes

All logs include:
- User ID and username (denormalized)
- IP address (X-Forwarded-For aware)
- Action type and resource ID
- HTTP method and path (or SOCKET for WebSocket)
- Contextual metadata (event slugs, match IDs, etc.)

Fire-and-forget pattern ensures logging never blocks requests.
This commit is contained in:
Radosław Gierwiało
2025-12-02 20:07:10 +01:00
parent 0466ef9e5c
commit d83e4163e5
5 changed files with 217 additions and 3 deletions

View File

@@ -1,6 +1,7 @@
const { Server } = require('socket.io');
const { verifyToken } = require('../utils/auth');
const { prisma } = require('../utils/db');
const { ACTIONS, log: activityLog } = require('../services/activityLog');
// Track active users in each event room
const activeUsers = new Map(); // eventId -> Set of { socketId, userId, username, avatar }
@@ -202,6 +203,20 @@ function initializeSocket(httpServer) {
username: socket.user.username,
avatar: socket.user.avatar,
});
// Log join event chat activity
activityLog({
userId: socket.user.id,
username: socket.user.username,
ipAddress: socket.handshake.address,
action: ACTIONS.EVENT_JOIN_CHAT,
resource: `event:${eventId}`,
method: 'SOCKET',
path: 'join_event_room',
metadata: {
eventSlug: slug,
},
});
} catch (error) {
console.error('Join event room error:', error);
socket.emit('error', { message: 'Failed to join room' });
@@ -236,6 +251,20 @@ function initializeSocket(httpServer) {
console.log(`👤 ${socket.user.username} left event room ${socket.currentEventSlug}`);
// Log leave event chat activity
activityLog({
userId: socket.user.id,
username: socket.user.username,
ipAddress: socket.handshake.address,
action: ACTIONS.EVENT_LEAVE_CHAT,
resource: `event:${eventId}`,
method: 'SOCKET',
path: 'leave_event_room',
metadata: {
eventSlug: socket.currentEventSlug,
},
});
// Clear current event data
socket.currentEventId = null;
socket.currentEventRoom = null;
@@ -349,6 +378,20 @@ function initializeSocket(httpServer) {
where: { id: parseInt(matchId) },
data: updateData,
});
// Log join match room activity
activityLog({
userId: socket.user.id,
username: socket.user.username,
ipAddress: socket.handshake.address,
action: ACTIONS.CHAT_JOIN_ROOM,
resource: `match:${matchId}`,
method: 'SOCKET',
path: 'join_match_room',
metadata: {
matchId: parseInt(matchId),
},
});
}
} catch (error) {
console.error('Join match room error:', error);