← Portfolio CodeMas — Architecture
ACTORS API LAYER EXECUTION 👨‍💻 Student Browser 👨‍🏫 Trainer Dashboard Django REST API DRF · Simple JWT · Gunicorn · AWS Lambda POST /submit → attempt check (SELECT FOR UPDATE) → INSERT submission → 201 AWS Lambda · Gunicorn AWS SQS execute_submission queue FIFO · per-exam · Celery BRPOP Docker Sandbox Isolated execution CPU · mem · time limits · cgroups PostgreSQL Submissions · Results Attempts · Exam state SSE Stream EventSource API one connection per student POST /submit exam CRUD 201 + SSE open LPUSH check + INSERT BRPOP write result Redis pub/sub result pushed to browser
TRIGGERS AI AGENTS SERVICES Trainer: Exam Create topic · difficulty · count Submission Result pass or fail scored Submit Failed test cases didn't pass Exam Closed is_active → False Similarity Flagged cosine > 0.80 Exam Generator Questions + test cases HITL: review before persist human-in-the-loop gate Rubric Scorer 4 dimensions · 0–2 each per-dim justification async after result Hint Agent Socratic nudge only concept hint · no answer on 3rd failed attempt Dashboard Agent Cohort narrative per-student summaries polls every 10s Plagiarism Engine Behavioural + TF-IDF 5% → 95% · 19× lift GPT evidence brief GPT-4o-mini OpenAI API · async calls all agents share this endpoint PostgreSQL ExamDraft · RubricScore AIHint · PlagiarismFlag shared endpoint scores · hints · flags
Key Design Decisions
Core Architecture
Lambda + SQS decoupling
Code submission returns 201 immediately and opens an SSE stream. Execution is queued to SQS — deadline bursts queue up without stalling the API. The Lambda worker dequeues and runs the Docker sandbox independently.
AWS LambdaSQS FIFOSSE
Plagiarism Detection
Reframing the problem
"Are two submissions similar?" → "Did this student write this?" Layer 1 scores behavioural signals (paste ratio, speed vs difficulty, tab switches) at exam close. Layer 2 runs TF-IDF cosine only on suspects — O(K×N) not O(N²).
TF-IDFBehavioural signalspre_save signal
AI Agent Design
Async, never on delivery path
All 5 agents are triggered by events but execute fully async — none sit between submission and result. Rubric scoring, hints, and narratives appear after the result is already delivered. Zero latency added to the student experience.
Async queueGPT-4o-miniIdempotent
Code Execution Safety
Docker sandbox isolation
Every submission runs in an isolated Docker container with strict CPU, memory, and time limits enforced by cgroups. No student code can affect another execution or the host. Container killed after the time limit regardless of state.
Dockercgroupstime-limit kill
Concurrency Safety
Attempt gating with row lock
Before accepting a submission, the API checks attempt count using SELECT FOR UPDATE. Prevents race conditions when two tab submissions arrive within milliseconds — common at exam end when every student submits at the same deadline.
PostgreSQLSELECT FOR UPDATE
Real-time Delivery
SSE over WebSocket
Code execution results are unidirectional — server pushes once. SSE chosen over WebSockets for native browser reconnection, HTTP/1.1 proxy compatibility, and simpler Lambda scaling. Redis pub/sub bridges the worker result to the SSE endpoint.
SSEEventSource APIRedis pub/sub