The docs still described two standalone projects with separate frontends,
separate parsers and three Vite variants. Rewritten around what the repo now
is, merging both projects' copies rather than keeping one and discarding the
other — deployment-guide.md and system-architecture.md existed in both and
documented different pipelines.
project-overview.md goal, scope, constraints, the four datasets, history
system-architecture.md data flow, canonical schema, routing, how one
frontend serves both exam years without branching
data-pipeline.md per-dataset Excel formats, the three 2016 layouts,
overflow-sheet gotcha, expected row counts
deployment-guide.md the single-build workflow, adding a dataset,
why no uncompressed database can ship
Records the release gate in plans/reports/parser-parity-result.md: row counts,
all 18 pre-existing per-column non-NULL counts and the deterministic student
samples are identical across all four datasets, against databases decompressed
from the exact bytes the pipeline publishes. The 1,691 recovered
foreign-language scores are documented with the evidence they are real.
Also drops a machine-specific absolute path from a comment in
format_detect_2016.rs. The build-database.js citations there are kept: that
file no longer exists in this repo, but the references explain why several
parsing rules look arbitrary.
2.6 KiB
Project Overview
Goal
A public lookup tool for Vietnam's National High School Graduation Exam scores, running entirely in the browser and hosted for free on GitHub Pages. Covers the 2016 and 2017 exams — 1.7 million candidates across four datasets.
Scope
- Lookup by exam ID or full name, with Vietnamese diacritics handled
- Read-only SQL queries against a single
studenttable - Admission-block (khối thi) totals computed per candidate
- Static datasets — both exams are long over and the data is frozen
Target users
- Former candidates checking their scores
- Education researchers and data journalists running aggregate statistics
- Developers exploring SQL against a real-world dataset
Constraints
- Zero backend. The full database (38–48 MB gzipped per dataset) is downloaded to the browser and queried in-process.
- Read-only.
INSERT/UPDATE/DELETEare rejected, so nobody is misled into thinking edits persist.sql.jsis in-memory anyway. - Row caps. 100 rows for lookups, 1000 for custom SQL, to prevent browser hangs.
- Vietnamese-first UI. App labels and data are Vietnamese; documentation is English.
Datasets
| id | Exam | Candidates | Notes |
|---|---|---|---|
2016 |
2016 | 877,461 | 119 files, three column layouts |
2017 |
2017 | 861,068 | current generation, reproducible from source |
2017-old |
2017 | 847,348 | pre-refresh archive |
2017-old2 |
2017 | 679,764 | corrected re-export |
The three 2017 datasets are kept side by side because they disagree, and the
disagreement is itself informative. Only 2017 is re-fetchable; the rest exist
solely as the copies committed here.
Original 2016 aggregator link
(https://dtntbacgiang.edu.vn/tin-tuc/tin-tuc-su-kien/cong-bo-diem-thi-thptqg-2016-toan-bo-120-cum-thi-da-co-diem.html)
is no longer accessible, which is why the raw files are mirrored in data/2016/.
History
Each year began as a standalone repository (thptqg2016, thptqg2017), merged
here with full history. They initially kept separate frontends and separate
copies of the same Rust parser, synchronised by hand. That duplication was
removed: there is now one frontend, one parser, and one canonical schema, with
per-dataset differences confined to four small config files and one registry
entry each.
The unification also fixed a latent data-loss bug — neither year's parser
config listed the complete set of subjects, so 1,691 candidates were missing
their foreign-language score. See data-pipeline.md.
Status
Stable, data frozen. Work is limited to UX polish and keeping the pipeline maintainable.