Commit Graph

215 Commits

Author SHA1 Message Date
Radosław Gierwiało
e1fabeb297 chore(docker): configure production resource limits for 4 CPU / 8GB server
- nginx-prod: 0.5 CPU / 512M RAM (limits), 0.25 CPU / 256M (reserved)
- frontend-prod: 0.5 CPU / 512M RAM (limits), 0.25 CPU / 256M (reserved)
- backend-prod: 1.5 CPU / 2G RAM (limits), 1.0 CPU / 1G (reserved)
- db-prod: 1.0 CPU / 3G RAM (limits), 0.75 CPU / 2G (reserved)

Total: 3.5 CPU / 6GB limits, 2.25 CPU / 3.5GB reserved
Leaves ~0.5 CPU / 2GB for host system
2025-12-06 12:26:29 +01:00
Radosław Gierwiało
b556abb854 feat(seed): split seed scripts into production and development
- Create seed.production.js with admin user, divisions, and competition types only
- Rename seed.js to seed.development.js with all test data
- Add admin@spotlight.cam account with isAdmin flag and COMFORT tier
- Update test users to use @spotlight.cam domain and SUPPORTER tier
- Remove wsdcId from test users
- Add npm scripts: prisma:seed:dev and prisma:seed:prod
- Add Makefile targets: seed-dev and seed-prod
2025-12-06 12:23:05 +01:00
Radosław Gierwiało
4066bf1081 refactor(ui): remove History link and add footer to authenticated pages
- Remove History navigation link from both desktop and mobile navbar
- Create dedicated Footer component for authenticated users
- Add Footer to Layout component used on Dashboard and other protected pages
- Footer includes platform navigation, support links, and legal section
2025-12-06 12:09:33 +01:00
Radosław Gierwiało
c7e577bf12 feat(chat): add user status grouping and 'No heats' indicator
Improved participants sidebar UX by grouping users and clearly showing
who can't be contacted for match requests and why.

User Status Groups (in order):
1. Available - Online with declared heats (🟢 green dot)
   - Ready to receive match requests
   - Shows heat badges
   - Active match button with "Send match request" tooltip

2. Online - No Heats - Online but no heats declared (🟡 yellow dot)
   - Shows "No heats declared" gray badge
   - Match button disabled with "User has not declared heats yet" tooltip
   - Clear visual indicator of unavailability reason

3. Offline - Not currently online ( gray dot)
   - Can still send requests if they have heats (button faded)
   - Shows "No heats declared" badge if no heats
   - Match button disabled if no heats

Visual Improvements:
- Color-coded status dots for quick scanning
- Section headers with user counts per group
- "No heats declared" badge for users without heats
- Clear, contextual tooltips on disabled states
- Better spacing between groups (space-y-4 vs space-y-2)

Benefits:
- Users immediately see who's available to match
- No confusion about why buttons are disabled
- Priority given to online users with heats
- Reduced support questions
- Better conversion (users know what to do)

Applies to:
- Desktop sidebar (visible on chat tab)
- Mobile participants tab
2025-12-06 12:01:35 +01:00
Radosław Gierwiało
3d991d6f96 docs: update How It Works page with comprehensive user guide
Replaced Lorem Ipsum placeholder with detailed step-by-step guide
explaining the entire platform workflow from registration to rating.

Content includes:
- 10-step process (registration → check-in → matching → video exchange → rating)
- Two matching methods: auto-matching and manual requests
- Detailed explanation of WebRTC P2P video transfer
- Features overview (Chat, Matching, Transfer, Profiles)
- Tips for success and best practices
- Links to other help resources

Design improvements:
- Numbered step badges with circular icons
- Color-coded tip boxes for important information
- Intro box highlighting main value proposition
- Better visual hierarchy with custom styling
- Responsive layout with proper spacing

User-focused content:
- Non-technical language (explains what, not how)
- Practical instructions dancers can follow at events
- Emphasis on community karma and fairness system
- Mentions beta SUPPORTER tier benefits
2025-12-06 11:55:37 +01:00
Radosław Gierwiało
e2b10387c2 feat(beta): add beta testing features and privacy policy page
Implemented comprehensive beta testing system with tier badges and
reorganized environment configuration for better maintainability.

Beta Testing Features:
- Beta banner component with dismissible state (localStorage)
- Auto-assign SUPPORTER tier to new registrations (env controlled)
- TierBadge component with SUPPORTER/COMFORT tier display
- Badge shown in Navbar, ProfilePage, and PublicProfilePage
- Environment variables: VITE_BETA_MODE, BETA_AUTO_SUPPORTER

Environment Configuration Reorganization:
- Moved .env files from root to frontend/ and backend/ directories
- Created .env.{development,production}{,.example} structure
- Updated docker-compose.yml to use env_file for frontend
- All env vars properly namespaced and documented

Privacy Policy Implementation:
- New /privacy route with dedicated PrivacyPage component
- Comprehensive GDPR/RODO compliant privacy policy (privacy.html)
- Updated CookieConsent banner to link to /privacy
- Added Privacy Policy links to all footers (HomePage, PublicFooter)
- Removed privacy section from About Us page

HTML Content System:
- Replaced react-markdown dependency with simple HTML loader
- New HtmlContentPage component for rendering .html files
- Converted about-us.md and how-it-works.md to .html format
- Inline CSS support for full styling control
- Easier content editing without React knowledge

Backend Changes:
- Registration auto-assigns SUPPORTER tier when BETA_AUTO_SUPPORTER=true
- Added accountTier to auth middleware and user routes
- Updated public profile endpoint to include accountTier

Files:
- Added: frontend/.env.{development,production}{,.example}
- Added: backend/.env variables for BETA_AUTO_SUPPORTER
- Added: components/BetaBanner.jsx, TierBadge.jsx, HtmlContentPage.jsx
- Added: pages/PrivacyPage.jsx
- Added: public/content/{about-us,how-it-works,privacy}.html
- Modified: docker-compose.yml (env_file configuration)
- Modified: App.jsx (privacy route, beta banner)
- Modified: auth.js (auto SUPPORTER tier logic)
2025-12-06 11:50:28 +01:00
Radosław Gierwiało
a786b1d92d feat(analytics): integrate Google Analytics 4 with GDPR compliance
Prepared the application for Google Analytics 4 tracking with full
GDPR/RODO compliance. GA only loads after user explicitly accepts cookies.

Features:
- Automatic page view tracking on route changes
- Custom event tracking for key user actions
- Privacy-first: GA loads only after cookie consent
- Easy configuration via environment variable
- Comprehensive tracking utilities for common events

Implementation:
- Created analytics.js with GA initialization and event tracking functions
- Created usePageTracking hook for automatic page view tracking
- Integrated GA into App.jsx with AnalyticsWrapper component
- Updated CookieConsent to initialize GA after user consent
- Added VITE_GA_MEASUREMENT_ID to .env.example

Custom events tracked:
- login, sign_up (authentication)
- match_request, match_accepted (matching)
- webrtc_connection, file_transfer (WebRTC)
- event_join, recording_suggestion (events/recording)
- search (search functionality)

Setup:
1. Add VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX to .env
2. Restart frontend container
3. GA will auto-load after user accepts cookies

Documentation:
- Created comprehensive setup guide in docs/GOOGLE_ANALYTICS_SETUP.md
- Includes troubleshooting, debugging tips, and usage examples
2025-12-05 22:28:00 +01:00
Radosław Gierwiało
3523172ecb feat(compliance): add GDPR/RODO compliant cookie consent banner
Implemented cookie consent banner to comply with EU regulations (GDPR/RODO).
The banner appears on first visit and stores user preference in localStorage.

Features:
- Non-intrusive bottom banner with clear messaging
- Accept/Decline options for user choice
- Link to privacy policy in About Us page
- Responsive design for mobile and desktop
- Auto-dismisses after consent with 1s delay on first show
- High z-index to stay above all content

Also added comprehensive Privacy & Cookies section to About Us page
explaining:
- What cookies we use (essential, analytics, preferences)
- How we handle user data
- GDPR/RODO compliance statements
- Contact information for privacy questions

Changes:
- Created CookieConsent component with modern UI
- Integrated banner into App.jsx
- Updated about-us.md with privacy policy section
2025-12-05 22:22:23 +01:00
Radosław Gierwiało
2cab8c3eba feat(participants): add profile links to usernames in Participants tab
Enabled profile links for all usernames in the event Participants sidebar.
Users can now click on any participant's username to view their public
profile page at /u/username.

This improves user discoverability and allows participants to learn more
about other dancers before connecting or sending match requests.

Changes:
- Set linkToProfile={true} in ParticipantsSidebar for all UserListItem components
- Usernames now display as clickable links with hover state
2025-12-05 22:18:33 +01:00
Radosław Gierwiało
229aafc8e9 refactor(recordings): remove manual matching trigger from Recording tab
Removed "Run matching" buttons from the Recording tab to prevent manual
triggering. The system now only displays matching status information:
- Shows countdown when registration deadline is approaching
- Shows last run time when matching has been completed
- Shows informational message when matching hasn't run yet

This ensures matching is only triggered automatically by the system
or through the admin interface, maintaining better control over the
matching process.

Changes:
- Removed handleRunMatching function and runningMatching state
- Replaced actionable buttons with informational status displays
- Improved date/time formatting for last run timestamp
- Changed "not run yet" status to positive "will be run soon" message
2025-12-05 22:16:49 +01:00
Radosław Gierwiało
76be8a4419 refactor(frontend): replace confirm() with modern confirmation modals
Replaced all confirm() dialogs with reusable ConfirmationModal component
for better UX. Modal dialogs provide clearer context, visual consistency,
and prevent accidental confirmations.

Changes:
- MatchesPage: Reject match request confirmation modal
- DashboardPage: Decline and cancel request confirmation modals
- ContactMessagesPage: Delete message confirmation modal

All modals support loading states during async operations and provide
clear action descriptions with destructive action styling.
2025-12-05 22:14:09 +01:00
Radosław Gierwiało
bb8a876ab0 refactor(frontend): replace alert() with modern toast notifications
Replaced all alert() calls with react-hot-toast notifications for better
user experience. Toast notifications are non-blocking, auto-dismiss, and
provide visual feedback with icons based on message type.

Changes:
- EventChatPage: Match request success/error toasts
- MatchChatPage: Video file selection and WebRTC connection error toasts
- MatchesPage: Match accept/reject action toasts
- RatePartnerPage: Rating submission and validation toasts
- VerifyEmailPage: Email verification sent toast
- ScheduleConfigSection: Schedule save success/error toasts
- MatchingConfigSection: Deadline save success/error toasts

All toast notifications use appropriate types (success, error, warning, info)
for better visual distinction and user feedback.
2025-12-05 22:09:37 +01:00
Radosław Gierwiało
3ae9fd149b feat(frontend): add unified header and footer to public pages
Implemented consistent navigation across all public-facing pages with a
reusable layout system. Created PublicLayout component that wraps pages
with a header containing the logo and a footer with navigation links.

Changes:
- Created PublicHeader component with logo linking to homepage
- Created PublicFooter component with Product, Account, and Support sections
- Created PublicLayout wrapper component using flex layout
- Updated all public pages to use PublicLayout:
  - LoginPage, RegisterPage, ForgotPasswordPage, ResetPasswordPage
  - VerifyEmailPage, ContactPage, AboutUsPage, HowItWorksPage
  - NotFoundPage
- Fixed gradient background pages to use min-h-full for proper height
- Fixed content pages to avoid min-h-screen conflicts with flex-grow
- Updated About Us content
2025-12-05 21:59:56 +01:00
Radosław Gierwiało
c47d182b98 docs: update TODO.md with Phase 3.6 completion status
- Update test count to 351/351 (from 350)
- Add recent work entries for 2025-12-05:
  - Cloudflare TURN/STUN WebRTC integration
  - Public pages (About Us, How It Works)
  - Cloudflare Turnstile CAPTCHA
  - Contact form and 404 page
  - Responsive design improvements
2025-12-05 21:32:25 +01:00
Radosław Gierwiało
ef7b82aa5e docs: update documentation for Phase 3.6 features
Update README.md and SESSION_CONTEXT.md to reflect recent changes:

Phase 3.6 features:
- Cloudflare Turnstile CAPTCHA (registration & contact form)
- Cloudflare TURN/STUN servers for WebRTC
- Public profiles accessible without authentication
- Static content pages (About Us, How It Works)
- Contact form with admin panel
- 404 page with activity logging
- Responsive mobile design improvements
- Trust proxy configuration

Testing updates:
- 351 tests (up from 342), 100% passing
- 73% coverage (up from 72.5%)
- New webrtc-api.test.js with 9 comprehensive tests
- 100% coverage for routes/webrtc.js

Structure updates:
- New routes: /api/webrtc/ice-servers, /api/public/contact
- New admin pages: ContactMessagesPage
- Static content in frontend/public/content/
- Enhanced navbar with admin dropdown
2025-12-05 21:30:58 +01:00
Radosław Gierwiało
a92d7469e4 feat(webrtc): integrate Cloudflare TURN/STUN servers
- Add backend endpoint to fetch ICE server credentials from Cloudflare
- Implement dynamic ICE server configuration in frontend
- Add fallback to public STUN servers when Cloudflare unavailable
- Create comprehensive test suite for WebRTC API endpoint
- Update environment configuration with Cloudflare TURN credentials

Backend changes:
- New route: GET /api/webrtc/ice-servers (authenticated)
- Fetches temporary credentials from Cloudflare API with 24h TTL
- Returns formatted ICE servers for RTCPeerConnection
- Graceful fallback to Google STUN servers on errors

Frontend changes:
- Remove hardcoded ICE servers from useWebRTC hook
- Fetch ICE servers dynamically from backend on mount
- Store servers in ref for peer connection initialization
- Add webrtcAPI service for backend communication

Tests:
- 9 comprehensive tests covering all scenarios
- 100% coverage for webrtc.js route
- Tests authentication, success, and all fallback scenarios
2025-12-05 21:23:50 +01:00
Radosław Gierwiało
e1138c789e fix(homepage): improve responsive layout for mobile devices
Navigation:
- Reduce logo and text size on mobile (w-6 h-6 -> w-8 h-8 on sm+)
- Reduce spacing between nav items (space-x-2 -> space-x-4 on sm+)
- Hide 'Dashboard' text on mobile, show icon only
- Adjust padding and text sizes for all nav buttons
- Add whitespace-nowrap to 'Get Started' button

Hero section:
- Responsive heading sizes (text-3xl -> text-6xl)
- Responsive paragraph sizes (text-base -> text-2xl)
- Responsive padding (py-12 -> py-20)
- Responsive button sizes (px-6/py-3 -> px-8/py-4)
2025-12-05 18:42:52 +01:00
Radosław Gierwiało
00825d56b6 fix(profile): improve responsive layout for public profile
- Add flex-wrap to stats section to prevent overflow on small screens
- Make profile header flex-col on mobile, flex-row on larger screens
- Add flex-shrink-0 to icons to prevent them from shrinking
- Reduce padding on mobile (p-4) and increase on larger screens
- Add min-w-0 to prevent text overflow issues
2025-12-05 18:40:13 +01:00
Radosław Gierwiało
fb4e0bea99 refactor(profile): remove Matches count from public profile stats
- Remove Matches stat display from public profile
- Keep only Rating and Reviews stats visible
- Remove unused Users icon import
2025-12-05 18:38:14 +01:00
Radosław Gierwiało
d4dd7bac30 feat(navbar): make username clickable link to public profile
- Desktop: username and avatar link to /u/{username}
- Mobile: username section in dropdown links to public profile
- Adds hover effect to indicate clickability
2025-12-05 18:36:51 +01:00
Radosław Gierwiało
1f763d4558 refactor(footer): remove Events link from Product section 2025-12-05 18:34:51 +01:00
Radosław Gierwiało
c4372930dd feat(content): add How It Works page with markdown support
- Create HowItWorksPage component with markdown rendering
- Add how-it-works.md with Lorem Ipsum placeholder content
- Add /how-it-works route in App.jsx
- Add How It Works link to homepage footer (Product section)
2025-12-05 18:33:25 +01:00
Radosław Gierwiało
2c5689ac8e feat(content): add About Us page with markdown content support
- Create AboutUsPage component with markdown rendering
- Add react-markdown library for content rendering
- Create public/content directory for editable markdown files
- Add about-us.md with Lorem Ipsum placeholder content
- Create public/images/about directory for page images
- Add /about-us route in App.jsx
- Add About Us link to homepage footer
- Support for external links (open in new tab) and internal links
- Responsive image rendering with rounded corners and shadow
2025-12-05 18:30:44 +01:00
Radosław Gierwiało
d8085f828f feat(security): add Cloudflare Turnstile CAPTCHA to registration form
- Add Turnstile widget rendering in RegisterPage on step 2
- Implement programmatic widget initialization with callbacks
- Add token validation before form submission
- Update AuthContext and API service to pass turnstileToken
- Add backend verification via Cloudflare API in register controller
- Include client IP in verification request
- Add validation rule for turnstileToken
- Reset widget on registration error
2025-12-05 18:20:26 +01:00
Radosław Gierwiało
f3b8156557 feat(security): implement Cloudflare Turnstile CAPTCHA on contact form
- Add Turnstile script to frontend/index.html
- Implement programmatic widget rendering in ContactPage
- Add backend verification via Cloudflare API
- Include client IP in verification request
- Update CSP headers to allow Cloudflare resources
- Add environment variable configuration for site and secret keys
- Pass VITE_TURNSTILE_SITE_KEY to frontend container
- Add validation and error handling for CAPTCHA tokens
2025-12-05 18:08:05 +01:00
Radosław Gierwiało
25042d0fec feat(home): adapt homepage for authenticated users
Changes for logged-in users:
- Top navigation: Show "Dashboard" and "Logout" buttons instead of "Sign In" and "Get Started"
- Hero CTA: Change main button to "Go to Dashboard" instead of "Start Collaborating"
- Hide bottom CTA section (registration prompt) for authenticated users
- Footer Account section: Show "Dashboard" and "Logout" instead of "Sign In" and "Register"

Other improvements:
- Removed "Explore Events" button from hero section
- Cleaned up footer: removed empty placeholder links (Features, How It Works, About, Privacy, Terms)
- Added "Support" section in footer with "Contact Us" link to /contact
- Simplified footer to 3 columns: Product (Events), Support (Contact Us), Account (dynamic based on auth)
2025-12-05 17:21:55 +01:00
Radosław Gierwiało
34f18b3b50 feat(contact): add contact form with admin panel and navbar dropdown
Database changes:
- Added ContactMessage model to Prisma schema
- Fields: userId, username, firstName, lastName, email, subject, message, status, ipAddress
- Status enum: new, read, resolved
- Relation to User model

Backend changes:
- Added POST /api/public/contact endpoint for form submissions
- Works for both authenticated and non-authenticated users
- Validation for email, subject (3-255 chars), message (10-5000 chars)
- Activity logging for submissions
- Added admin endpoints:
  - GET /api/admin/contact-messages - list with filtering by status
  - GET /api/admin/contact-messages/:id - view single message (auto-marks as read)
  - PATCH /api/admin/contact-messages/:id/status - update status
  - DELETE /api/admin/contact-messages/:id - delete message

Frontend changes:
- Created ContactPage at /contact route
- For non-logged-in users: firstName, lastName, email, subject, message fields
- For logged-in users: auto-fills username, shows only email, subject, message
- Character counter for message (max 5000)
- Success screen with auto-redirect to homepage
- Created ContactMessagesPage at /admin/contact-messages
- Two-column layout: message list + detail view
- Filter by status (all, new, read, resolved)
- View message details with sender info and IP address
- Update status and delete messages
- Added admin dropdown menu to Navbar
  - Desktop: dropdown with Activity Logs and Contact Messages
  - Mobile: expandable submenu
  - Click outside to close on desktop
  - ChevronDown icon rotates when open

Note: CAPTCHA integration planned for future enhancement
2025-12-05 17:15:25 +01:00
Radosław Gierwiało
f90945aa47 fix(profiles): make public profiles accessible without authentication and unify 404 behavior
Backend changes:
- Removed authentication requirement from GET /api/users/:username endpoint
- Removed authentication requirement from GET /api/users/:username/ratings endpoint
- These are public profile endpoints and should be accessible to all users

Frontend changes:
- PublicProfilePage now shows NotFoundPage component when user doesn't exist
- Unified 404 behavior: both invalid URLs and non-existent users show the same 404 page
- NotFoundPage "Requested URL" box now only shows in dev mode (import.meta.env.DEV)
- Removed unused AlertCircle icon import from PublicProfilePage
2025-12-05 16:54:38 +01:00
Radosław Gierwiało
948c694ed6 feat(system): implement 404 page with activity logging and change profile route format
Backend Changes:
- Added public API endpoint /api/public/log-404 (no auth required)
- Created backend/src/routes/public.js for public endpoints
- Added ACTIONS.SYSTEM_404 and CATEGORIES.system to activity log service
- Registered public routes in app.js

Frontend Changes:
- Created NotFoundPage.jsx with standalone layout (no auth required)
- Added publicAPI.log404() to log 404 access attempts
- Logs both authenticated and anonymous users
- Changed profile route from /@:username to /u/:username
- Made profile route public (removed ProtectedRoute wrapper)
- Updated all profile links from /@${username} to /u/${username} in:
  - ChatMessage.jsx
  - DashboardMatchCard.jsx
  - MatchRequestCards.jsx
  - MatchCard.jsx
  - UserListItem.jsx
  - MatchChatPage.jsx
  - PublicProfilePage.jsx

Fixes:
- React Router doesn't support @ in path segments
- 404 page now accessible to non-authenticated users without redirect
- Profile route no longer catches all unmatched routes
2025-12-03 20:27:51 +01:00
Radosław Gierwiało
eb5aacd797 refactor(admin): move event details page to admin section
- Moved EventDetailsPage from /events/:slug/details to /admin/events/:slug/details
- Added admin authentication check with redirect to login/home
- Updated all navigation links across the app:
  - EventsPage: "View details (admin)" button
  - EventChatPage: "View QR Code (admin)" link
  - EventCard: handleViewDetails navigation
- Fixed relative imports after moving to admin folder

This page contains admin-only features (QR codes, participants list,
matching config, scheduler config, matching runs) and should only be
accessible to administrators.
2025-12-03 19:52:00 +01:00
Radosław Gierwiało
179aaa8f16 fix(admin): activity logs empty success filter showing no results
- Fixed issue where empty string success filter was interpreted as false
- Backend was filtering for only failed logs when success='' was sent
- Added check to skip sending success parameter when empty string
- Activity logs page now shows all logs when filters are set to 'All'

Bug: When user selected 'All' for success filter, frontend sent success='',
backend parsed this as success=false, showing only failed logs (usually none).
2025-12-03 19:39:16 +01:00
Radosław Gierwiało
6562db1518 fix(backend): enable trust proxy for correct client IP detection
- Added app.set('trust proxy', 1) to allow Express to read proxy headers
- Enables proper client IP detection behind nginx reverse proxy
- Added /api/debug/ip endpoint for IP forwarding verification

Without trust proxy, Express ignores X-Forwarded-For and X-Real-IP headers,
causing all requests to appear from nginx container IP (172.x.x.x).

This fix ensures:
- Activity logs record correct client IPs
- Rate limiting works per actual client IP
- Security features function properly
2025-12-03 19:30:58 +01:00
Radosław Gierwiało
d8d04adfc6 fix(nginx): allow Vite dev dependencies in development mode
- Changed regex /\. to /\.(git|svn|htaccess|htpasswd|env) to allow .vite directory
- Removed node_modules from nginx blocked paths for Vite dependency serving
- Set VITE_ALLOWED_HOSTS=all in development mode for Docker networking

Fixes issue where nginx was blocking Vite's pre-bundled dependencies in
/node_modules/.vite/deps/, causing 404 errors for React and other imports.
2025-12-03 19:21:52 +01:00
Radosław Gierwiało
f6fd983c68 docs: update documentation with chat enhancements
Document three recent chat improvements:

1. Real-time Active Users Fix (dd31761)
   - Fixed bug where users list didn't update when new users joined
   - Rewrote getAllDisplayUsers() to prioritize Socket.IO data

2. Message Length Limits (4a91a10)
   - Added 2000 character limit with visual counter
   - Backend + frontend validation

3. Spam Protection System (ace3311)
   - Rate limiting: 10 messages per minute
   - Duplicate detection within 60 second window
   - Profanity filter with Polish + English words

Updated:
- README.md: Added chat features to Events & Chat section
- SESSION_CONTEXT.md: New "Chat Enhancements" section
- COMPLETED.md: Comprehensive entry with problem/solution/impact
- Last updated dates: 2025-12-03
2025-12-03 00:03:37 +01:00
Radosław Gierwiało
ace33111a4 feat(chat): implement spam protection and profanity filter
Add comprehensive message validation with three protection mechanisms:

1. Rate Limiting: 10 messages per minute per user
2. Duplicate Detection: Prevents sending identical messages within 1 minute
3. Profanity Filter: Blocks inappropriate language (English + Polish)

Implementation:
- New messageValidation.js middleware with validateMessage() function
- Integrated into both event chat and match chat handlers
- Uses bad-words library (v2.0.0 for CommonJS compatibility)
- In-memory tracking with automatic cleanup every 5 minutes
- User-friendly error messages for each validation type

Technical details:
- Rate limit: 10 msg/min sliding window
- Duplicate check: Last 5 messages within 60s window
- Profanity: bad-words + 11 Polish words
- Memory management: Periodic cleanup of expired data
2025-12-02 23:59:16 +01:00
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
a8fcb5e6eb docs: update documentation with Activity Log System implementation
Updated all major documentation files to reflect the completed Activity
Log System (Phase 3.5) implementation.

Changes:
- README.md: Added Admin & Monitoring section, updated database schema
  to 12 tables, added Activity Log System to completed phases, updated
  project structure to show admin pages and services
- SESSION_CONTEXT.md: Updated recent work, added activity log system to
  core features, updated database schema, added comprehensive Phase 3.5
  overview with all implementation details
- COMPLETED.md: Added full Activity Log System entry with all 8 phases,
  implementation details, git commits, and access information

Updated dates to 2025-12-02.
2025-12-02 23:24:38 +01:00
Radosław Gierwiało
1051cc6754 feat(admin): implement activity logs frontend page (Phase 6-7)
Complete implementation of admin activity logs dashboard with real-time
streaming capabilities. Admin users can now monitor all system activity
through a comprehensive web interface.

Features:
- Stats dashboard with 4 key metrics (total logs, unique users, failures, 24h activity)
- Category breakdown visualization with color-coded badges
- Advanced filtering (date range, category, action type, username, success/failure)
- Paginated log table (50 entries per page) with sort by timestamp
- Real-time streaming toggle using Socket.IO
- Color-coded action badges (blue=auth, green=event, purple=match, red=admin, yellow=chat)
- Admin-only access with automatic redirect for non-admin users
- Responsive design for mobile and desktop

Frontend Changes:
- Created ActivityLogsPage.jsx (600+ lines) with complete UI implementation
- Added 3 admin API methods to api.js (getActivityLogs, getActivityLogActions, getActivityLogStats)
- Added /admin/activity-logs route to App.jsx
- Added admin navigation link to Navbar (desktop & mobile) with Shield icon
- Only visible to users with isAdmin flag

Implementation Details:
- Uses getSocket() from socket service for real-time updates
- Joins 'admin_activity_logs' Socket.IO room on streaming enable
- Receives 'activity_log_entry' events and prepends to table (first page only)
- Comprehensive error handling and loading states
- Empty states for no data
- Clean disconnect handling when streaming disabled

Testing:
- Build successful (no errors)
- Ready for manual testing and verification

Phase 8 (Testing) remains for manual verification of all features.
2025-12-02 23:17:19 +01:00
Radosław Gierwiało
08845704cf docs: update TODO with Activity Log System Phase 1-5 completion 2025-12-02 20:12:10 +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
4dd6603018 feat(activity-log): add admin API endpoints (Phase 4)
Added 3 admin-only endpoints for activity log management:

1. GET /api/admin/activity-logs
   - Query logs with comprehensive filtering
   - Supports: date range, action, category, username, userId, success
   - Pagination with limit/offset
   - Logs ADMIN_VIEW_LOGS action
   - Returns: logs array, total count, pagination info

2. GET /api/admin/activity-logs/actions
   - Get list of unique action types
   - Returns: action names and categories
   - Useful for filter dropdowns in UI

3. GET /api/admin/activity-logs/stats
   - Dashboard statistics
   - Returns: total logs, unique users, failed actions,
     success rate, logs by category, recent activity (24h)

All endpoints protected with authenticate + requireAdmin middleware.
2025-12-02 20:09:49 +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
0466ef9e5c security(nginx): block access to sensitive files and directories
Added comprehensive security rules to all nginx configurations:

Dev proxy (nginx/conf.d/default.conf):
- Block dotfiles and .git directory
- Block .env* files and config files
- Block node_modules, docker configs, package files
- Block backup files (.bak, .swp, ~)

Prod proxy (nginx/conf.d.prod/default.conf):
- All dev security rules
- Added security headers (X-Frame-Options, CSP, etc.)
- Strict CSP with frame-ancestors 'none'

Frontend container (frontend/nginx.conf):
- Block dotfiles and sensitive config files
- Block node_modules and build configs
- Added security headers

All blocked paths return 404 and disable logging to avoid log spam.

Blocks: .env*, .git, node_modules, docker*, package*.json,
prisma, backup*, *.bak, *.swp, tsconfig.json, and more.
2025-12-02 19:55:08 +01:00
Radosław Gierwiało
c9beee9a4e feat(admin): add Activity Log backend services (Phase 2)
Core services for activity logging system:

1. ActivityLog Service (backend/src/services/activityLog.js)
   - Centralized logging with fire-and-forget pattern
   - 18 action constants (auth, event, match, admin, chat)
   - Query interface with filtering (date, action, user, category)
   - Socket.IO emission for real-time streaming
   - Statistics and action types endpoints
   - Never throws - logging cannot crash app

2. Request Utility (backend/src/utils/request.js)
   - getClientIP() - Extract client IP from headers/socket
   - Handles X-Forwarded-For and X-Real-IP proxy headers
   - IPv6-mapped IPv4 conversion

3. Admin Middleware (backend/src/middleware/admin.js)
   - requireAdmin() - Protect admin routes
   - Fresh DB check of isAdmin flag
   - Returns 403 for non-admin users
   - Use after authenticate middleware

Next phases: logging integration points, API endpoints, frontend UI
2025-12-02 19:47:47 +01:00
Radosław Gierwiało
f9cdf2aa98 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.
2025-12-02 19:42:24 +01:00
Radosław Gierwiało
b77ccab9d4 refactor(emails): restructure email system and add recording notifications
- Move email templates to separate files in src/emails/templates/
- Create new email service architecture (service.js, index.js)
- Add recording suggestions email template for matching notifications
- Integrate email notifications with matching system (sends when suggestions created)
- Update controllers (auth.js, user.js) to use new email module
- Update tests to use new email module path
- Remove deprecated src/utils/email.js

Features:
- Template-based email system for easy editing
- Automatic email notifications when recording assignments are made
- Clean separation between template logic and sending logic
- Graceful error handling for AWS SES failures
2025-12-02 19:19:22 +01:00
Radosław Gierwiało
231d3d177c docs: update TODO and COMPLETED with spam protection and notifications
- Mark S15.1-15.2 (Rate Limiting & Spam Protection) as implemented
- Mark S16.1 (Socket Notifications) as implemented
- Update test count: 342 → 350 tests
- Add implementation details to COMPLETED.md
- Update recent work timeline
2025-12-01 00:07:24 +01:00
Radosław Gierwiało
ec659d83e8 feat(matches): implement spam protection and socket notifications
S15.1-15.2: Rate Limiting & Spam Protection
- Add max 20 pending outgoing match requests limit
- Implement rate limiter: 10 match requests per minute per user
- Return 429 status with clear error messages

S16.1: Socket Notifications for New Suggestions
- Emit 'recording_suggestions_created' event when matching creates suggestions
- Notify only assigned recorders (not NOT_FOUND status)
- Group suggestions by recorder for efficiency
- Include event details and suggestion count

Implementation:
- backend/src/routes/matches.js: Rate limiter + pending limit check
- backend/src/services/matching.js: Socket notifications in saveMatchingResults
- backend/src/__tests__/spam-protection-notifications.test.js: 8 test cases

Test coverage:
- TC1-TC3: Max pending requests (spam protection)
- TC4-TC5: Rate limiting (10/min)
- TC6-TC8: Socket notifications for new suggestions
2025-12-01 00:03:46 +01:00
Radosław Gierwiało
964897bdc0 docs: move completed tasks to archive and update TODO status
- Add recent completions to COMPLETED.md:
  - 3-Tier Account System & Fairness Algorithm (2025-11-29)
  - Mobile-first Design Improvements (2025-11-29)
  - Test Bot for Automated Testing (2025-11-29)
  - Ratings & Stats System (2025-11-30, 9 E2E tests)
  - Matching Runs Audit & origin_run_id Tracking (2025-11-30, 30 tests)
  - Documentation Reorganization (2025-11-30)
- Update TODO.md current status (342/342 tests passing - 100%)
- Remove "Recently Completed" sections from TODO.md
- Update implemented scenarios list
2025-11-30 20:22:07 +01:00