You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Routes are wired in main.go and stub handlers exist in internal/handlers/invites.go and internal/handlers/attempts.go, but every handler returns placeholder JSON. All business logic needs to be implemented.
Already done
Route registration in main.go for all invite/attempt endpoints
Create InviteService in internal/core/services/ with deps on InviteRepo, AttemptRepo, AssessmentRepo
Create AttemptService in internal/core/services/ with deps on AttemptRepo, AnswerRepo, QuestionRepo, SubmissionRepo
Invite handlers (internal/handlers/invites.go)
CreateInvite — parse assessment :id + JSON body (candidate_email), generate random invite_token (uuid or crypto/rand hex), insert via InviteRepo with status=pending and expires_at, return token + copyable link
ValidateInvite — look up by :token, check not expired and status is pending/started, return assessment metadata (title, description, duration, question count). Return 404/410 for invalid/expired tokens
StartAttempt — validate invite is pending, create AttemptRepo row with started_at=now, update invite status to "started", return attempt_id. Reject if already started (one-attempt rule)
Attempt handlers (internal/handlers/attempts.go)
ListAttempts — query by assessmentId query param (join through invites), return attempt list with email, status, total_score, timestamps
GetAttempt — return attempt details including remaining time (duration_minutes - elapsed since started_at)
GetAttemptQuestions — return all questions for this attempt's assessment (join invite -> assessment_template)
SaveAnswers — parse JSON body (question_id, response), upsert answer row via AnswerRepo. Validate attempt is in_progress and timer hasn't expired
SubmitAttempt — set status to submitted, set completed_at, auto-score MCQ/short-answer (compare response to correct_answer), sum total_score, update invite status to completed. Reject if already submitted or timer expired
DI wiring in main.go
Instantiate InviteService and AttemptService with repos
Pass services into handlers (same pattern as assessment handlers: SetXService() or handler struct)
Business rules
Invite can only be started once
Answers only saved while attempt is in_progress
Submit fails if attempt already submitted or timer expired
MCQ scoring: compare selected option(s) to correct_answer (all-or-nothing)
Invite & Attempt Logic — Backend
Routes are wired in
main.goand stub handlers exist ininternal/handlers/invites.goandinternal/handlers/attempts.go, but every handler returns placeholder JSON. All business logic needs to be implemented.Already done
main.gofor all invite/attempt endpointsRemaining work
Service layer
InviteServiceininternal/core/services/with deps on InviteRepo, AttemptRepo, AssessmentRepoAttemptServiceininternal/core/services/with deps on AttemptRepo, AnswerRepo, QuestionRepo, SubmissionRepoInvite handlers (
internal/handlers/invites.go)CreateInvite— parse assessment:id+ JSON body (candidate_email), generate random invite_token (uuid or crypto/rand hex), insert via InviteRepo with status=pending and expires_at, return token + copyable linkListInvites— call InviteRepo.ListByAssessmentID (filter byassessmentIdquery param), return arrayValidateInvite— look up by:token, check not expired and status is pending/started, return assessment metadata (title, description, duration, question count). Return 404/410 for invalid/expired tokensStartAttempt— validate invite is pending, create AttemptRepo row with started_at=now, update invite status to "started", return attempt_id. Reject if already started (one-attempt rule)Attempt handlers (
internal/handlers/attempts.go)ListAttempts— query byassessmentIdquery param (join through invites), return attempt list with email, status, total_score, timestampsGetAttempt— return attempt details including remaining time (duration_minutes - elapsed since started_at)GetAttemptQuestions— return all questions for this attempt's assessment (join invite -> assessment_template)SaveAnswers— parse JSON body (question_id, response), upsert answer row via AnswerRepo. Validate attempt is in_progress and timer hasn't expiredSubmitAttempt— set status to submitted, set completed_at, auto-score MCQ/short-answer (compare response to correct_answer), sum total_score, update invite status to completed. Reject if already submitted or timer expiredDI wiring in
main.goSetXService()or handler struct)Business rules
Note: this requires the completion of #17 and #18