ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
Exam-prep platform in production: timed mocks, difficulty-weighted scoring and PDF-to-question tools. Next.js, TypeScript, PostgreSQL.
翻译准备中
正在加载完整 README。
查看完整 README ↗An exam-prep platform for the NUET, the entrance test for Nazarbayev University, used by real students at a test-prep academy in Kazakhstan. Students take timed mock exams and homework. Teachers build tests from PDFs, follow progress, and run paid exams with difficulty-weighted scoring.
In production: 43 student accounts, 94 submitted attempts, 3,691 saved answers and 670 questions, from the first submission on 24 October to 8 November 2026.
Stack: TypeScript, Next.js 16 (App Router, Server Actions), React 19, Prisma, PostgreSQL (Neon), Vercel, Vitest, GitHub Actions.
| Taking a mock | Reviewing the result |
|---|---|
| Student dashboard | Teacher's group results |
|---|---|
Screenshots use invented students and sample questions. The interface is in Russian; the exams are in English.
For students
For teachers
Paid exams
flowchart LR
B[Browser] -->|Server Actions| N[Next.js on Vercel]
B -->|images, checked per request| N
B -. "pdf.js cuts PDFs locally" .-> B
N -->|Prisma, pooled connection| P[(Neon Postgres)]
The server renders pages and does all checking; a client component runs the exam screen. Question pictures live in Postgres, so a backup holds everything in one place.
Answers never reach the browser early. toPlayerQuestion builds what the exam screen receives field by field, so a new database column can't leak by accident. Pictures of a paid exam are checked per request against the student's own attempt (route).
Difficulty-weighted scoring that can't change published results. A question's weight is 1 + bonus × (1 − p), where p is the share of students who solved it. Because scores depend on everyone's answers, each saved result records the bonus it was computed with, and recalculating reuses it (examScoring.ts). I tuned the bonus from 2 down to 0.5 after real results showed it pushed students who solved mostly easy questions too far below their share of correct answers.
Section timers with no background job. An attempt stores only its current stage and when that stage ends. stageAt works out the rest from the clock, so nothing has to run when a timer expires, and a server restart loses nothing. The server refuses answers for a section that has closed.
Built for a whole class submitting at once. Pictures are cached in memory with a size cap, while access is still checked on every request. Exams never change once started, because questions lock when the first student begins.
Rate limiting in the database. Serverless instances share no memory, so failed logins are counted in Postgres under hashed keys. One counter is per login and address, so nobody can lock a student out of an exam from elsewhere. A larger one is per address, because a whole school can share one.
PDF cutting in two languages. The question cutter exists as a Python script for bulk imports and a browser port for teachers. Both read text positions and drawn shapes from the page to find where each question starts and ends.
httpOnly, and only a hash of each token is stored.permissions.ts), so a crafted request gets nothing.npm test
Vitest covers scoring, section timing, spreadsheet import, permissions, password handling, rate limiting and what the browser receives. CI runs the tests, type check and production build on every push. There are no browser tests in this repo yet.
You need Node 24 and an empty PostgreSQL database.
npm install
cp .env.example .env # point both URLs at your empty database
npm run db:push
ALLOW_DEMO_SEED=yes-wipe-everything npm run demo:seed
npm run dev
Open http://localhost:3000 and log in as [email protected] or [email protected] with the password demo1234. These accounts exist only in the demo data.
The seed deletes everything in the database it connects to, which is why it needs that variable.
The app runs from a private repository, because it also holds exam papers and answer keys. This public copy has the same code and commit history with that material removed, so a few commit messages mention content that isn't here. Features added to the private repo after 8 November 2026 may not be here yet.
I built this with Claude Code as an AI pair programmer, as the commit trailers show. Product decisions, testing with real students and running it in production are mine.
Built by Magzhan Altynsarin.