Otkrytyi Diplom: Curricula by Admission Year and Edition
In Otkrytyi Diplom the curriculum has become an entity of its own: plans are stored by programme, form of study and admission year, every correction is saved as a new edition, checksums verify a plan when it is loaded, and a plan that exists only as a scan is entered as a difference from a similar one. How it works and how it was checked on real plans.
Until now the curriculum was an auxiliary file in Otkrytyi Diplom: it was attached to a grade statement, the program took credits and totals from it, and that was the end of its role. Now a plan is stored in the database as an entity of its own — by programme, form of study and admission year, with a history of corrections. The decision is recorded in ADR-0008, and the prototype has gained a “Curricula” section.

Why the plan belongs in the database
Checking the archive showed two things. First, a plan changes from year to year, but only a little. Between neighbouring admission years the credits of every discipline matched — 51 of 51 and 59 of 59 for two bachelor’s programmes — and a master’s plan matched the next year’s in every column of every row. Second, the forms of study of a single year differ more. The part-time master’s programme has its semesters shifted by one and 122 contact hours instead of 820; the part-time bachelor’s programme has its technological practice as one row of 9 credits, while the full-time one has two rows, of 6 and 3.
Hence the task: to see exactly what changed, and not to enter the plan anew every year. Typing numbers from the plan into the summary table for every graduation is exactly where errors are born.
One more circumstance gets in the way: of the archive’s 43 PDF plans, only five have text. The rest are scans, which can only be retyped.
Programme, plan, edition
The data model has three levels:
- programme — the field-of-study code and the profile; profiles are compared ignoring case and punctuation;
- curriculum — a programme, a form of study and an admission year; every year has its own plan, even if it matches last year’s;
- edition — an immutable snapshot of a plan.
Loading a plan with the same key again creates a new edition only if at least one cell or the header differs; the SHA-256 of the header and all rows is compared. The same file loaded again gets the answer “already loaded”. A saved edition never changes: a correction is saved as a new edition that refers to the one it was based on. So a graduating class checked against a plan can always refer to the edition it was checked against.
Rows are stored as printed in the plan: the index, the name, the semesters of five forms of assessment, three credit columns and five hour columns. A row’s key is its position, not its index, because the index is not unique even within one plan: «Б.3.1.1» is printed both on the final qualification work and on the state exam.
The plan’s structure — a row’s parent, its block, the leaves, elective alternatives, the printed name of a practice — is not stored but computed on reading. So an old edition does not depend on how an old version of the program parsed it: fixing the parsing rules changes the display, not the data.

Checksums
The plan checks itself. In every row, credits equal the credits for exams plus the credits for classes, hours equal credits times 36, and class hours equal contact work plus independent work. In the structure, every row equals the sum of the rows nested in it, and the programme’s volume equals the sum of blocks 1–3. A wrong number is reported once — at the row above it, not along the whole chain of parents.
A loaded file is saved in any case, and the number of errors is recorded in the edition and shown in the list of plans. A correction whose sums do not hold can be saved only if the operator explicitly confirms it.

Checking real plans found one false alarm, and it is instructive. The hours of the “part formed by the participants” were off by exactly 328. These are the physical culture electives: they have hours but no credits, and «Планы», the planning software, leaves them out of the part’s sum. Now a row without credits stays out of the sums — the way the source itself counts.
Comparison with the nearest plan
Every edition is compared with the programme’s nearest plan: the same form for the nearest previous year, or, if there is none, another form for the same year. Elements are matched by their printed name, not by index, so a renumbered discipline remains the same discipline. The comparison shows what was added and removed, where credits and forms of assessment changed, and how the totals changed.
On real plans the comparison confirmed what would otherwise have had to be found by eye: the master’s plans of two neighbouring years matched entirely, while comparing the full-time and part-time forms of one year showed the semesters shifted by one and classroom hours going from 820 to 122.
A plan that exists only as a scan
Recognising scans — with OCR or a small model — was considered and postponed. Another route turned out cheaper: «Создать на основе», “Create from”. The operator takes the nearest plan and corrects only the differences, and the checksums confirm the result. If the form of study is different, the contact and independent hours are cleared: they depend on the form, while the remaining hours follow from the credits. The operator types in the total hours from the document.

It was checked on a real case: the part-time bachelor’s plan for 2021 exists only as a scan. It was created from the full-time plan of the same year: the technological practice was merged into one row of 9 credits, the second row removed, and the contact and independent hours typed into the totals row. The sums held, the comparison showed exactly this correction, and all 55 elements matched the scan.
How it was checked
Seven real plans — five PDFs with text and two Excel files — were loaded through the pages, and the sums hold for all of them. The only remaining warning is a module heading without numbers. The Excel and PDF versions of one plan matched row by row in every column. Loading the same PDF again was recognised as “already loaded”, and a scan was refused with a hint about “Create from”. The checks ran locally; real plans never reach the repository, since the tests build plans in memory.
There are now 128 tests instead of 91, and they were again checked by breaking the code. The tests caught three planted errors: counting rows without credits in the sums, finding a parent by index prefix without the dot — which put the second «Б.3.1.1» under the first — and carrying contact hours over to a plan of another form.
One breakage went unnoticed, and rightly so. The explicit limit on the number of form fields was removed from the settings: Tomcat 10.1.60 defaults to 10,000, and the form of a 70-row plan has about 1,200 fields. The setting stays anyway: if a Tomcat update brings a lower default, a long plan must not be silently cut off. A separate test with a form of over 1,500 fields guards it.
Server and container
The prototype still runs as a single file on a workstation, but it can now be installed on a server too. A new context-path setting publishes the program under a prefix behind a reverse proxy, for example at https://example.org/open-diplom/: page links are relative to a <base> with the prefix, redirects start from it, and the routes do not see it. The prefix is empty by default, so a desktop run is unchanged.
For servers that already run Docker there is an image. Its build runs every test, including printing and reading PDF plans: for them the image gets the Liberation Serif font, which has the metrics of Times New Roman. The program itself runs in the container as an unprivileged user and keeps its database in the /data volume.
Next
The next stage is the graduating class: binding it to a specific edition of the plan and matching grade-statement rows to plan elements in the staging area. The links “statement row → plan element” will be stored at the programme level, so that next year’s plan picks them up by itself. One limitation is already known: “Create from” carries the semesters over as they are, while the part-time form numbers them differently. The diploma supplement does not need semesters, but they should be corrected in the plan from the document.
Conclusions
- A document that changes from year to year is worth storing as editions rather than overwriting; otherwise it is lost which version a result was checked against.
- Structure is better computed on reading than stored: then fixing the parsing rules does not require rewriting old data.
- Checksums turn manual entry from a risk into a verifiable operation — and are themselves checked on real data: the 328-hour false alarm surfaced only there.
- A scan does not have to be recognised. Entering the difference from a similar plan, verified by the sums, is cheaper and more reliable.
- A setting the tests cannot break is not necessarily redundant: the explicit field limit protects against a future update, and a separate test pins it down.
Availability
The project is open under the Apache 2.0 licence. The decision on storing plans is docs/architecture/adr/0008-curricula-by-editions.md; the results of the checks are in docs/prototype.md.
- Source code: github.com/nikita-konkin/open-diplom
Tags
More project updates
Otkrytyi Diplom: From Grade Statement to Blank — Graduation, Documents, Printing and Blank Accounting
In a week the Otkrytyi Diplom prototype went the whole way of a graduation: matching a group's grade statement to the curriculum, a registry with registration numbers, correctio...
Otkrytyi Diplom: A Java 11 Prototype, Checked Until the XML Matched Byte for Byte
The draft architecture for an open replacement for CyberDiploma now has a prototype and a repository of its own. What the prototype does, which of the stack criteria are already...