Commit Graph

112 Commits

Author SHA1 Message Date
Radosław Gierwiało
671b16cb82 feat(backend): add test bot for automated event chat testing
Add test-bot.js script that simulates a user participating in event chat for testing purposes.

Features:
- Authenticates as user via API
- Checks in to event using QR code token
- Connects to Socket.IO and joins event room
- Sends random messages at configurable intervals
- Auto-accepts recording suggestions

Usage from container:
docker compose exec backend sh -c 'API_URL=http://localhost:3000 node scripts/test-bot.js --email user@example.com --password pass --slug event-slug --interval 10'
2025-11-29 19:00:43 +01:00
Radosław Gierwiało
b79173937b chore: add .repl_history and .claude/ to gitignore 2025-11-29 15:05:38 +01:00
Radosław Gierwiało
9206565523 security: add nginx headers and fix npm vulnerabilities
- Add security headers to nginx (X-Frame-Options, CSP, etc.)
- Reduce client_max_body_size from 500M to 10M
- Add npm overrides to fix cookie vulnerability in csurf
- Make navbar sticky with full width
2025-11-29 15:04:26 +01:00
Radosław Gierwiało
6f7465ee5a fix(tests): add wsdcId cleanup to prevent unique constraint violations
Both users.test.js and auth-phase1.5.test.js were failing due to
unique constraint violations on wsdc_id field when running after
other test suites. Added wsdcId to cleanup queries and proper
deletion of related data (messages, matches, eventParticipants).
2025-11-23 22:59:06 +01:00
Radosław Gierwiało
0ca79b6c7d refactor(backend): add status constants and update code to use them
- Create constants/statuses.js with MATCH_STATUS, SUGGESTION_STATUS
- Update routes/dashboard.js to use MATCH_STATUS
- Update routes/matches.js to use MATCH_STATUS
- Update routes/events.js to use SUGGESTION_STATUS
- Update services/matching.js to use SUGGESTION_STATUS
- Update tests to use constants
2025-11-23 22:40:54 +01:00
Radosław Gierwiało
4467c570b0 feat(matching): add schedule config for division collision groups
Allow event organizers to configure which divisions run in parallel
(same time slot) for accurate collision detection in the auto-matching
algorithm. Divisions in the same slot will collide with each other.

- Add scheduleConfig JSON field to Event model
- Add PUT /events/:slug/schedule-config API endpoint
- Update matching algorithm to use slot-based collision detection
- Add UI in EventDetailsPage for managing division slots
- Add unit tests for schedule-based collision detection
2025-11-23 19:05:25 +01:00
Radosław Gierwiało
a5a1296a4e feat(frontend): add recording matching UI
Add frontend components for auto-matching recording partners:

- RecordingTab component with suggestions list and opt-out toggle
- Tab navigation in EventChatPage (Chat, Uczestnicy, Nagrywanie)
- Matching configuration in EventDetailsPage (deadline, run matching)
- matchingAPI functions in api.js
- Return registrationDeadline and matchingRunAt in GET /events/:slug/details

UI allows users to:
- View who will record their heats
- View heats they need to record
- Accept/reject suggestions
- Opt-out from being a recorder
- Set registration deadline (admin)
- Manually trigger matching (admin)
2025-11-23 18:50:35 +01:00
Radosław Gierwiało
c18416ad6f feat(matching): add auto-matching system for recording partners
Implement algorithm to match dancers with recorders based on:
- Heat collision avoidance (division + competitionType + heatNumber)
- Buffer time (1 heat after dancing before can record)
- Location preference (same city > same country > anyone)
- Max 3 recordings per person
- Opt-out support (falls to bottom of queue)

New API endpoints:
- PUT /events/:slug/registration-deadline
- PUT /events/:slug/recorder-opt-out
- POST /events/:slug/run-matching
- GET /events/:slug/match-suggestions
- PUT /events/:slug/match-suggestions/:id/status

Database changes:
- Event: registrationDeadline, matchingRunAt
- EventParticipant: recorderOptOut
- RecordingSuggestion: new model for match suggestions
2025-11-23 18:32:14 +01:00
Radosław Gierwiało
edf68f2489 feat(events): add competitor number (bib) support
Allow participants to set their bib/competitor number per event.
Display as badge next to username in participant lists.

- Add competitorNumber field to EventParticipant model
- Add PUT /events/:slug/competitor-number endpoint
- Include competitorNumber in heats/me and heats/all responses
- Add input field in HeatsBanner component
- Display badge in UserListItem component
- Add unit tests for competitor number feature
2025-11-23 17:55:25 +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
901b046a34 feat(backend): implement dashboard API endpoint
- Add GET /api/dashboard endpoint for authenticated users
- Returns active events with user heats
- Returns accepted matches with partner info
- Detects video exchange status from message parsing
- Tracks rating completion status (rated by me/partner)
- Returns incoming/outgoing pending match requests
- Add comprehensive test suite (12 tests, 93% coverage)
- Add DASHBOARD_PLAN.md with full design documentation
2025-11-21 21:00:50 +01:00
Radosław Gierwiało
198c216b44 fix(backend): auto-create event ChatRoom on first check-in
Problem:
- User got "Chat room not found" error when trying to send messages
- Event ChatRooms were only created by seed script, not for manually
  created events
- Event "Another Dance Event" (ID: 420) was missing its ChatRoom

Root Cause:
- Seed script (seed.js:179-188) correctly creates ChatRooms for events
- But events created outside of seed (CLI, manual DB insert) didn't
  create ChatRooms
- Socket handler requires ChatRoom to exist before accepting messages

Solution:
1. Added defensive check in check-in handler (POST /api/events/checkin/:token)
2. Automatically creates ChatRoom if missing when first user checks in
3. Logs creation for debugging: "Created missing chat room for event: {slug}"

Impact:
- Existing events without ChatRooms will get them on next check-in
- Future manually-created events will work correctly
- No breaking changes - all 223 tests pass

Changes:
- backend/src/routes/events.js: Added ChatRoom existence check and
  auto-creation logic (lines 256-272)

Note: Manually created ChatRoom for event ID 420 to fix immediate issue
2025-11-21 17:34:17 +01:00
Radosław Gierwiało
688f71343d test: fix test isolation by using unique test data per suite
- Add unique prefixes to test usernames (users_, matches_, events_)
- Add unique prefixes to test emails to prevent conflicts
- Add unique prefixes to event slugs and worldsdc_id values
- This prevents race conditions when Jest runs tests in parallel

Results:
- All 223 tests now passing (was 145/223)
- 14/14 test suites passing (was 11/14)
- Code coverage improved to 71.31% (from ~45%)

Fixes:
- users.test.js: Changed john_dancer → users_john_dancer
- matches.test.js: Changed to matches_ prefix
- events.test.js: Changed to events_ prefix + unique worldsdc_id
2025-11-20 22:12:09 +01:00
Radosław Gierwiało
fd0dcdf77f test: improve test cleanup with selective deletion
- Replace deleteMany({}) with selective deletion by username/email/slug in:
  - events.test.js (target specific test users/events only)
  - matches.test.js (target specific test users/events only)
  - csrf.test.js (target csrftest user only)
- Replace delete() with deleteMany() for resilient cleanup:
  - matches.test.js (2 inline cleanups)
  - socket-webrtc.test.js (1 inline cleanup)
- Update TODO.md with test status and future UX/UI improvements

Test improvement: 189/223 passing (84.8%), up from 145/223 (65%)
2025-11-20 00:05:24 +01:00
Radosław Gierwiało
d6f3eafeb2 fix(tests): improve socket.test.js cleanup to avoid test interaction issues
- Replace delete() with deleteMany() in all afterAll hooks (more resilient)
- Add checks for testUser existence before creating EventParticipant
- Add .catch() handlers to ignore duplicate or foreign key errors
- Add conditional checks with ?. before cleanup operations

Changes improve test isolation and prevent foreign key constraint
violations when tests run together. All socket tests now pass
individually (12/12 socket.test.js, 7/7 socket-webrtc.test.js).
2025-11-19 22:22:49 +01:00
Radosław Gierwiało
93c0943bfa fix(tests): fix backend test failures and improve test isolation
- Fixed CORS test in app.test.js to use allowed origin
- Updated auth-phase1.5.test.js to match actual error messages
- Fixed socket.test.js to use slug parameter instead of eventId
- Added EventParticipant records for socket event room tests
- Updated security config to allow both frontend origins in dev

All socket tests now passing (12/12). Test changes ensure proper
cleanup and prevent database conflicts by using selective deletion
instead of wiping entire tables.
2025-11-19 22:10:36 +01:00
Radosław Gierwiało
85a47f4e8e test: fix backend test cleanup to preserve production data
Replace deleteMany({}) with selective cleanup targeting only test data:

- events.test.js: Delete only test users (john_dancer, sarah_swings, mike_blues)
  and test events (test-dance-festival-2025) before creating new ones
- matches.test.js: Clean up john_dancer, sarah_swings, mike_moves and
  test-dance-festival slug specifically
- users.test.js: Remove only john_dancer and sarah_swings test users
  in both beforeAll and afterAll hooks
- auth.test.js: Target specific test usernames/emails (testuser, newuser,
  lockouttest, etc.) instead of all users
- auth-phase1.5.test.js: Clean up 12 specific test users by username/email
- socket.test.js: Add beforeAll cleanup for sockettest user to prevent
  conflicts from previous test runs
- socket-webrtc.test.js: Clean up webrtc_user1 and webrtc_user2 before
  creating them

Fix CORS configuration for tests:
- security.js: Add http://localhost:3000 to allowed origins in development
  mode to fix app.test.js CORS test (was failing with 500 error)

Results: Improved from 125/223 passing to 137/223 passing (12 more tests fixed)
All test data cleanup now uses WHERE clauses with specific usernames/emails/slugs
instead of wiping entire tables with deleteMany({})
2025-11-19 21:46:04 +01:00
Radosław Gierwiało
bfbfd0e729 test: fix auth test expectations and add test commands to Makefile
- Update auth.test.js to match current API error messages
  - Registration success message includes email verification notice
  - Duplicate credentials use generic message to prevent user enumeration

- Add test commands to Makefile
  - make test: run all backend tests
  - make test-watch: run tests in watch mode
  - make test-coverage: run tests with coverage report

All auth tests now pass (19/19 ✓)
2025-11-19 20:23:25 +01:00
Radosław Gierwiało
44df50362a feat(security): implement comprehensive security hardening
- Add CSRF protection with cookie-based tokens
  - Add cookie-parser and csurf middleware
  - Create GET /api/csrf-token endpoint
  - Frontend automatically includes CSRF token in POST/PUT/DELETE requests
  - Add retry logic for expired CSRF tokens

- Implement account lockout mechanism
  - Add database fields: failedLoginAttempts, lockedUntil
  - Track failed login attempts and lock accounts after max attempts (configurable)
  - Auto-unlock after lockout duration expires
  - Return helpful error messages with remaining time

- Add comprehensive security environment variables
  - Rate limiting configuration (API, auth, email endpoints)
  - CSRF protection toggle
  - Password policy requirements
  - Account lockout settings
  - Logging levels

- Add comprehensive test coverage
  - 6 new tests for account lockout functionality
  - 11 new tests for CSRF protection
  - All tests handle enabled/disabled states gracefully

- Update documentation
  - Add Phase 3 security hardening to SESSION_CONTEXT.md
  - Document new database fields and migration
  - Update progress to 85%

Files changed:
- Backend: app.js, auth controller, security config, new migration
- Frontend: api.js with CSRF token handling
- Tests: auth.test.js (extended), csrf.test.js (new)
- Config: .env examples with security variables
- Docs: SESSION_CONTEXT.md updated
2025-11-19 20:16:05 +01:00
Radosław Gierwiało
6a17143ce1 feat(events): add client-side pagination and animations on /events\n\n- Show 5 nearest events (>= today-3d) by default\n- Add Load previous/Load later with smooth fade-slide-in for new items\n- Prevent animating existing items; preserve scroll on prepend\n- Show check-in prompt only for initial 5 events\n- Add keyframes utility in index.css 2025-11-15 22:44:21 +01:00
Radosław Gierwiało
b9d6f42ff5 feat(import): add WSDC list parser with location + update-missing-location option\n\n- Parse Event List for name/date/location/country/sourceUrl\n- Support --source list|calendar|auto and --update-missing-location\n- Keep calendar import for title/start/end/url fallback\n- Update CLI summary and docs (ADMIN_CLI.md, README.md) 2025-11-15 21:56:05 +01:00
Radosław Gierwiało
457de6c1c4 fix(cli): keep REPL alive on errors and consolidate help\n\n- Replace process.exit(1) with thrown errors in handlers\n- REPL catches and prints CLI errors without exiting\n- Consolidated help to include all commands and examples\n- Add events:import:wsdc command mapping and alias 2025-11-15 21:41:01 +01:00
Radosław Gierwiało
78f96e2849 feat(cli): add admin REPL + commands and docs
- Add CLI entry in backend with default REPL, persistent history, aliases
- Add commands: users:list/create/verify, events:list/details/participants/checkin,
  matches:list, logs:app, logs:messages
- Support running subcommands inside REPL via .cli and run()
- Add Makefile targets: dev-cli, prod-cli, dev/prod up/down (+rebuild)
- Update README and add docs/ADMIN_CLI.md
- Add CLI tests with mocked Prisma
2025-11-15 20:51:24 +01:00
Radosław Gierwiało
b948b81f80 refactor: use environment-specific .env files
- Rename .env.example to .env.development.example
- Update docker-compose.yml to use env_file for dev backend
- Update .gitignore to ignore .env.development and .env.production
- Remove generic .env and .env.example in favor of:
  * .env.development (dev) + .env.development.example (template)
  * .env.production (prod) + .env.production.example (template)
2025-11-15 17:26:16 +01:00
Radosław Gierwiało
a400068053 feat: add production Docker setup with multi-stage builds
- Add production Dockerfiles for frontend and backend
  * Frontend: multi-stage build with nginx serving static files
  * Backend: multi-stage build with Prisma generation
- Create production nginx configuration (nginx/conf.d.prod/)
  * Routes to frontend-prod:80 and backend-prod:3000
  * Supports WebSocket connections for Socket.IO
- Update docker-compose.yml to use production config
  * Add env_file support for backend-prod
  * Mount production nginx config directory
- Add .env.production.example template for deployment
2025-11-15 17:21:25 +01:00
Radosław Gierwiało
91962ab4d5 test: add comprehensive WebRTC test suite
Add test coverage for WebRTC signaling and detection:

Backend tests (socket-webrtc.test.js):
- WebRTC offer/answer relay via Socket.IO
- ICE candidate exchange
- Authorization checks for match access
- Full WebRTC signaling flow
- All 7 tests passing

Frontend tests (ready for test runner):
- webrtcDetection.test.js: Browser WebRTC capability detection
- WebRTCWarning.test.jsx: Warning component rendering and interaction

Note: Frontend tests require test runner setup (e.g., Vitest)
2025-11-15 16:29:15 +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
6948efeef9 test: fix CORS test and remove duplicate events-checkin tests
- Fixed app.test.js CORS test by adding Origin header
- Removed duplicate events-checkin.test.js (covered by events.test.js)
- Improved app.js coverage to 97.43%

Note: Individual test files pass 100% when run separately:
- events.test.js: 34/34 passing (82% coverage)
- users.test.js: 25/25 passing (90% user.js, 82% users.js)
- matches.test.js: 24/24 passing (76% coverage)

Database conflicts occur when running all tests in parallel.
Consider using --runInBand for sequential execution.
2025-11-14 23:43:28 +01:00
Radosław Gierwiało
47a21b5fd6 test: add comprehensive test suite for User Profiles API
- Created users.test.js with 25 tests covering all 4 endpoints:
  * GET /api/users/me - get current user profile
  * PATCH /api/users/me - update profile (all fields)
  * PATCH /api/users/me/password - change password
  * GET /api/users/:username - get public profile
  * GET /api/users/:username/ratings - get user ratings

- All 25 tests passing (100%)
- controllers/user.js coverage: 90.16% (up from 8.19%)
- routes/users.js coverage: 81.81% (up from 27.27%)
- Tested email change with verification
- Tested password security and validation
2025-11-14 23:38:07 +01:00
Radosław Gierwiało
1747bf2d91 test: add comprehensive test suite for Events API
- Created events.test.js with 34 tests covering all 10 endpoints:
  * GET /api/events - list events with join status
  * GET /api/events/:slug - event details
  * GET /api/events/:slug/messages - event chat messages
  * POST /api/events/checkin/:token - QR code checkin
  * GET /api/events/:slug/details - detailed event info
  * DELETE /api/events/:slug/leave - leave event
  * POST /api/events/:slug/heats - add/update user heats
  * GET /api/events/:slug/heats/me - get user's heats
  * GET /api/events/:slug/heats/all - get all heats
  * DELETE /api/events/:slug/heats/:id - delete heat

- All 34 tests passing (100%)
- events.js coverage: 82.02% (up from 8.98%)
- Branch coverage: 75%
- Function coverage: 88.23%
2025-11-14 23:30:34 +01:00
Radosław Gierwiało
6697c1d60a test: fix remaining 5 test failures in matches.test.js
- Changed expected status from 404 to 403 for non-participant access
- Fixed rating response structure (data directly, not data.rating)
- Added testUser3 to setup to avoid duplicate match constraints
- Updated tests to use different user combinations to avoid conflicts

All 24 tests now passing (100%)
Coverage: matches.js improved to 76.58% statement coverage
2025-11-14 23:18:37 +01:00
Radosław Gierwiało
830f08edba test: add comprehensive test suite for Matches & Ratings API
- Created matches.test.js with 24 tests covering:
  * Match creation and validation
  * Match listing and filtering
  * Match acceptance workflow
  * Match deletion
  * Rating creation and validation
  * User ratings display

- Fixed Jest ES module issues:
  * Added mock for jsdom to bypass parse5 compatibility
  * Added mock for dompurify for test environment
  * Updated package.json with moduleNameMapper

Test results: 19/24 passing (79%)
Remaining: 5 tests need investigation
2025-11-14 23:12:08 +01:00
Radosław Gierwiało
49e492a8f8 feat: implement Ratings API (Phase 2.5)
Complete the match lifecycle with partner rating functionality.

Backend changes:
- Add POST /api/matches/:slug/ratings endpoint to create ratings
  * Validate score range (1-5)
  * Prevent duplicate ratings (unique constraint per match+rater+rated)
  * Auto-complete match when both users have rated
  * Return detailed rating data with user and event info
- Add GET /api/users/:username/ratings endpoint to fetch user ratings
  * Calculate and return average rating
  * Include rater details and event context for each rating
  * Limit to last 50 ratings
- Add hasRated field to GET /api/matches/:slug response
  * Check if current user has already rated the match
  * Enable frontend to prevent duplicate rating attempts

Frontend changes:
- Update RatePartnerPage to use real API instead of mocks
  * Load match data and partner info
  * Submit ratings with score, comment, and wouldCollaborateAgain
  * Check hasRated flag and redirect if already rated
  * Validate match status before allowing rating
  * Show loading state and proper error handling
- Update MatchChatPage to show rating status
  * Replace "Rate Partner" button with "✓ Rated" badge when user has rated
  * Improve button text from "End & rate" to "Rate Partner"
- Add ratings API functions
  * matchesAPI.createRating(slug, ratingData)
  * ratingsAPI.getUserRatings(username)

User flow:
1. After match is accepted, users can rate each other
2. Click "Rate Partner" in chat to navigate to rating page
3. Submit 1-5 star rating with optional comment
4. Rating saved and user redirected to matches list
5. Chat shows "✓ Rated" badge instead of rating button
6. Match marked as 'completed' when both users have rated
7. Users cannot rate the same match twice
2025-11-14 22:35:32 +01:00
Radosław Gierwiało
c2010246e3 feat: add match slugs for security and fix message history loading
Security improvements:
- Add random CUID slugs to Match model to prevent ID enumeration attacks
- Update all match URLs from /matches/:id to /matches/:slug
- Keep numeric IDs for internal Socket.IO operations only

Backend changes:
- Add slug field to matches table with unique index
- Update all match endpoints to use slug-based lookups (GET, PUT, DELETE)
- Add GET /api/matches/:slug/messages endpoint to fetch message history
- Include matchSlug in all Socket.IO notifications

Frontend changes:
- Update all match routes to use slug parameter
- Update MatchesPage to use slug for accept/reject/navigate operations
- Update MatchChatPage to fetch match data by slug and load message history
- Update RatePartnerPage to use slug parameter
- Add matchesAPI.getMatchMessages() function

Bug fixes:
- Fix MatchChatPage not loading message history from database on mount
- Messages now persist and display correctly when users reconnect
2025-11-14 22:22:11 +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
92315d5a8c feat: add test accounts and secure event slugs
Security improvements:
- Add @default(cuid()) to Event.slug for auto-generated random slugs
- Prevent ID enumeration attacks (no more predictable slugs like "warsaw-dance-festival-2025")
- Event slugs now generated as secure cuid strings (e.g., "cmhz3lcgb00018vbn34v4phoi")

Test accounts:
- Add 3 test users to seed (john_dancer, sarah_swings, mike_blues)
- All users checked in to Warsaw Dance Festival 2025
- Pre-configured heats for testing matchmaking system
- Full profiles with WSDC IDs, social media, and locations

Seed improvements:
- Add bcryptjs for password hashing
- Add Prisma seed configuration to package.json
- Use worldsdcId for event upsert (instead of slug)
- Auto-generate event slugs via Prisma default

Documentation:
- Add test account credentials to SESSION_CONTEXT.md
- Document event slug security model
- Include sample heats for each test user
2025-11-14 17:55:29 +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
02d3d7ac42 feat: add competition heats system backend
- Add 3 new database tables: divisions, competition_types, event_user_heats
- Add seed data for 6 divisions (NEW, NOV, INT, ADV, ALL, CHA) and 2 competition types (J&J, STR)
- Add API endpoints for divisions and competition types
- Add heats management endpoints in events route (POST/GET/DELETE)
- Implement unique constraint: cannot have same role in same division+competition type
- Add participant verification before allowing heats management
- Support heat numbers 1-9 with optional Leader/Follower role
2025-11-14 15:32:40 +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
6823851b63 fix: improve event check-in UX and participant counting
Backend:
- Use _count.participants for accurate real-time participant count
- Remove reliance on stale participantsCount column

Frontend:
- Show check-in requirement message for non-joined events
- Display "Open chat" button only for joined events
- Add dev-only "View details" button for QR code access during testing
- Improve visual feedback with amber-colored check-in notice

This ensures the participant count reflects actual checked-in users
and prevents unauthorized access to QR codes in production while
maintaining developer convenience in development mode.
2025-11-14 14:20:20 +01:00
Radosław Gierwiało
71cba01db3 feat: add QR code event check-in system
Backend:
- Add event_checkin_tokens table with unique tokens per event
- Implement GET /api/events/:slug/details endpoint (on-demand token generation)
- Implement POST /api/events/checkin/:token endpoint (date validation only in production)
- Implement DELETE /api/events/:slug/leave endpoint
- Add comprehensive test suite for check-in endpoints

Frontend:
- Add EventDetailsPage with QR code display, participant list, and stats
- Add EventCheckinPage with success/error screens
- Add "Leave Event" button with confirmation modal to EventChatPage
- Install qrcode.react library for QR code generation
- Update routing and API client with new endpoints

Features:
- QR codes valid from (startDate-1d) to (endDate+1d)
- Development mode bypasses date validation for testing
- Automatic participant count tracking
- Duplicate check-in prevention
- Token reuse for same event (generated once, cached)
2025-11-14 14:11:24 +01:00
Radosław Gierwiało
5bea2ad133 build: add Docker entrypoint scripts for automated setup
- Add backend entrypoint with automated Prisma migrations and client regeneration
- Add frontend entrypoint with dependency management
- Update Dockerfiles to use entrypoint scripts
- Ensures database schema stays in sync with Prisma Client after migrations
2025-11-14 13:35:10 +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
897d6e61b3 feat: add public user profiles
- Add GET /api/users/:username endpoint for public profiles
- Create PublicProfilePage component with user stats and info
- Add getUserByUsername function to API service
- Add /:username route to App.jsx
- Display user info: name, location, stats, WSDC ID, social links
- Only show public data (no email or sensitive information)
- Accessible only to authenticated users

Users can now view public profiles of other users by visiting
/<username>. The profile displays stats, location, WSDC ID, and
social media links.
2025-11-13 21:03:37 +01:00
Radosław Gierwiało
144b13a0cf feat: add country and city fields to user profile
- Add country and city fields to User model
- Create database migration for location fields
- Add validation for country and city (max 100 characters)
- Create countries.js with complete list of 195 countries
- Add country dropdown select and city text input to profile page
- Include country and city in GET /api/users/me response
- Update profile form to support location data

Users can now select their country from a dropdown list of all
countries and enter their city name.
2025-11-13 20:57:43 +01:00
Radosław Gierwiało
48f9dfe1b4 feat: add social media links to user profile
- Add YouTube, Instagram, Facebook, and TikTok URL fields to User model
- Create database migration for social media link columns
- Add custom validators to ensure URLs contain correct domains
- Update profile page with social media input fields
- Include social media URLs in GET /api/users/me response
- Add icons for each social platform in the UI

Users can now add links to their social media profiles. Each field
validates that the URL contains the appropriate domain (e.g.,
instagram.com for Instagram, youtube.com/youtu.be for YouTube).
2025-11-13 20:47:57 +01:00
Radosław Gierwiało
ebf4b84ed2 fix: profile page form pre-population and WSDC ID editing
- Add useEffect to pre-fill profile form with current user data
- Add WSDC ID field to profile edit form with numeric validation
- Update backend to accept wsdcId in profile updates with null handling
- Add wsdcId validation to updateProfileValidation middleware
- Include firstName, lastName, wsdcId in GET /api/users/me response

Fixes issue where profile inputs were empty on page load and allows
users to update their WSDC ID.
2025-11-13 20:38:36 +01:00