Unitru Academic is organized as a monorepo containing two completely independent services — a Next.js 16 frontend and a Python 3.12 / FastAPI backend — that communicate exclusively over a single persistent WebSocket connection. There are no REST endpoints exposed for data retrieval; the only HTTP route in the backend isDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Andr21Da16/UNITRU-ACADEMIC/llms.txt
Use this file to discover all available pages before exploring further.
/health, used for infrastructure health checks. Every piece of academic data travels over the WebSocket in real time, from the first progress event to the final dashboard_ready payload.
System Diagram
Communication Contract
The entire data exchange is event-driven over a single/ws WebSocket connection:
Connect and send credentials
The frontend opens a WebSocket to
/ws and immediately sends a JSON message with the student’s username and password.Receive progress events
While the backend navigates the SUV, it emits a stream of progress events. Each message follows the envelope:The frontend displays these in the
AuthenticationProgress component as labelled steps.Receive the dashboard payload
Once all data has been extracted, the backend sends a single terminal event:The frontend transitions directly to the dashboard view — no additional requests are needed.
All backend errors (authentication failure, navigation error, extraction error, SUV timeout) are also delivered over the WebSocket as
{ "event": "error", "data": { "message": "...", "category": "..." } }, never as HTTP error codes.Security Model
Credential security is achieved through architecture, not encryption at rest — because credentials are never stored at rest.Credentials live in memory only
The
username and password fields exist only inside the active WebSocket handler coroutine. They are passed directly to the AuthenticateStudentUseCase, typed into the Playwright page, and then go out of scope. No database write, no log line, no session store.Browser session destroyed on close
SessionManager ties each BrowserSession to a WebSocket connection. When the socket closes — whether normally or due to an error — the finally block calls destroy_session, which closes the Playwright resources in strict order: Page → BrowserContext → Browser → Playwright.No persistence beyond the session
There is no database, no Redis session store, and no cookie jar persisted between requests. Each new login creates a fresh Chromium context with no prior state.
Anti-detection hardening
The Playwright context is created with a real Chrome User-Agent and
navigator.webdriver hidden via an init script, so the SUV portal cannot distinguish the automated browser from a real one.Service Separation
The two services have a strict division of responsibility:| Service | Responsibility |
|---|---|
| Backend (FastAPI) | All scraping logic, CAPTCHA solving, data extraction, domain modeling, analytics computation, schedule optimization |
| Frontend (Next.js) | Purely presentational — renders the data received from the backend, manages UI state transitions, displays real-time progress |
Architecture Styles
- Backend applies Clean Architecture + Hexagonal Architecture: infrastructure adapters implement domain ports, and use cases orchestrate domain services. Dependencies always point inward toward the domain.
- Frontend applies Feature-Based Architecture: one folder per product feature, each owning its own components and types, with a single shared
infrastructure/websocket/integration point.
Backend Architecture
Deep dive into the Python Clean + Hexagonal layers, use cases, ports, Playwright adapters, OCR pipeline, and dependency wiring.
Frontend Architecture
Feature directory structure, WebSocket client integration, authentication flow, key types, and component organization.