Sokrates is a learning platform with a FastAPI backend and a Next.js frontend.
- Frontend (Next.js 14): Browser UI, session handling (NextAuth), and real-time notifications via WebSocket.
- Backend (FastAPI): REST API, auth, business logic, DB access, and WebSocket notification service.
- Database: SQL database via SQLModel.
- Redis (optional): Used for caching and cross-instance notification fanout.
- WebSocket endpoint:
/api/v1/notifications/ws - Auth: JWT access token (query param
token, Authorization header, or cookie). - Topics: MQTT-style topics with
+(single level) and#(multi-level) wildcards. - Flow:
- Client connects with access token.
- Backend validates token and associates socket with user + topic subscriptions.
- Messages are pushed to connected users; Redis pubsub fans out across instances if configured.
- Client displays notifications as toasts and auto-reconnects on drop.
- Notification payloads include a
topicfield (defaultbroadcast). - Admin broadcast endpoint accepts a
topicfield to target subscribers. - The frontend subscribes to topics on connect (see
WebSocketNotifications.tsx). - Subscription logic is handled on the frontend; the backend only filters based on topic matches.
- To move subscription logic to the backend, ignore client subscription messages and set server-side defaults per user/session.
- Default frontend subscriptions:
broadcastanduser/<id>. - You can pass initial topics via query param:
?topics=broadcast,user/123. - You can update subscriptions after connect by sending a JSON message:
{"type": "subscribe", "topics": ["org/123"]}{"type": "unsubscribe", "topics": ["org/123"]}{"type": "set_subscriptions", "topics": ["broadcast", "user/123"]}
- The backend emits tutor-scoped notifications when a student starts an activity and when a student completes an activity for the first time.
- These notifications are room-aware and are sent once per student room membership at the time of the state change.
- If a student is in two rooms at the same time, two notifications are emitted. This is intentional for now so the frontend can later throttle or aggregate without losing room context.
- Current topic shapes:
user/<tutor_id>/courses/<course_uuid>/students/<student_uuid>/rooms/<room_uuid>/activity-starteduser/<tutor_id>/courses/<course_uuid>/students/<student_uuid>/rooms/<room_uuid>/activity-completed
- Notification payloads include
room_idandroom_uuidindata. room_uuidis currently synthetic and derived from the numeric room id ascourse_room_<room_id>, becausecourse_roomdoes not yet have a persisted UUID column.- The backend now emits these notifications, but the frontend still needs to subscribe to the corresponding topic subtree before tutors will see them.
- Implementation lives in:
- Backend notifier:
apps/api/src/services/notifications/service.py - Emission hook:
apps/api/src/services/trail/trail.py - Future tutor subscription handler:
apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/tutor/page.tsx
- Backend notifier:
apps/api/app.py: App entry, middleware, static mounts.apps/api/src/router.py: API router wiring.apps/api/src/core/events/events.py: Startup/shutdown hooks.apps/api/src/security/auth.py: JWT auth helpers.apps/api/src/security/security.py: JWT secrets/algorithms.apps/api/src/routers/notifications.py: WebSocket notifications endpoint.apps/api/src/services/notifications/manager.py: Connection manager + keepalive pings.apps/api/src/services/notifications/broker.py: Redis pubsub fanout.apps/api/src/services/notifications/models.py: Notification payload schema.apps/api/src/services/notifications/service.py: Public notification helpers (notify_user, etc.).
apps/web/app/layout.tsx: Global providers + Toaster + WebSocket client.apps/web/components/Notifications/WebSocketNotifications.tsx: WebSocket client, reconnection, toast rendering.apps/web/services/config/config.ts: API/WS URL helpers.apps/web/components/ui/toaster.tsx: Toast container.apps/web/hooks/use-toast.ts: Toast API.
apps/api/config/config.py: Backend config loading.apps/api/pyproject.toml: Backend deps.apps/web/package.json: Frontend deps.dev.env: Local environment template.
- Run the full backend test suite:
cd apps/api
PYTHONPATH=. poetry run pytest src/tests- Run a single backend test file:
cd apps/api
PYTHONPATH=. poetry run pytest src/tests/test_trail_tutor_verification.py- Run lint checks after larger backend/frontend changes:
make lint- Email: admin@school.dev
- Password: admin