I built a quiz engine from an XLSX in one afternoon
A client needed a timed quiz platform with anti-cheat. They handed me an XLSX of questions. I handed them a live platform in a day.
infoThe Situation
A client needed to run timed quizzes for their candidates — with anti-cheat enforcement and automated result delivery. They had the questions ready in an XLSX. Everything else was a blank page. The timeline was tight: one afternoon to have something demonstrable.
outputWhat Came Out
A live branded quiz platform on a custom domain. Anti-cheat enforcement. Automated result delivery. All from an XLSX.
routeHow It Went Down
Read the client's XLSX file containing all quiz questions
Extracted questions, options, correct answers, timing data — structured and ready
Prompted to transform the XLSX data into DynamoDB-compatible JSON records
Clean JSON matching DynamoDB schema — no manual reformatting needed
Set up hosting, wired up the frontend quiz interface
Live URL with custom domain via Route53
Populated questions via script generated in step 2
Full question bank live in the database, ready to serve
Built anti-cheat: window blur / alt-tab detection → strike system
1 strike = warning banner. 3 strikes = disqualified, quiz auto-submitted
Wired up result email on quiz completion
Candidates receive their results within seconds of submitting
I didn't rebuild the data manually. I didn't manually key in 60 questions into a web form. I prompt-engineered the boring part away and focused on the architecture that actually mattered.
starThe Key Move
Gemini didn't just read the XLSX — it restructured it to match DynamoDB schema in one shot. That was the whole hack. Without that step, I'd have spent the whole afternoon manually reformatting 60 questions.
thumb_upWhat Made It Satisfying
“The Gemini transformation step was the key. What would have been hours of manual data entry became a 5-minute prompt. The rest was standard AWS plumbing.”
schoolLessons Learned
warningWhat Was Hard
Getting the anti-cheat UX right. A blur event can fire innocuously — when a user switches to another tab to check something. The strike threshold and warning copy had to feel fair, not punitive.
redoWhat I'd Do Differently
I'd add a review screen before final submission so candidates can double-check answers. The anti-cheat was non-negotiable for the client, but a review step would make the experience less stressful.
codeAnti-cheat detection (the key UX piece)
// Detect tab switch / window blur = strike
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
addStrike();
}
});
window.addEventListener('blur', () => {
addStrike();
});
function addStrike() {
strikes++;
if (strikes >= 3) {
submitQuiz(true); // force disqualified
showDisqualifiedScreen();
} else {
showWarning(`Strike ${strikes}/3`);
}
}