20 KiB
Security Awareness Learning Platform - Documentation
Complete technical documentation for the containerized security awareness training platform.
Table of Contents
- Platform Overview
- Architecture
- Getting Started
- User Roles & Workflows
- Lessons System
- API Reference
- Database Schema
- Frontend Components
- Deployment
- Development Guide
Platform Overview
Purpose
A containerized web application for security awareness training featuring:
- Hub-based architecture - Participants join events with pseudonyms
- Modular lessons - Easily expandable lesson system
- Interactive content - Hands-on security demonstrations
- Weighted scoring - Flexible point configuration per event
Technology Stack
- Backend: Node.js 18 + Express
- Frontend: React 18 + Vite 5
- Database: PostgreSQL 15
- Deployment: Docker Compose
- Lesson Format: YAML configs + JavaScript modules
Key Features
- ✅ No registration required for participants (pseudonym-based)
- ✅ Admin panel with password authentication
- ✅ Interactive security lessons (SQL injection, phishing demos)
- ✅ Progress tracking and analytics
- ✅ Weighted scoring system
- ✅ Containerized deployment (production-ready)
Architecture
High-Level Architecture
┌─────────────────────────────────────────────┐
│ User (Browser) │
└─────────────┬───────────────────────────────┘
│
├─── http://localhost (Frontend - Nginx)
│ ├─ Hub (Join Events)
│ ├─ Lesson Player
│ ├─ Admin Panel
│ └─ Progress Dashboard
│
├─── http://localhost:3000/api (Backend - Express)
│ ├─ Participant API
│ ├─ Admin API
│ ├─ Lesson API
│ └─ Lesson Modules
│
└─── PostgreSQL:5432 (Database)
├─ Events & Participants
├─ Lessons & Progress
└─ Answers & Scores
Container Architecture
services:
database:
- PostgreSQL 15 Alpine
- Volume: lesson_platform_data
- Health checks enabled
backend:
- Node.js 18 Alpine
- Depends on: database (healthy)
- Volumes: ./backend/lessons (lessons)
- Health endpoint: /health
frontend:
- Nginx Alpine
- Serves: React SPA
- Reverse proxy: API calls to backend
Data Flow
Participant Flow:
Hub → Join Event → View Lessons → Complete Lesson → View Progress
Admin Flow:
Login → Dashboard → Manage Events → Assign Lessons → View Analytics
Lesson Execution:
Start → Navigate Steps → Answer Questions → Submit → Complete
Getting Started
Prerequisites
- Docker Desktop or Docker Engine + Docker Compose
- 2GB RAM minimum
- Ports 80, 3000, 5432 available
Quick Start
-
Clone and Setup:
cd lernplattform cp .env.example .env # Edit .env with your settings -
Start Platform:
docker-compose up -d -
Verify Health:
docker-compose ps # All should be "healthy" curl http://localhost:3000/health -
Access:
- Participants: http://localhost
- Admin: http://localhost/admin/login
- Username:
admin - Password:
admin123
- Username:
-
Seed Lessons (if needed):
docker exec lernplattform_backend node seed-lessons.js
First Time Setup
-
Create an Event:
- Login to admin panel
- Click "Manage Events"
- Create new event with name and dates
-
Assign Lessons:
- Click "Manage Lessons" on event
- Assign lessons with weights
- Configure max points
-
Test as Participant:
- Go to http://localhost
- Join the event with a pseudonym
- Complete a lesson
User Roles & Workflows
Participant Role
Capabilities:
- Join events with pseudonym (no registration)
- View assigned lessons
- Complete interactive lessons
- Submit answers and receive immediate feedback
- View personal progress and score
- Complete lessons in any order (unless locked)
Workflow:
- Navigate to hub page
- Select event from dropdown
- Enter pseudonym
- Click "Join Event"
- View lesson list
- Click lesson to start
- Navigate through steps
- Answer questions
- Complete lesson
- View updated score
Session Management:
- Session token stored in localStorage
- Remains logged in across browser sessions
- Can logout to join different event
Admin Role
Capabilities:
- Create, edit, delete events
- Assign lessons to events
- Configure lesson weights and points
- View participant data and progress
- See detailed answers submitted
- Export analytics
Workflow:
Event Management:
- Login to admin panel
- Navigate to Event Management
- Create/edit/delete events
- Set dates and active status
Lesson Configuration:
- Select event
- Click "Manage Lessons"
- Assign lessons from catalog
- Set order, weights, points
- Mark as required/optional
Monitor Progress:
- Select event
- Click "View Participants"
- See completion rates
- Click participant for details
- Review submitted answers
Lessons System
Architecture
Every lesson consists of:
- YAML Configuration - Structure, questions, scoring
- JavaScript Module - Validation, interactive data
- Database Entry - Metadata, catalog reference
Lesson Flow
Load Config → Initialize Module → Render Steps → Validate Answers → Calculate Score
Step Types
1. Content Step
- id: "intro"
type: "content"
title: "Introduction"
content: "Educational content..."
2. Question Step
- id: "question-1"
type: "question"
questionType: "single_choice|multiple_choice|free_text"
question: "Question text?"
options: [...]
maxPoints: 25
3. Interactive Step
- id: "demo"
type: "interactive"
title: "Interactive Demo"
interactiveComponent: "ComponentName"
content: "Instructions..."
Available Lessons
| Lesson | Key | Difficulty | Duration | Interactive |
|---|---|---|---|---|
| Phishing Email Detection | phishing-email-basics |
Beginner | 15 min | No |
| SQL Injection Shop | sql-injection-shop |
Intermediate | 20 min | Yes |
| Browser-in-the-Browser | browser-in-browser-attack |
Advanced | 25 min | Yes |
Detailed Documentation:
API Reference
Base URL
http://localhost:3000/api
Authentication
Participant:
- Header:
Authorization: Bearer <session_token> - Token obtained on event join
Admin:
- Header:
Authorization: Bearer <jwt_token> - Token obtained on login
Participant Endpoints
POST /participant/join
Body: { pseudonym, eventId }
→ { sessionToken, participant, event }
GET /participant/events
→ { events: [...] }
GET /participant/progress
Auth: Bearer session_token
→ { totalScore, completedLessons, ... }
Lesson Endpoints
GET /lesson/event/:eventId/lessons
Auth: Bearer session_token
→ { lessons: [...] }
GET /lesson/:eventLessonId
Auth: Bearer session_token
→ { title, steps, maxPoints, progress }
POST /lesson/:eventLessonId/start
Auth: Bearer session_token
→ { progressId, status }
POST /lesson/:eventLessonId/answer
Auth: Bearer session_token
Body: { questionId, answer }
→ { isCorrect, pointsAwarded, totalScore }
POST /lesson/:eventLessonId/complete
Auth: Bearer session_token
→ { completedAt, finalScore }
POST /lesson/:eventLessonId/action/:action
Auth: Bearer session_token
Body: { ...actionData }
→ { result }
Admin Endpoints
POST /admin/login
Body: { username, password }
→ { token, admin }
GET /admin/events
Auth: Bearer admin_token
→ { events: [...] }
POST /admin/events
Auth: Bearer admin_token
Body: { name, description, startDate, endDate }
→ { event }
GET /admin/events/:eventId/participants
Auth: Bearer admin_token
→ { participants: [...] }
GET /admin/lessons
Auth: Bearer admin_token
→ { lessons: [...] }
POST /admin/events/:eventId/lessons
Auth: Bearer admin_token
Body: { lessonId, orderIndex, maxPoints, weight }
→ { eventLesson }
Error Responses
{
"success": false,
"error": {
"message": "Error description",
"statusCode": 400
}
}
Database Schema
Core Tables
events
id, name, description, start_date, end_date, is_active,
created_at, updated_at
participants
id, pseudonym, event_id, session_token,
created_at, last_active
UNIQUE(pseudonym, event_id)
lessons
id, lesson_key, title, description,
module_path, config_path, difficulty_level, estimated_duration,
created_at, updated_at
event_lessons
id, event_id, lesson_id, order_index, max_points, weight,
is_required, unlock_after_lesson_id,
created_at, updated_at
UNIQUE(event_id, order_index)
lesson_progress
id, participant_id, event_lesson_id, status,
started_at, completed_at, score, attempts, current_step
lesson_answers
id, lesson_progress_id, question_key, answer_data (JSONB),
is_correct, points_awarded, feedback, submitted_at
admin_users
id, username, password_hash, created_at, updated_at
Relationships
events (1) → (*) event_lessons → (*) lesson_progress
events (1) → (*) participants → (*) lesson_progress
lessons (1) → (*) event_lessons
lesson_progress (1) → (*) lesson_answers
Indexes
participants(session_token)- Session lookupevent_lessons(event_id, order_index)- Lesson orderinglesson_progress(participant_id, event_lesson_id)- Progress trackinglesson_answers(lesson_progress_id)- Answer retrieval
Frontend Components
Page Structure
src/
├── pages/
│ ├── Hub.jsx # Join event
│ ├── EventLanding.jsx # Lesson list
│ ├── LessonView.jsx # Lesson player
│ ├── ParticipantProgress.jsx # Progress view
│ └── admin/
│ ├── AdminLogin.jsx
│ ├── AdminDashboard.jsx
│ ├── EventManagement.jsx
│ ├── LessonConfiguration.jsx
│ └── ParticipantData.jsx
├── components/
│ ├── common/ # Shared components
│ └── lessons/
│ └── InteractiveContent/
│ ├── SQLShopDemo.jsx
│ └── BitBDemo.jsx
├── contexts/
│ ├── ParticipantContext.jsx # Participant auth
│ └── AdminContext.jsx # Admin auth
├── services/
│ ├── api.service.js # API client
│ └── session.service.js # Session mgmt
└── routes/
└── AppRoutes.jsx # Route config
State Management
Context Providers:
ParticipantContext- Session, authentication, profileAdminContext- Admin auth, profile
Local State:
- Component-level useState for UI state
- No Redux/Zustand needed for current scale
Routing
/ → Hub (public)
/event → EventLanding (protected: participant)
/lesson/:id → LessonView (protected: participant)
/progress → ParticipantProgress (protected: participant)
/admin/login → AdminLogin (public)
/admin → AdminDashboard (protected: admin)
/admin/events → EventManagement (protected: admin)
/admin/events/:id/lessons → LessonConfiguration (protected: admin)
/admin/events/:id/participants → ParticipantData (protected: admin)
Interactive Components
SQLShopDemo:
- Fake e-commerce search interface
- Executes vulnerable SQL queries
- Real-time injection detection
- Safe vs vulnerable comparison
BitBDemo:
- Fake OAuth popup simulator
- Drag-test demonstration
- Right-click inspection
- Educational feedback system
Deployment
Environment Variables
# Database
DB_HOST=database
DB_PORT=5432
DB_NAME=lernplattform_db
DB_USER=lernplattform_user
DB_PASSWORD=your_secure_password
# Backend
NODE_ENV=production
PORT=3000
JWT_SECRET=your_jwt_secret_key
SESSION_SECRET=your_session_secret
# Admin
ADMIN_PASSWORD=your_admin_password
Docker Compose Commands
# Start all services
docker-compose up -d
# Stop all services
docker-compose down
# View logs
docker-compose logs -f [service]
# Rebuild specific service
docker-compose up -d --build [service]
# Check status
docker-compose ps
# Execute command in container
docker exec [container] [command]
Health Checks
Backend Health:
curl http://localhost:3000/health
Expected response:
{
"status": "healthy",
"timestamp": "2026-01-12T...",
"environment": "production",
"database": "connected"
}
Container Status:
docker-compose ps
# All should show "Up" and "healthy"
Backup & Restore
Backup Database:
docker exec lernplattform_db pg_dump -U lernplattform_user lernplattform_db > backup.sql
Restore Database:
cat backup.sql | docker exec -i lernplattform_db psql -U lernplattform_user lernplattform_db
Production Considerations
- Change Default Passwords in
.env - Enable HTTPS with reverse proxy (nginx/traefik)
- Set Up Regular Backups of database
- Configure CORS for production domain
- Enable Rate Limiting on API endpoints
- Set Up Monitoring (logs, metrics)
- Configure Log Rotation
- Use Strong JWT/Session Secrets
Development Guide
Local Development Setup
-
Install Dependencies:
cd backend && npm install cd ../frontend && npm install -
Run Without Docker:
# Terminal 1: Database docker run -p 5432:5432 -e POSTGRES_PASSWORD=pass postgres:15-alpine # Terminal 2: Backend cd backend && npm run dev # Terminal 3: Frontend cd frontend && npm run dev -
Access Development Server:
- Frontend: http://localhost:5173
- Backend: http://localhost:3000
Adding a New Lesson
Step-by-Step:
-
Create YAML config:
nano backend/lessons/configs/my-lesson.yaml -
Create module directory:
mkdir backend/lessons/modules/my-lesson nano backend/lessons/modules/my-lesson/index.js -
Extend base class:
const LessonModule = require('../base/LessonModule'); class MyLesson extends LessonModule { constructor(config) { super(config); } } module.exports = MyLesson; -
Seed to database:
# Add to seed script docker exec lernplattform_backend node seed-lessons.js -
(Optional) Create interactive component:
nano frontend/src/components/lessons/InteractiveContent/MyComponent.jsx -
Register in LessonView.jsx
-
Test thoroughly
Code Style
Backend:
- Use async/await (not callbacks)
- Validate inputs with ApiError
- Use prepared statements for SQL
- Handle errors in asyncHandler
- Comment complex logic
Frontend:
- Functional components + hooks
- PropTypes for type checking (optional)
- CSS-in-JS for styling
- Destructure props
- Keep components small
Testing
Manual Testing Checklist:
- Can join event
- Lessons appear correctly
- Questions validate properly
- Scoring calculates correctly
- Progress saves
- Admin can assign lessons
- Interactive components work
- Session persists
API Testing:
# Health check
curl http://localhost:3000/health
# Get events (as participant)
curl http://localhost:3000/api/participant/events
Debugging
Backend Logs:
docker logs -f lernplattform_backend
Frontend Console:
- Open browser DevTools (F12)
- Check Console tab for errors
- Check Network tab for API calls
Database Query:
docker exec -it lernplattform_db psql -U lernplattform_user lernplattform_db
\dt -- List tables
SELECT * FROM lessons;
Troubleshooting
Common Issues
1. Port already in use
# Find process using port
lsof -i :80 # or 3000, 5432
# Kill process or change port in docker-compose.yml
2. Database connection failed
# Check database is running
docker-compose ps database
# Check logs
docker logs lernplattform_db
# Verify credentials in .env
3. Frontend shows blank page
# Check frontend logs
docker logs lernplattform_frontend
# Rebuild frontend
docker-compose up -d --build frontend
# Check browser console
4. Admin login fails
# Verify password hash in database
docker exec lernplattform_db psql -U lernplattform_user lernplattform_db -c "SELECT username, password_hash FROM admin_users;"
# Regenerate hash if needed
5. Lesson won't assign
# Check backend logs for constraint errors
docker logs lernplattform_backend
# Verify lesson exists
docker exec lernplattform_db psql -U lernplattform_user lernplattform_db -c "SELECT * FROM lessons;"
# Check for duplicate order_index (fixed in latest version)
Security Notes
Authentication
- Participants: UUID session tokens (stateless)
- Admins: JWT tokens with bcrypt password hashing
- No password recovery (admin must reset manually)
Data Protection
- No PII collected from participants (pseudonyms only)
- Session tokens in localStorage (XSS risk mitigated)
- SQL injection prevented (parameterized queries)
- Input validation on frontend and backend
Production Security
- Change all default passwords
- Use strong JWT secrets
- Enable HTTPS
- Configure CORS properly
- Implement rate limiting
- Regular security updates
- Monitor logs for attacks
Performance
Current Scale
- Handles ~100 concurrent users
- Database pool: 20 connections
- Frontend: Static files, fast load
Optimization Options
- Add Redis for session caching
- Enable frontend caching (service worker)
- CDN for static assets
- Database read replicas
- Horizontal scaling (multiple backend instances)
Future Enhancements
Planned Features
- More lessons (XSS, CSRF, password security)
- Email notifications
- Bulk participant import
- Certificate generation
- Advanced analytics dashboard
- Lesson scheduling
- Mobile responsive improvements
- Dark mode
Extension Points
- Custom lesson modules
- Additional interactive components
- Third-party integrations (LDAP, SSO)
- LMS integration (SCORM)
- API webhooks
Support & Resources
Documentation
- This File: Platform overview
- LESSONS_DOCUMENTATION.md: Comprehensive lesson guide
- LESSON_QUICK_REFERENCE.md: Quick reference for instructors
- lessons/README.md: Lesson development guide
Useful Commands
# View all containers
docker ps -a
# Clean up
docker-compose down -v # Remove volumes
docker system prune # Clean unused resources
# Database access
docker exec -it lernplattform_db psql -U lernplattform_user lernplattform_db
# Backend shell
docker exec -it lernplattform_backend sh
# Tail logs
docker-compose logs -f --tail=100
Version: 1.0.0 Last Updated: 2026-01-12 License: MIT (or your license) Repository: https://github.com/your-org/lernplattform (if applicable)