Project Info
Inspiration
We are students ourselves, and we built ExamTwin because we were looking for a tool like this and could not find one. Study materials are usually scattered across PDFs, notes, old exams, university platforms, group chats, and shared folders. Existing tools can generate quizzes or flashcards, but they rarely understand the real structure of a specific exam, track performance across multiple attempts, or help students prepare together. We wanted one place where students could upload their real course materials, recreate the format of their exam, generate realistic mock exams, understand their weak areas, and improve through repeated practice.
What it does
ExamTwin is an adaptive exam preparation platform that turns real study materials into personalized mock exams. Students can: create a study space for a course or exam; upload notes, past exams, rubrics, syllabi, and other learning materials; generate realistic mock exams based on those materials; complete exams directly inside the platform; receive structured feedback and performance analytics; identify recurring mistakes and weak skills; generate follow-up exams focused on those weaknesses; track progress across multiple attempts; share study spaces with classmates; create groups and prepare together; publish reusable study spaces in a community library. Unlike a generic quiz generator, ExamTwin focuses on the full preparation cycle: materials → exam structure → mock exam → evaluation → analytics → adaptive next exam
How we built it
We built ExamTwin as a modular full-stack platform. The frontend is built with Next.js, React, and TypeScript. It provides the study dashboard, material upload flows, mock exam interface, analytics views, shared study spaces, and community features. The backend is built with FastAPI, Pydantic, SQLAlchemy, and PostgreSQL. It manages authentication, users, study spaces, uploaded materials, exams, attempts, responses, analytics, and collaboration features. The AI layer uses OpenAI models to: analyze uploaded study materials; extract topics, skills, question types, and exam structure; generate grounded mock exams; evaluate open-ended responses; explain mistakes; map answers to skills; create personalized follow-up exams. The analytics layer uses Python and pandas to calculate scores, skill-level performance, trends, consistency, confidence, recurring mistakes, and readiness estimates. We designed the system to remain flexible across very different subjects, from IELTS and university entrance exams to mathematics, law, medicine, and quantum physics. Codex was used throughout the development process for implementation, refactoring, debugging, architecture decisions, API design, and testing.
Challenges we ran into
The hardest challenge was making the system flexible enough to support very different kinds of exams. An IELTS writing task, a multiple-choice biology test, and a quantum physics problem set cannot be evaluated using the same fixed structure. We therefore avoided hardcoding the platform around one subject and instead created reusable abstractions for: exam sections; question types; skills; scoring rules; rubrics; difficulty levels; answer formats. Another challenge was keeping generated exams grounded in the uploaded materials. The system needs to create new questions without inventing unsupported facts or ignoring the original exam format. We also had to separate AI-generated insights from deterministic analytics. Language models are useful for evaluation and explanation, but scores, trends, attempt histories, and statistical metrics must remain structured, reproducible, and transparent. Finally, we had to control the scope. ExamTwin combines AI generation, analytics, collaboration, community features, and gamification, which made it very easy to attempt building an entire university ecosystem in one week. Humanity survives scope creep once again.
Accomplishments we're proud of
We are proud that ExamTwin became more than a basic PDF-to-quiz generator. We built a complete preparation workflow where students can upload real materials, generate exams, complete them, receive feedback, understand their weak skills, and continue with personalized practice. We are especially proud of: the flexible exam model; adaptive mock exam generation; skill-level analytics across multiple attempts; support for both objective and open-ended questions; reusable study spaces; collaborative preparation; a clean and focused user experience; building a working product in a very short period of time. The project was created by students for a problem we experience personally, which helped us make product decisions based on real needs rather than imaginary user personas.
What we learned
We learned that generating questions is the easy part. Building a reliable learning system around those questions is much harder. A useful education product needs more than an AI prompt. It needs structured exam models, clear evaluation rules, historical data, confidence estimates, transparent analytics, and a feedback loop that actually changes what the student studies next. We also learned that educational analytics must be domain-independent. The platform cannot assume that every subject consists of vocabulary terms or multiple-choice questions. Most importantly, we learned that familiar ideas can become more valuable when they are combined around a clear user problem. ExamTwin uses known components such as document analysis, mock exams, progress tracking, and study communities, but connects them into one continuous exam preparation workflow.
What's next
Our next steps are to: improve exam blueprint extraction; support more document formats; add stronger rubric-based evaluation; introduce richer skill graphs; improve readiness prediction; add spaced repetition and personalized study plans; expand group challenges and gamification; build a larger community library of reusable courses and exams; allow teachers and institutions to create verified study spaces; add deeper analytics for long-term learning progress; expand support to professional certifications and standardized exams. Our long-term goal is to make ExamTwin a shared preparation layer for any exam: students should be able to find or create a study space, practice under realistic conditions, understand exactly where they are weak, and improve together.
ExamTwin
Build a faithful digital twin of a real exam, practise it under realistic conditions, and turn every attempt into a better next mock.
ExamTwin is an adaptive exam-preparation platform created for OpenAI Build Week. It helps students organise university exams, attach the material that defines each exam, describe its structure and rules, run a focused mock session, and retain results for future feedback and adaptation.
The product is deliberately exam-centred:
- a Subject is a lightweight category such as Quantum Physics;
- an Exam owns its context files, blueprint, scenario, timing, scoring rules, attempts, feedback and statistics;
- a Class shares either a whole Subject or selected Exams with a group;
- an Attempt is an archived mock run with answers, score, duration and feedback.
Current status
The repository contains a working, API-backed P0 product, the complete P1 artifact pipeline, and an opt-in P2 grounded-AI loop. Demo mode remains available for visual review, while normal mode persists the complete core flow in PostgreSQL.
| Area | Status |
|---|---|
| Authentication and profile | Implemented in the API and frontend flows |
| Subject CRUD | Implemented |
| Nested Exam CRUD | Implemented |
| Exam data, blueprint, scenario and rules editor | Persisted through the API with optimistic configuration versions |
| Exam Run simulation | Backend-generated mock, durable attempt, autosave, reload/resume and immutable submit |
| Personal statistics and analytics | analytics.v2, canonical observations, versioned snapshots, data-quality gates, trends, readiness and adaptive.v2 implemented |
| Library publishing and cloning | Implemented with safe public snapshots and independent private clones |
| Class CRUD, membership and progress | Implemented with owner-only aggregate analytics, small-group suppression, comparable exam scope and experiment events |
| PostgreSQL models and migrations | Implemented through D3, including observations, snapshots, taxonomy, shadow results and cohort events |
| Artifact ingestion and retrieval | Implemented: private upload, parsing, chunking, embeddings and owned-exam vector retrieval |
| Vertex AI generation and evaluation | Implemented with gemini-3.5-flash when APP_VERTEX_PROJECT is configured; deterministic fallback remains available |
| Background worker pipeline | Implemented with durable Dramatiq/Redis jobs and restart-safe retries |
The UI distinguishes the deterministic fallback from Vertex AI generation. AI questions are grounded in retrieved chunks, retain source citations, and use prior weak-topic evidence to adapt later mocks.
Product preview
All product images below were captured from the running local application in the native browser at a laptop/desktop responsive breakpoint. Each screenshot includes the complete page width; no interface sections are cropped or reconstructed.
Dashboard (updated local capture)
The home view keeps the next preparation action prominent and shows the student’s current exam context. This screenshot was freshly captured from the local demo at a wide desktop viewport.

Data-science analytics
The analytics views separate readiness from evidence confidence and make score movement inspectable over time.


Subjects
Subjects are intentionally simple categories. Exam-specific readiness, dates and content live on Exams instead.

Subject workspace
Each Subject exposes its nested Exams and Classes without becoming a second exam-detail surface.

Exams
The global Exams index provides a cross-subject view and the primary creation entry point.

Exam workspace
Exam Detail is the control centre for data sources, blueprint, scenario, rules and attempt history.

Five-step exam creation
The creation flow separates basics, data, blueprint, generation scenario/rules and final review.

Focused Exam Run
The simulation uses a distraction-free shell and prepares a mock from the configured exam structure.

Exam statistics
Statistics are scoped to an Exam and clearly label the confidence of insights while attempt coverage is still low.

Classes
Classes can be scoped to a complete Subject or a selected group of Exams.

Demo video
Watch the ExamTwin product walkthrough on YouTube: ExamTwin — OpenAI Build Week.
Why ExamTwin
Students usually prepare from fragmented notes, syllabi, rubrics, past papers and generic question banks. Conventional generators may cover the same topic, but they rarely reproduce the actual constraints that shape performance: section order, question types, point distribution, allowed materials, time pressure and grading rules.
ExamTwin treats those constraints as first-class data. Its target feedback loop is:
- Create a Subject category.
- Create an Exam inside that Subject.
- Add past papers, rubrics, notes, learning targets and other context.
- Review the extracted or manually entered blueprint.
- Configure scenario and rules such as timing, points, pass mark and penalties.
- Generate a grounded mock exam.
- Complete it in the focused Exam Run interface.
- Archive answers, result and feedback.
- Use evidence from previous attempts to produce a more useful next mock.
Domain model
User
└── Subject (category)
├── Exam
│ ├── Data sources / context files
│ ├── Blueprint sections
│ ├── Generation scenario
│ ├── Rules and grading notes
│ └── Attempts
│ ├── Answers
│ ├── Result
│ └── Feedback
└── Class
└── All subject exams or selected exams
This boundary prevents Subject pages from accumulating exam-only responsibilities and allows multiple finals, midterms, oral exams or certification attempts to coexist under one course category.
Architecture
Browser
│
├── Next.js 16 / React 19 frontend and BFF
│ ├── App Router pages
│ ├── API-backed product state (optional local demo mode)
│ ├── HTTP-only session cookies and authenticated API proxy
│ └── focused exam-session layout
│
└── FastAPI API
├── authentication and JWT lifecycle
├── ownership-protected CRUD and attempt lifecycle
├── SQLAlchemy async models
├── Alembic migrations
└── PostgreSQL / pgvector
files → object storage → worker → parsing/chunking → embeddings/retrieval
→ Vertex AI grounded generation → mock → evaluation → mastery
Technology stack
| Layer | Technology | Responsibility |
|---|---|---|
| Web | Next.js 16, React 19, TypeScript, Tailwind CSS 4 | Product interface and exam session |
| API | FastAPI, Pydantic, SQLAlchemy asyncio | Auth, ownership and domain APIs |
| Database | PostgreSQL 17 with pgvector | Relational records and future vector retrieval |
| Migrations | Alembic | Versioned database schema |
| Cache/jobs | Redis and Dramatiq worker | Durable artifact processing and retries |
| AI | Vertex AI / Google Gen AI SDK | Gemini 3.5 Flash generation, embeddings, evaluation and adaptation |
| Runtime | Docker Compose | Local PostgreSQL, Redis and API services |
Repository layout
.
├── backend/
│ ├── api/app/ # FastAPI routes, services, models and configuration
│ ├── api/migrations/ # Alembic migrations
│ ├── api/tests/ # Unit and PostgreSQL integration tests
│ ├── worker/ # Background-worker boundary
│ ├── compose.yaml
│ └── pyproject.toml
├── frontend/
│ ├── src/app/ # Next.js App Router routes and layouts
│ ├── src/components/ # Shared UI and product shell
│ ├── src/features/ # Auth, subjects, exams, classes and demo state
│ └── public/
├── materials/ # Product screenshots and submission assets
└── deep-research-report.md # Product research and rationale
Run locally
Prerequisites
- Node.js ^20.19.0 or >=22.12.0
- npm
- Python 3.11–3.13
- Docker with Docker Compose
Fastest path: frontend demo
The frontend can be explored without the API. Demo entities and attempts are stored in browser localStorage.
cd frontend
cp .env.example .env.local
npm install
npm run dev
Open http://localhost:3000. The example environment enables NEXT_PUBLIC_DEMO_MODE=true, so protected product pages are available for local review.
Full P0 product
From the repository root:
cd backend
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e '.[dev]'
cp .env.example .env
docker compose -f compose.yaml up -d
alembic upgrade head
uvicorn app.main:app --app-dir api --reload --port 8010
In a second terminal:
cd frontend
npm install
NEXT_PUBLIC_DEMO_MODE=false API_URL=http://127.0.0.1:8010/api/v1 npm run dev
Open http://localhost:3000/register. Product data is stored in PostgreSQL; the browser only keeps HTTP-only session cookies and an active-attempt recovery pointer.
To enable grounded AI, set APP_VERTEX_PROJECT and APP_VERTEX_LOCATION in backend/.env and authenticate with Google Application Default Credentials (gcloud auth application-default login). Without Vertex configuration, the same endpoints deliberately use the deterministic generator/evaluator, making local development and CI reproducible.
Health checks:
GET http://localhost:8010/api/v1/health/live
GET http://localhost:8010/api/v1/health/ready
The complete containerised backend can also be started from backend/:
docker compose up --build
By default Compose exposes the API on port 8010, PostgreSQL on 55432, and Redis on 6379.
Implemented API
All endpoints are prefixed with /api/v1.
| Method | Endpoint | Purpose |
|---|---|---|
POST | /auth/register | Create an account |
POST | /auth/login | Start an authenticated session |
POST | /auth/refresh | Rotate access credentials |
POST | /auth/logout | End a session |
GET, PATCH | /me | Read or update current user |
POST, GET | /subjects | Create or list owned subjects |
GET, PATCH, DELETE | /subjects/{subject_id} | Manage one subject |
POST, GET | /subjects/{subject_id}/exams | Create or list nested exams |
GET, PATCH, DELETE | /exams/{exam_id} | Manage one exam |
POST, GET | /subjects/{subject_id}/classes | Create or list classes |
GET, PATCH, DELETE | /classes/{class_id} | Manage one class |
POST | /exams/{exam_id}/mocks | Generate a deterministic mock |
GET | /mocks/{mock_id} | Read a mock without exposing answer keys |
POST | /mocks/{mock_id}/attempts | Start or resume an active attempt |
GET | /attempts/{attempt_id} | Reload an attempt and saved responses |
PUT | /attempts/{attempt_id}/responses/{question_id} | Autosave one response |
POST | /attempts/{attempt_id}/submit | Submit and evaluate idempotently |
GET | /exams/{exam_id}/attempts | List result history |
GET | /exams/{exam_id}/statistics | Read basic exam statistics |
The legacy /workspaces contract remains available for compatibility while new product surfaces use Subjects and Exams.
Frontend routes
| Route | Experience |
|---|---|
/home | Student dashboard |
/subjects | Subject categories |
/subjects/[subjectId] | Nested exams and classes |
/exams | Global exam index |
/exams/new | Five-step exam creation |
/exams/[examId] | Exam workspace |
/exams/[examId]/edit | Edit exam configuration |
/exams/[examId]/run | Focused mock simulation |
/exams/[examId]/statistics | Exam performance overview |
/classes | Class management |
Quality checks
Frontend:
cd frontend
npm run lint
npx tsc --noEmit
npm run build
Backend:
cd backend
source .venv/bin/activate
ruff check api
ruff format --check api
mypy
TEST_DATABASE_URL=postgresql+asyncpg://postgres:postgres@127.0.0.1:55432/openai_buildweek pytest
alembic check
PostgreSQL integration tests validate authentication, ownership isolation, CRUD, durable Exam configuration, mock generation, autosave, immutable submission and statistics. The same gates run in .github/workflows/ci.yml.
Privacy and product principles
- Private by default: uploaded study materials remain private unless a user explicitly publishes them.
- Exam fidelity over generic generation: mocks should follow the reviewed blueprint and rules.
- Evidence before adaptation: recommendations should disclose confidence, coverage and recency.
- Human review for high-stakes feedback: generated scoring is study guidance, never an official grade.
- Rights-aware sharing: users must have permission to publish third-party course materials.
- Clear prototype boundaries: simulated or incomplete AI functionality is labelled honestly.
Remaining release work
- Deploy the complete stack and configure judge credentials.
- Run the committed judge rehearsal in the final release environment.
- Freeze the release and capture the submission video.
Further documentation
- Frontend guide
- Backend guide
- Data Science D0–D3 acceptance plan
- Analytics v2 model card
- Judge demo runbook
- Research report
License
No open-source license has been selected. Until one is added, all rights are reserved by the repository owner.
Analysis
View
Metric
- 83
- 3
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- CSSIn code
- FastAPIIn code
- Next.jsIn code
- PythonIn code
- ReactIn code
- Tailwind CSSIn code
- TypeScriptIn code
- DockerClaimed
- PostgreSQLClaimed
- PyTorchClaimed
7 of 10 appear in the indexed code. 3 claimed on Devpost could not be matched to code, which may simply mean the tool leaves no trace in the repository.
AI coding agents
- Claude CodeConfig
- CodexConfig
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
989 KB
Source files
226
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
Rokki-Khazratov/OpenAI-buildweek
276 files · 2.0 MB · @ 2656af4
Structure
Interface
43 files · 16%Screens, components and styles rendered to the user.
API & routing
64 files · 23%Request entry points: routes, handlers and controllers.
Application logic
47 files · 17%Domain rules, services and shared utilities.
Background jobs
2 files · 1%Work run outside a request: tasks, workers and schedules.
Data & schema
40 files · 14%Schema definitions, migrations and data access.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- Python45%
- TypeScript39%
- Markdown13%
- YAML2%
- CSS0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
backend/pyproject.toml
pypi · 21- alembic
- asyncpg
- boto3
- dramatiq[redis]
- email-validator
- fastapi
- google-genai
- pgvector
- pwdlib[argon2]
- pydantic-settings
- pyjwt
- pymupdf
- python-docx
- python-multipart
- sqlalchemy[asyncio]
- uvicorn[standard]
- +5 more
frontend/package.json
npm · 17- @fontsource-variable/instrument-sans
- lucide-react
- next
- react
- react-dom
- +12 more
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This project’s features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.