Commit Graph

16 Commits

Author SHA1 Message Date
Radosław Gierwiało
4a91a10aff feat(chat): add 2000 character limit for messages
Added message length validation to prevent spam and improve UX with
character counter feedback.

Backend:
- Added MESSAGE_MAX_LENGTH constant (2000 characters)
- Validation in send_event_message handler:
  - Check if content is string
  - Check if not empty after trim
  - Check if not exceeding max length
- Validation in send_match_message handler (same checks)
- Returns error message if validation fails

Frontend:
- Added MESSAGE_MAX_LENGTH constant (2000 characters)
- ChatInput component enhancements:
  - maxLength attribute on input (hard limit)
  - Character counter shows when >80% of limit
  - Counter turns red when at limit
  - Submit button disabled when at limit
  - Counter format: "X/2000"

UX:
- User sees counter at 1600+ characters (80% of limit)
- Hard limit prevents typing beyond 2000 chars
- Clear visual feedback (red text) when at limit
- Consistent validation on both event and match chats

Security:
- Prevents spam with extremely long messages
- Protects against potential DoS via message size
- Database already uses TEXT type (supports limit)
2025-12-02 23:46:54 +01:00
Radosław Gierwiało
dd3176196e fix(chat): real-time active users list updates
Fixed issue where active users list in event chat did not update in
real-time when new users joined. Users had to refresh the page to see
newly joined participants.

Root Cause:
- getAllDisplayUsers() used checkedInUsers (loaded once from API) as
  base list, with activeUsers (Socket.IO real-time) only for isOnline flag
- When new user joined chat, they appeared in activeUsers but not in
  checkedInUsers, so they were not displayed

Solution:
- Rewrote getAllDisplayUsers() to prioritize activeUsers (real-time data)
- Merges activeUsers (online) with checkedInUsers (offline checked-in users)
- Uses Socket.IO data as source of truth for online users
- Enriches with database data when available (firstName, lastName, etc)
- Sorts online users first, offline second

Changes:
- EventChatPage.jsx: Rewrote getAllDisplayUsers() to merge activeUsers
  with checkedInUsers, prioritizing real-time Socket.IO data
- useEventChat.js: Added debug logging for active_users events
- socket/index.js: Added debug logging for active_users emissions

Testing:
- User A in chat sees User B appear immediately when B joins
- No page refresh required
- Online/offline status updates in real-time
2025-12-02 23:38:46 +01:00
Radosław Gierwiało
d641e3f059 feat(activity-log): add Socket.IO real-time streaming (Phase 5)
Added socket handlers for admin activity log streaming:

Socket Events:
- join_admin_activity_logs: Admin joins streaming room
  - Verifies isAdmin flag from database
  - Rejects non-admin users with warning log
  - Emits confirmation: admin_activity_logs_joined

- leave_admin_activity_logs: Admin leaves streaming room
  - Clean disconnect from room

Real-time Flow:
1. Admin connects and emits join_admin_activity_logs
2. Server verifies admin status (fresh DB check)
3. Admin joins 'admin_activity_logs' Socket.IO room
4. activityLog.log() emits activity_log_entry to room
5. Admin receives real-time log entries as they happen

The activityLog service (Phase 2) already emits events,
so streaming is fully functional with these handlers.
2025-12-02 20:10:47 +01:00
Radosław Gierwiało
d83e4163e5 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.
2025-12-02 20:07:10 +01:00
Radosław Gierwiało
4e9557bd29 feat(chat): add country flags and competitor numbers with normalized data architecture
Implemented display of country flags and competitor numbers in event chat messages:
- Country flags displayed as emoji (🇸🇪, 🇵🇱, etc.) with proper emoji font support
- Competitor numbers shown in #123 format next to usernames
- Normalized data architecture with user and participant caches on frontend
- User data (username, avatar, country) and participant data (competitorNumber) cached separately
- Messages store only core data (id, content, userId, createdAt)
- Prevents data inconsistency when users update profile information
- Fixed duplicate message keys React warning with deduplication logic
- Backend sends nested user/participant objects for cache population
- Auto-updates across all messages when user changes avatar or country

Backend changes:
- Socket.IO event_message and message_history include nested user/participant data
- API /events/:slug/messages endpoint restructured with same nested format
- Batch lookup of competitor numbers for efficiency

Frontend changes:
- useEventChat hook maintains userCache and participantCache
- ChatMessage component accepts separate user/participant props
- ChatMessageList performs cache lookups during render
- Emoji font family support for cross-platform flag rendering
2025-11-29 19:49:06 +01:00
Radosław Gierwiało
8a369c1fc4 fix(socket): improve connection stability with heartbeat and auto-reconnect
- Backend: Add pingInterval (25s) and pingTimeout (60s) for better keep-alive
- Frontend: Increase reconnection attempts to Infinity (keep trying forever)
- Frontend: Add reconnect event handlers to rejoin rooms after reconnection
- Frontend: Check initial connection state when reusing socket instance
2025-11-21 21:53:51 +01:00
Radosław Gierwiało
78280ca8d8 feat(dashboard): add unread count for match chats
Track unread messages in match chats and display count badge:
- Schema: Add user1LastReadAt/user2LastReadAt to Match model
- Backend: Calculate unreadCount in dashboard API
- Socket: Update lastReadAt when user joins match room
- Frontend: Display red badge with unread count on match avatar
2025-11-21 21:46:00 +01:00
Radosław Gierwiało
2c0620db6a feat(dashboard): add online count for events
Show real-time count of users currently in each event chat room.
- Backend: Export getEventsOnlineCounts from socket module
- Dashboard API: Include onlineCount for each active event
- Frontend: Display online count with animated green dot indicator
2025-11-21 21:41:16 +01:00
Radosław Gierwiało
664a2865b9 feat: implement WebRTC P2P file transfer with DataChannel
Add complete WebRTC peer-to-peer file transfer functionality:

Backend changes:
- Add WebRTC signaling events to Socket.IO (offer, answer, ICE candidates)
- Implement authorization checks for match participants
- Add signaling relay between matched users

Frontend changes:
- Create useWebRTC hook for RTCPeerConnection management
- Implement RTCDataChannel with 16KB chunking for large files
- Add real-time progress monitoring for sender and receiver
- Implement automatic file download on receiver side
- Add connection state tracking and error handling
- Integrate WebRTC with MatchChatPage (replace mockup)

Configuration:
- Add Vite allowed hosts configuration via VITE_ALLOWED_HOSTS env var
- Support comma-separated host list or 'all' for development
- Add .env.example with configuration examples
- Update docker-compose.yml with default allowed hosts

Documentation:
- Add comprehensive WebRTC testing guide with troubleshooting
- Add quick test checklist for manual testing
- Document WebRTC flow, requirements, and success criteria

Features:
- End-to-end encrypted P2P transfer (DTLS)
- 16KB chunk size optimized for DataChannel
- Buffer management to prevent overflow
- Automatic connection establishment with 30s timeout
- Support for files of any size
- Real-time progress tracking
- Clean connection lifecycle management
2025-11-15 14:12:51 +01:00
Radosław Gierwiało
4a3e32f3b6 feat: implement Phase 2 - Matches API with real-time notifications
Backend changes:
- Add matches API routes (POST, GET, PUT, DELETE)
- Create/accept/reject match requests
- Auto-create private chat rooms on match acceptance
- Socket.IO notifications for match events (received, accepted, cancelled)
- Users join personal rooms (user_{id}) for notifications

Frontend changes:
- Add MatchesPage component with inbox UI
- Matches navigation link with notification badge
- Real-time match request count updates
- Accept/reject match functionality
- Filter matches by status (all/pending/accepted)
- Integrate match requests in EventChatPage (UserPlus button)

Features:
- Send match requests to event participants
- Accept incoming match requests
- Real-time notifications via Socket.IO
- Automatic private chat room creation
- Match status tracking (pending/accepted/completed)
- Authorization checks (only participants can match)
- Duplicate match prevention
2025-11-14 19:22:23 +01:00
Radosław Gierwiało
c4240f05bb feat: add Socket.IO heats_updated broadcast event
- Export getIO function from socket module
- Broadcast heats_updated event when user updates their heats
- Event includes userId, username, and updated heats array
- Non-blocking broadcast (won't fail request if socket fails)
2025-11-14 15:35:39 +01:00
Radosław Gierwiało
a6e4981f17 fix: prevent bypassing event check-in via page refresh
Users could gain unauthorized access to event chats by refreshing the page after leaving an event. The socket handler was automatically creating participation records when users joined rooms, completely bypassing the QR code check-in requirement. This fix verifies that users have legitimately checked in before allowing socket room access.
2025-11-14 14:36:49 +01:00
Radosław Gierwiało
b2c2527c46 feat: add event slugs to prevent ID enumeration attacks
Replace sequential event IDs in URLs with unique alphanumeric slugs to prevent enumeration attacks. Event URLs now use format /events/{slug}/chat instead of /events/{id}/chat.

Backend changes:
- Add slug field (VARCHAR 50, unique) to Event model
- Create migration with auto-generated 12-char MD5-based slugs for existing events
- Update GET /api/events/:slug endpoint (changed from :id)
- Update GET /api/events/:slug/messages endpoint (changed from :eventId)
- Modify Socket.IO join_event_room to accept slug parameter
- Update send_event_message to use stored event context instead of passing eventId

Frontend changes:
- Update eventsAPI.getBySlug() method (changed from getById)
- Update eventsAPI.getMessages() to use slug parameter
- Change route from /events/:eventId/chat to /events/:slug/chat
- Update EventsPage to navigate using event.slug
- Update EventChatPage to fetch event data via slug and use slug in socket events

Security impact: Prevents attackers from discovering all events by iterating sequential IDs.
2025-11-13 21:43:58 +01:00
Radosław Gierwiało
20f405cab3 feat: track event participation and show joined events first
Backend:
- Add EventParticipant model to track user-event participation
- Create database migration for event_participants table
- Record participation when user joins event chat via Socket.IO
- Update GET /api/events to include isJoined flag for current user
- Sort events: joined events first, then by start date
- Add authenticate middleware to GET /api/events

Frontend:
- Replace mock events with real API data from backend
- Add loading and error states to EventsPage
- Display "Joined" badge on events user has joined
- Highlight joined events with colored border
- Show "Open chat" vs "Join chat" button text
- Auto-refresh events list when navigating back

When users join an event chat, this is now recorded in the database.
Joined events appear at the top of the list with visual indicators.
2025-11-13 21:18:15 +01:00
Radosław Gierwiało
9d8fc9f6d6 feat: add chat message history and infinite scroll
Backend changes:
- Socket.IO: Send last 20 messages on join_event_room
- REST API: Add GET /api/events/:eventId/messages endpoint with pagination
- Support for 'before' cursor-based pagination for loading older messages

Frontend changes:
- Load initial 20 messages when joining event chat
- Implement infinite scroll to load older messages on scroll to top
- Add loading indicator for older messages
- Preserve scroll position when loading older messages
- Add eventsAPI.getMessages() function for pagination

User experience:
- New users see last 20 messages immediately
- Scrolling up automatically loads older messages in batches of 20
- Smooth scrolling experience with position restoration

Note: Messages are encrypted in transit via HTTPS/WSS but stored
as plain text in database (no E2E encryption).
2025-11-13 20:16:58 +01:00
Radosław Gierwiało
75cb4b16e7 feat: implement real-time chat with Socket.IO
Implemented WebSocket-based real-time messaging for both event rooms and private match chats using Socket.IO with comprehensive test coverage.

Backend changes:
- Installed socket.io@4.8.1 for WebSocket server
- Created Socket.IO server with JWT authentication middleware
- Implemented event room management (join/leave/messages)
- Added active users tracking with real-time updates
- Implemented private match room messaging
- Integrated Socket.IO with Express HTTP server
- Messages are persisted to PostgreSQL via Prisma
- Added 12 comprehensive unit tests (89.13% coverage)

Frontend changes:
- Installed socket.io-client for WebSocket connections
- Created socket service layer for connection management
- Updated EventChatPage with real-time messaging
- Updated MatchChatPage with real-time private chat
- Added connection status indicators (● Connected/Disconnected)
- Disabled message input when not connected

Infrastructure:
- Updated nginx config to proxy WebSocket connections at /socket.io
- Added Upgrade and Connection headers for WebSocket support
- Set long timeouts (7d) for persistent WebSocket connections

Key features:
- JWT-authenticated socket connections
- Room-based architecture for events and matches
- Real-time message broadcasting
- Active users list with automatic updates
- Automatic cleanup on disconnect
- Message persistence in database

Test coverage:
- 12 tests passing (authentication, event rooms, match rooms, disconnect, errors)
- Socket.IO module: 89.13% statements, 81.81% branches, 91.66% functions
- Overall coverage: 81.19%

Phase 1, Step 4 completed. Ready for Phase 2 (Core Features).
2025-11-12 22:42:15 +01:00