Everything that powers the WCL examination at Ramdeobaba University: a sealed desktop client candidates take the exam in, a live control room for administrators, public portals for hall tickets and results, and one API behind them all.
rbuexam.in | result.rbuexam.in | admin.rbuexam.in | api.rbuexam.in
The deployment that served these hostnames has been decommissioned.
- What this is
- In production
- The five applications
- How exam day works
- Architecture
- Tech stack
- Running it locally
- Production
- Documentation
- Team
- License
This repository is the complete software stack used to conduct the Western Coalfields Limited (WCL) examination hosted at Ramdeobaba University (RBU), Nagpur. Hundreds of candidates sit the exam at the same time on lab computers, and the platform covers their entire journey: downloading a hall ticket at home, taking a proctored exam in a locked-down fullscreen application, receiving their score the moment the paper is submitted, and looking the result up again afterwards.
This is not a demonstration. The platform has conducted a live examination for real candidates on this infrastructure.
The WCL examination was conducted on 26 July 2026 on the deployment described below.
| Candidates registered | 574 |
| Candidates who sat the exam | 526 |
| Paper | 100 questions, 60 minutes, negative marking of 0.5 |
| Submitted by the candidate | 340 |
| Auto-submitted by the server at the deadline | 186 |
| Sessions left ungraded or unfinished | 0 |
| Feedback responses collected | 526 |
Every candidate who began the exam was graded and every result was
written. Results were published to result.rbuexam.in after the paper
closed.
| App | Role |
|---|---|
app/client |
Electron desktop app the candidates take the exam in. Fullscreen kiosk with no title bar and no way out, question images with zoom, offline-tolerant answer saving, and integrity monitoring. Updates itself between releases. |
app/admin |
Next.js control room: manage questions and their images, import participants, watch live sessions, add time, release device bindings, and export results. |
app/hallticket |
Next.js public portal where candidates fetch and print their hall ticket PDF before exam day. |
app/result |
Next.js public portal where candidates look up their score and per-question breakdown once results are published. |
app/api |
Bun + Express + Drizzle API that owns authentication, exam sessions, answer sync, grading, and feedback. PostgreSQL stores the truth, Redis holds the hot exam state. |
- Before the exam. The candidate opens
rbuexam.in, enters their employee id and date of birth, and downloads a hall ticket PDF with their seat allocation. - Sitting down. The lab PC launches the exam client straight into fullscreen kiosk mode. The candidate signs in with their assigned credentials and the session binds to that machine, so nobody else can continue it elsewhere.
- During the exam. The timer runs on the server, so refreshes, crashes, and reboots cannot add time. Every answer is buffered locally and synced continuously, so nothing is lost if a machine dies mid-click. Leaving fullscreen, switching windows, or losing focus is recorded as an integrity event that proctors see live.
- If a PC fails. A proctor presses Release device in the admin panel, the candidate logs in on any other machine, and every answer, every mark for review, and the running clock resume exactly where they left off.
- Submitting. Grading happens instantly on the server, with negative marking of 0.5 per wrong answer. The candidate sees their final score, rates the platform and the venue, and the application closes itself, leaving the seat ready for the next candidate.
- The deadline. Anyone still writing at the deadline is auto-submitted by the server, even if their machine is powered off. On exam day this accounted for 186 of the 526 papers.
- Afterwards. Once an administrator publishes results, candidates sign in at
result.rbuexam.inwith the same employee id and date of birth to see their score again, along with every question they were served and the correct answer. Nothing is disclosed before that switch is flipped.
flowchart LR
K["Exam client<br/>Electron kiosk on lab PCs"] -->|HTTPS| LB
B["Candidate and admin<br/>browsers"] -->|HTTPS| LB
subgraph AWS["AWS ap-south-1"]
direction LR
LB["Application Load Balancer<br/>one TLS certificate,<br/>routing by host name"]
subgraph FE["Frontend EC2<br/>Docker, watchtower"]
direction TB
HT["Hall ticket portal<br/>rbuexam.in"]
RS["Result portal<br/>result.rbuexam.in"]
AD["Admin panel<br/>admin.rbuexam.in"]
end
subgraph BE["Backend EC2<br/>Docker, watchtower"]
direction TB
API["API<br/>api.rbuexam.in"]
OBS["Observability<br/>Grafana, Prometheus, Loki<br/>grafana.rbuexam.in"]
end
subgraph DATA["Managed data"]
direction TB
PG[("PostgreSQL<br/>Amazon RDS")]
RD[("Redis<br/>ElastiCache")]
S3[("Amazon S3<br/>question images")]
end
LB --> HT
LB --> RS
LB --> AD
LB --> API
LB --> OBS
API --> PG
API --> RD
API --> S3
HT --> PG
RS --> PG
end
The infrastructure is codified as Terraform in terraform/,
and the full network design (VPC, security groups, data flows) is explained
in docs/ARCHITECTURE.md.
Server deploys are cut deliberately with ./release.sh <service>, which
tags a version; the exam client ships on every push to main:
flowchart LR
T["release.sh tag"] --> GA["GitHub Actions"]
P["Push to main"] --> GA
GA -->|Docker images| DH["Docker Hub"]
DH -->|pulled by watchtower| SRV["EC2 services"]
GA -->|Windows installer| GR["GitHub Releases"]
GR -->|electron-updater| EX["Installed exam clients"]
Bun, TypeScript, Express, Drizzle ORM, PostgreSQL, Redis, Next.js, React, Tailwind CSS, shadcn/ui, Electron, electron-vite, Docker, GitHub Actions, Terraform, Grafana, Prometheus, Loki, and AWS (EC2, ALB, RDS, ElastiCache, S3, Route 53, ACM).
Prerequisites: Bun plus PostgreSQL and Redis (Docker works well for both).
| App | Start | Serves |
|---|---|---|
| API | cd app/api && bun install && bun run db:migrate && bun run seed && bun run dev |
http://localhost:4000 |
| Admin | cd app/admin && bun install && bun run dev |
http://localhost:5000 |
| Hall ticket | cd app/hallticket && bun install && bun run dev |
http://localhost:5001 |
| Result | cd app/result && bun install && bun run dev |
http://localhost:5002 |
| Client | cd app/client && bun install && bun run dev |
desktop window |
Each app ships a .env.example describing its configuration and a README
with the details. Everything defaults to the local API at port 4000.
The examination is over and the production environment has been decommissioned. The hostnames below served the platform on exam day and are listed as a record of the deployment; none of them resolve to infrastructure we operate any more.
| Hostname | Service |
|---|---|
| rbuexam.in | Hall ticket portal |
| result.rbuexam.in | Result portal |
| admin.rbuexam.in | Admin panel |
| api.rbuexam.in | API |
| grafana.rbuexam.in | Grafana dashboards |
The stack runs locally from this repository exactly as it did in production; see Running it locally.
| Document | Contents |
|---|---|
| docs/API.md | Full API reference |
| docs/RUNBOOK.md | Operations runbook for exam day |
| docs/NEW_EXAM.md | Setting up a new exam from scratch |
| docs/FEEDBACK.md | Post-submission candidate feedback |
| docs/KIOSK_LOCKDOWN.md | How the client lockdown works |
| docs/ARCHITECTURE.md | Network design, security groups, and data flows |
| docs/DEPLOY_FRONTEND.md | Frontend infrastructure and deployment |
| docs/DEPLOY_BACKEND.md | Backend infrastructure and deployment |
| docs/OBSERVABILITY.md | Logs, metrics, and dashboards |
| docs/RULES.md | Writing rules for prose in this repository |
Built and maintained by Bhuvnesh Verma and Vivian Demello.
Code ownership per path is declared in .github/CODEOWNERS, which GitHub uses to request the right reviewer automatically on every pull request.
Copyright (c) 2026 Bhuvnesh Verma and Vivian Demello. All rights reserved.
The source is published so it can be read and studied. It is not open source: using, copying, modifying, or redistributing it requires written permission from both copyright holders. See LICENSE for the full terms.