{
// ── Added by storeEvent ─────────────────────────────────
"eventId": "550e8400-e29b-41d4-a716-446655440000",
"storedAt": "2026-06-09T10:31:00.000Z",
// ── Event type ──────────────────────────────────────────
"event": "assessment.completed",
// or "assessment.disqualified" (if session was disqualified)
// ── Assessment identity ──────────────────────────────────
"assessmentId": "asmnt_72b47a64306f",
"assessmentName": "Full Stack Developer Assessment",
"jobTitle": "Senior Software Engineer",
// ── Candidate ──────────────────────────────────────────────
"candidateId": "cand_abc123",
"candidateName": "Priya Sharma",
"candidateEmail": "priya@example.com",
// ── Skills ──────────────────────────────────────────────
"skills": ["JavaScript", "React", "Node.js"],
// ── Result ──────────────────────────────────────────────
"status": "submitted",
"score": 78,
"totalMarks": 100,
"passMarks": 65,
"passed": true,
"submittedAt": "2026-06-09T10:30:00.000Z",
// durationMinutes: Math.ceil((submittedAt - startTime) / 60000), minimum 1
// null only if startTime or submittedAt is missing
"durationMinutes": 45,
// ── AI feedback ──────────────────────────────────────────
// Generated async AFTER submit — will be null when first stored.
// Your poller may see null here even for a successful session.
"aiFeedback": null,
// ── Report link ──────────────────────────────────────────
// Built from: env.REPORT_BASE_URL + /assessment/{assessmentId}/report/{candidateId}
"reportUrl": "https://your-frontend.com/assessment/asmnt_72b47a64306f/report/cand_abc123",
// ── Per-question breakdown ────────────────────────────────
"questionAnswers": [
{
"questionId": "q_001",
"type": "MCQ",
"question": "What is the time complexity of binary search?",
"options": ["O(n)", "O(log n)", "O(n²)", "O(1)"],
"correctAnswer": "O(log n)",
"marks": 5,
"difficulty": "Medium",
"candidateAnswer": "O(log n)",
"isCorrect": true,
"marksAwarded": 5,
"timeSpent": 45,
"order": 1
},
{
"questionId": "q_002",
"type": "Coding",
"question": "Reverse a linked list",
"options": [],
"correctAnswer": "",
"marks": 20,
"difficulty": "Medium",
"candidateAnswer": "function reverseList(head) { ... }",
"isCorrect": null,
"marksAwarded": 20,
"timeSpent": 380,
"order": 2
}
],
// ── Identity verification ─────────────────────────────────
"verification": {
// GCP signed URL to selfie photo — null if verification was skipped
"imageUrl": "https://storage.googleapis.com/assessmentmodule/...?X-Goog-Signature=..."
},
// ── Proctoring ────────────────────────────────────────────
"proctoring": {
"score": 88,
"violationCount": 2,
"tabSwitchCount": 1,
"fullscreenExitCount": 0,
"noFaceCount": 1,
"multipleFaceCount": 0,
"lookawayCount": 0,
"externalObjectCount": 0,
// Last 30 violations, newest first
"recentViolations": [
{
"type": "TAB_SWITCH",
"severity": "low",
"timestamp": "2026-06-09T10:05:00.000Z"
}
]
},
// ── Recording ─────────────────────────────────────────────
"recording": {
// not_started | in_progress | processing | ready | failed
"status": "processing",
// GCP signed URL — null while status is not "ready"
"url": null
}
}