Conversation
The ON CONFLICT DO UPDATE statement was calculating error_rate using old column values (before increment), causing statistics to be off by one measurement. Fixed by computing error_rate with incremented values: - error_rate = CAST(total_wrong + ? AS REAL) / (total_shown + 1) * 100 Tested with multiple answers on same questions: - Q5: 3 shown, 3 wrong → 100% ✅ - Q10: 3 shown, 2 wrong → 66.67% ✅ 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
Issues fixed: 1. skipQuestion() was not calling logBackendAnswer() 2. Skipped questions were not added to topWrongQuestions 3. This caused mismatch between wrongAnswers count and actual answers rows in DB 4. Telegram stats never showed skipped questions Changes: - app.js: skipQuestion() now treats skip as wrong answer - Gets current question - Adds to topWrongQuestions - Calls logBackendAnswer(questionId, false) - backend/database.js: Fix error_rate calculation for INSERT - Added error_rate to INSERT VALUES - First answer now correctly shows 100% or 0% error_rate - Previously showed 0% for all first answers Tested: - Q5 (correct): error_rate=0.0% ✅ - Q12 (skipped): logged as wrong, error_rate=100.0% ✅ - Q25 (wrong): error_rate=100.0% ✅ - Telegram notification includes skipped questions ✅ 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
Critical security issue:
- README instructed to serve repository root via Nginx
- This made .env publicly downloadable at https://domain/.env
- Telegram bot token would be immediately compromised
Changes:
1. Added security section in README with warnings
2. Updated Nginx config with deny rules:
- Block all dotfiles: location ~ /\.
- Block sensitive paths: .env, .git, node_modules, backend/*
3. Added .htaccess for Apache users with same protections
4. Added verification steps to check after deployment
Nginx rules added:
- location ~ /\. { deny all; return 404; }
- location ~* ^/(\.env|\.git|node_modules|backend/) { deny all; }
Apache .htaccess added:
- Denies access to .env and all dotfiles
- Blocks backend/ and node_modules/ directories
- Additional protection for sensitive file extensions
Verification:
curl https://domain/.env → should return 404/403
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
…ection Major Changes: Backend Security (database.js, server.js): - Migrate questions from JSON to SQLite (396 questions) - Questions stored in protected backend/data/, not accessible via web - Remove correct answer flags from API responses - Implement session token authentication for all protected endpoints - Add GET /api/session/:id/next - load one question at a time - Add POST /api/session/:id/submit-answer - server-side answer validation - Add POST /api/session/:id/focus-switch - log suspicious activity - Track session state: question_ids, current_question_index, focus_switches Frontend Security (app.js, security.js, style.css): - Remove questions_data.json from frontend (moved to backend) - Load questions one-by-one via protected API - localStorage stores ONLY sessionId/Token, NOT questions or answers - Implement anti-cheat protection module (security.js): * Block copy-paste (Ctrl+C, Ctrl+V, Ctrl+X) * Disable right-click context menu * Prevent text selection (user-select: none) * Detect DevTools opening (F12, Ctrl+Shift+I/J/C) * Monitor focus/tab switches with visual warnings - Add semi-transparent UUID watermark over exam screen - Log all suspicious activity to backend Migration & Tooling: - Add migrate-database.js - SQLite schema migration script - Add migrate-questions.js - JSON to SQLite data migration - Preserves all question data except correct answer flags in public API - Correct answers stored securely in separate column Testing: - API endpoints tested and working - 396 questions migrated successfully - Session token validation working - Frontend successfully integrated with secure API Security Benefits: - Correct answers never sent to client - Impossible to view answers in DevTools/localStorage - Exam integrity maintained through server-side validation - Suspicious activity (focus switches, DevTools) logged - User identification via persistent UUID watermark 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
The frontend is served by Express on port 3000, but localhost:3000 wasn't in the allowedOrigins list, causing CORS errors when frontend tried to fetch from the API. Fixed by adding: - http://localhost:3000 - http://127.0.0.1:3000 to the development allowedOrigins array. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Problem: When completing a test, the result screen showed 0 for all counters, but displayed correct values after page refresh. Root cause: Race condition when user clicks Exit button while checkAnswer() is still processing asynchronously. Local counters (correctAnswersCount, wrongAnswersCount) weren't updated yet. Solution: 1. In showResults(), fetch actual counters from server via new endpoint GET /api/stats/session/:id before displaying results 2. Added 100ms delay in Exit button handler to let pending operations complete 3. Server-side counters are always accurate since answers are logged to DB This ensures results are always correct regardless of timing or how user exits the test (Exit button vs automatic completion). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Allows users to click Exit button to view current progress/statistics, then return to continue the test from where they left off. Session only ends when all questions completed or user explicitly goes home/restarts. - Added continueTestBtn to result screen - Modified showResults() to accept forceEnd parameter - Session stays active for intermediate result views - Continue button shown only when questions remain - Updated restartTest() to force end session before restarting - Updated goToStart() to properly end session before going home 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Remove duplicate /api prefix in session stats endpoint call. The apiRequest function already includes /api in the base URL. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Prevent accidental session termination by disabling header click when user is on question screen. Header remains clickable on all other screens (home, results, info) for navigation. - Added logic to showScreen() to toggle header interactivity - cursor: pointer disabled on questionScreen - pointerEvents: none prevents clicks during test - Users must use explicit "Exit" button to leave test 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Created favicon featuring Class 4 hazardous materials sign: - Diamond shape with black border - Upper half white with black flame symbol - Lower half red - Number "4" at bottom - Based on real hazardous cargo warning signage 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Implemented interactive Telegram bot using long polling to respond to commands from authorized users. Features: - Long polling mechanism for receiving Telegram updates - /difficult command - shows top 10 most difficult questions - Authorization check (only TELEGRAM_CHAT_ID can use commands) - Graceful start/stop of polling with server lifecycle - New database function getDifficultQuestions(limit) Technical details: - Uses getUpdates API with 30s timeout - Polling interval: 2 seconds - Proper error handling and logging - Unauthorized access attempts are logged but ignored Example response format: ❗️ Топ-10 самых сложных вопросов: 1. Вопрос #142 📊 Ошибок: 65.2% (показан 23 раз) ... 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Reorganized project structure for better maintainability: Frontend: - Moved static assets to frontend/public/ - Moved source files to frontend/src/ - Updated all resource paths in index.html Backend: - Moved core files to backend/src/ - Organized config files in src/config/ - Organized services in src/services/ - Moved migration scripts to scripts/ - Updated all import paths and dotenv config - Removed unnecessary .htaccess file Root level: - Added package.json with npm workspaces - Added Docker support (docker-compose.yml, .dockerignore) - Added comprehensive documentation (DATABASE.md, API.md, TELEGRAM.md) - Added setup automation script (setup.sh) - Updated .gitignore for better coverage All file moves preserve git history via git mv. Server tested and confirmed working on port 3000. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Move path module import before dotenv.config() and use path.join() to properly resolve .env file location from backend/src/ directory. This fixes Telegram bot configuration not being loaded properly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Added automatic hiding of DevTools detection warning message after 5 seconds with fade-out animation, similar to focus switch warnings. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Added PM2 + Nginx deployment setup with complete documentation: Deployment Files: - ecosystem.config.js: PM2 process manager configuration - nginx.conf.example: Nginx reverse proxy config for subdomain - deploy.sh: Automated deployment script with git pull and PM2 restart - docs/DEPLOYMENT.md: Complete VPS deployment guide Documentation: - Step-by-step VPS setup instructions - DNS and subdomain configuration - SSL setup with Let's Encrypt - Firewall configuration (UFW) - Monitoring and troubleshooting - Backup strategies - Security best practices Updates: - README.md: Updated structure section, added deployment quick start - .gitignore: Added PM2 logs, backups, and pid files Features: - One-command deployment with deploy.sh - Automatic SSL with certbot - Production-ready PM2 configuration with auto-restart - Nginx optimization for static files - Security headers and access controls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Fixed 'Cannot GET /' error by adding explicit route that serves index.html for all non-API requests. Also fixed PM2 ecosystem.config.js to use fork mode instead of cluster mode to prevent EADDRINUSE errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Modified wildcard route to skip static file requests (js, css, images) and only serve index.html for non-static routes. This fixes MIME type errors where CSS/JS files were being served as HTML. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Changed image paths from 'img/' to 'public/img/' to reflect new directory structure after frontend reorganization. Fixes 404 errors for question images. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Added purple gradient background with hover effects and shadow for the exit button (#exitBtn). Random text generation preserved. Style features: - Purple gradient (667eea → 764ba2) - Smooth hover animation with reverse gradient - Enhanced shadow effects - Active state feedback 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Changed exit button gradient from purple to elegant dark blue: - Base: #2c3e50 → #3498db (dark slate to blue) - Hover: lighter shade with enhanced glow - Maintains smooth animations and shadow effects 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Enhanced /api/stats endpoint to include full question data - Statistics page now shows complete question text and all answers - Correct answers highlighted with green border - Added question cards with clean borders and spacing - Removed document links and hover effects for cleaner UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Added statistics mode card to main page with 3-card responsive layout - Increased container width to 1000px to accommodate 3 cards - Added responsive grid that stacks cards vertically on screens ≤800px - Updated PM2 port configuration to 3001 - Temporarily disabled shuffle checkbox in training mode 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Changed localhost API port from 3000 to 3001 to match server configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Added http://localhost:3001 and http://127.0.0.1:3001 to allowed origins - Fixes CORS blocking when accessing from port 3001 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…tions - Total sessions now counts only completed tests with >= 45 questions - Average percentage calculated only from full completed tests - Top difficult questions derived from answers in completed tests only - Ensures statistics reflect actual test performance, not partial attempts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Changed "Уникальных пользователей" to "Уникальных идентификаторов пользователей" - More accurately reflects that we track unique UUIDs, not actual users 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Fixed dbPath in migrate-database.js from '../config/statistics.db' to '../src/config/statistics.db' - Ensures migration script finds the actual production database - Prevents schema mismatch errors when server tries to insert sessions with new columns 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Created Dockerfile with Node.js 18 Alpine base image - Uses production dependencies only (npm ci --only=production) - Exposes port 3001 to match project configuration - Added .dockerignore to exclude node_modules, logs, and .env from build 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Updated backend/.env.example default PORT to 3001 - Changed server.js fallback port from 3000 to 3001 - Fixed docker-compose.yml to use correct database path (src/config/statistics.db) - Updated nginx.conf.example proxy_pass to port 3001 - Ensures consistent port configuration across all environments 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Changed skip flow to submit answerId=null instead of answers[0].id - Backend now treats null answerId as guaranteed incorrect answer - Prevents ~33% of skipped questions from being incorrectly marked as correct - Fixes statistics accuracy in /api/stats difficulty analytics - Ensures skipped questions are properly reflected in answers/questions_stats tables 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Added X-Session-Token header validation to /api/session-end - Modified endSession() in database.js to verify token before updating - Frontend now includes session token when ending sessions - Prevents unauthorized clients from: - Finalizing arbitrary session IDs - Polluting statistics with fake results - Spamming Telegram notifications - Manipulating other users' sessions - Returns 401 if token missing, 403 if token invalid 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… upgrades - Updated deploy.sh to detect and migrate old DB from backend/statistics.db to backend/src/config/statistics.db - Created automated migration script (scripts/migrate-db-location.sh) with backup functionality - Added npm script 'migrate:db-location' for manual migration - Created MIGRATION.md with detailed upgrade instructions - Prevents data loss when upgrading from old DB location - Automatically runs schema migration after moving database Migration process: 1. Creates src/config directory if missing 2. Creates timestamped backup of old database 3. Moves DB to new location 4. Runs schema migration to add new columns 5. Preserves all existing session/answer statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…d response Critical security fix for session enumeration and token exposure: Backend changes: - Modified getSessionStats() to require session token for active sessions - With token: returns full data (excludes session_token from response) - Without token: returns only public data for completed sessions - Updated /api/stats/session/:id endpoint to validate X-Session-Token header - Returns 403 if token invalid, 404 if session not found or not completed Frontend changes: - Added token authentication to session stats requests - Ensures only session owner can access active session data Prevents: - Session ID enumeration attacks - Session token exposure via API responses - Unauthorized access to active sessions - Hijacking tests by submitting answers with stolen tokens - Manipulating focus-switch counters of other users 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
No description provided.