My Degree Planner

My Degree Planner

ANU’s Programs & Courses pages hold everything a Computing student needs to know about their degree, but the Program Requirements section is a long block of text: nested “6 units from the following list”, “one of the following specialisations”, “Either … OR … AND …”, plus whole-program rules like “a maximum of 60 units may come from 1000-level courses”. My Degree Planner turns that text for four standalone 2027 Computing programs into an interactive requirements tree. It then lays the student’s own record over it: courses completed, being studied now, and planned for a future semester. The same plan is also shown as a semester-by-semester timeline. Each student has a private My Degree Planner account and plan. It is a planning aid built on the official catalogue, not a degree audit.

The requirements tree for the Bachelor of Advanced Computing (Honours): groups with progress bars, a choose-one list showing which course counts, and the whole-program rules on the right

What good looks like here

Every academic fact is official, and traceable. Everything comes from the 2027 ANU Programs & Courses catalogue, read on 27 September 2026:

The plain-text extracts, each with its source URL, are committed in research/2027/. Two further official sources sit alongside them:

Every requirement group shows its official sentence word for word, and the short title above it is only a navigation label. Where sources disagree, the app shows both. The program page lists COMP2100 as “Software Design Methodologies”, its course page says “Software Construction”, and the leaf carries both. The Machine Learning specialisation is listed in the 2027 AACOM requirements but has no 2027 page, so its structure comes from the 2026 page, and the node says so.

Hierarchy one level at a time, with a visual grammar for “and” and “or”. Nothing is expanded when the page loads. Each group has a glyph, a plain-words relation (“All 8 required”, “Choose 1 of 2”, “At least 12 units”, “Up to 12 units · optional”, “One pathway”, “Any 18 units”), and a connector line whose style repeats the relation: solid when every child is needed, dashed when you choose among them, dotted for an open “any course that fits” requirement. Pathways (specialisations, majors, the AACOM final-year options) are cards. The one you choose is marked, and the others show what they would hold if chosen. On a phone the tree becomes a drill-down: one group’s children fill the screen, with a breadcrumb trail back up.

On a phone: the Mathematics choose-one requirement, with one course counting here and the other counting toward Electives instead

Every course leads to its official page. Every course anywhere in the tree or the semester plan links to programsandcourses.anu.edu.au/2027/course/<CODE>. Every code comes from the verified list, so every link resolves.

A private plan, one record per course, one calculation.

The semester plan: courses by semester, each saying which requirement it counts toward, the current semester outlined

How progress is counted

Taking a course and having it satisfy a requirement are different things, and the tree shows both. Each course record credits at most one requirement, never more units than that requirement or any group around it can hold. Credit is given in this order, across the part of the tree in play (chosen pathways only):

  1. compulsory courses
  2. exact “choose” lists
  3. “at least” bands
  4. “up to” bands
  5. open requirements with a filter (“18 units of 3000/4000-level COMP”)
  6. unrestricted electives

A course goes whole into the first open requirement with room for it, and never splits across two. In a choose-one list such as “Choose 1 of 2 · MATH1005 / MATH2222”, only one course counts, and the other shows “Counts toward Electives instead”. The student can switch which one counts (“Count this one here”); the server checks the requirement, the option and that the course is in their plan. Adding the other option of a choose-one list offers to replace the course that currently counts, or to record both. Where the official pages list the two as incompatible (COMP1100 and COMP1130, for example), the second is recorded but counts nowhere: “Recorded in your study history · 0 units currently counted toward this degree”. Course history and requirement allocation are separate things, and a record is never refused as a way of fixing a count.

Whole-program rules sit beside the tree. Total units, the 1000-level maximum, the COMP level minimums and the Transdisciplinary Problem-Solving minimum are quoted in full and measured against the units that count toward the degree. Rules the planner deliberately doesn’t evaluate are listed separately: the AACRD 75%/80% WAM progression rules and the honours calculations.

Course rules

Each program course’s official “Requisite and Incompatibility” block mixes different kinds of statement:

An earlier version flattened each block into a list of codes and treated them all as incompatible. COMP3320’s block, for example, was read as saying it was incompatible with its own prerequisites. That model is gone.

src/lib/rules.ts now reads a block in three conservative steps:

  1. It splits the block into clauses by their opening words (“To enrol…”, “Incompatible with…”, “You are not able to enrol…”, “You must also be studying…”, permission wording), taken from the page’s own line structure.
  2. It reads a prerequisite into an expression tree only if every token is understood. The tree holds courses, co-requisite options, marks, “N units of subject X at level Y excluding Z”, and program nodes.
  3. Anything else is kept word for word, flagged, and never turned into a harder rule than the page states.

Rules the parser can’t read completely have a hand-reviewed reading in src/data/rule-overrides.ts (24 of 98), each pinned to the exact official text it was checked against. Where the wording is genuinely ambiguous (INFS3059 doesn’t say which alternative its enrolment condition covers), the planner shows the wording instead of choosing a reading. The result is:

Two things keep this from regressing:

The course panel shows the rules under their own headings: Prerequisites (as groups), Co-requisites, Incompatibilities, Other enrolment conditions, Assumed knowledge (advice, not a requirement), Co-taught with, and the Official wording, with a note when some conditions couldn’t be interpreted.

How rules are applied

Rules depend on the record’s status:

Refused (data integrity) Planning warnings, for Planned courses (notes otherwise)
A second record for a course already in the plan A prerequisite group the plan doesn’t show before the course
A code that isn’t in the 2027 undergraduate catalogue An official incompatibility with a course in the plan
Units outside the course’s official range More than 24 units in a study period (overload needs approval); more than 36, which ANU policy says is never permitted
Malformed input, an ended session, or an entry that isn’t yours A 2027 session the catalogue doesn’t list; a two-semester course starting outside a semester
Status that contradicts the calendar (planned in the past, completed in the future)

The load figures come from the ANU Student academic study load and progression policy (research/policy-study-load.txt, clauses 12 and 20). The server returns each refusal with its own status and code, and each save with its warnings and notes:

Accounts and privacy

This is a My Degree Planner account, not your ANU account. Never enter your ANU password here.

Before accounts existed, every visitor shared one anonymous demo user. Its data couldn’t be attributed to anyone and included duplicates and a fabricated code, so migration 0003 clears it. The migration trail was checked against a copy of that production data before deploying.

Where it stops

What was left out on purpose: combined and double degrees, every other ANU program, course recommendations, authoritative prerequisite enforcement, timetable clashes, GPA, financial information, enrolment, and any ANUHub or ISIS access. Reading a student’s results automatically would need an officially approved ANU integration; there is no public interface for it, and this app never asks for ANU credentials. A possible future step would be importing a Statement of Results with the student’s explicit consent, extracting only course codes and terms and keeping neither the document nor the marks. That is not built.

What’s enforced, and what’s judged

pnpm check holds the mechanical promises:

pnpm e2e (e2e/planner.e2e.mjs) drives a real browser against a running server through the flows only a browser can show: two accounts, duplicate then move (never into the semester it’s already in), editing, Remove with Undo, choose-one switching and replacement, “Add anyway”, COMP3320’s rules under the right headings, one announcement per action, unknown courses, an offline save, focus returning after Escape, the program switcher’s accessible names, a scoped reset, logging out and back in, and the mobile drill-down with reduced motion.

What only a person can judge: whether the tree is genuinely easier to follow than the official text, whether “counts here / counts toward … instead” makes the difference between taking and counting clear, whether the motion explains structure rather than decorating it, and whether the look is calm and recognisably ANU without imitating its site.

Running it

mise install
pnpm install
pnpm dev      # http://localhost:4321
pnpm check    # types, build, and every spec above
BASE=http://localhost:4321 CHROME="/path/to/chrome" pnpm e2e

The schema lives in src/lib/schema.ts and its migrations in drizzle/, applied at boot. Reference data (courses and programs) is re-seeded from research/ and src/data/ on every boot, and personal tables are never touched by the seed.