Your prototype
What this is
The Timetable Clash Resolver is a single-student tool for building and checking a personal weekly ANU timetable. A student searches a small catalogue of real ANU courses, selects the ones they’re taking, and adds specific class sessions from each course’s available offerings onto their timetable. The app immediately flags any sessions that overlap. When a clash occurs, the student can either remove one of the sessions or acknowledge the specific conflict and keep both. The timetable, course selections, and acknowledgement decisions all persist across reloads, so the prototype models the experience of actually building a timetable from ANU’s own course structure, rather than typing arbitrary sessions into a database.
What good looks like here
For this prototype, “good” means the timetable is useful, predictable, and honest about its state, built from data a real ANU student would recognise. A student should be able to search for a course by code or title, select it, add one of its real class sessions, reload the page without losing anything, see every current clash, and make an explicit decision about each conflict. The system should never hide a real clash simply because another session was added or because the user previously acknowledged it, and it should never ask the student to hand-type something the catalogue already knows.
The course catalogue itself draws a hard line between two kinds of data. Course codes, titles, and unit values (COMP1100, COMP1130, COMP2100, COMP2310, COMP3600, COMP3620, COMP4020) are real, public ANU information. The specific day/time/activity/location of each class session is manually curated for this demo — there is no scraper and no live feed into ANU’s own timetabling system, which is well outside this slice’s scope. src/lib/catalogue-seed.ts is the single source of truth for both halves, and says so directly at the top of the file.
I decided that a clash should be defined by two sessions occurring on the same weekday with overlapping half-open time intervals. Back-to-back sessions therefore do not clash. I also decided that conflict detection should always be derived from the persisted timetable rather than stored as a separate piece of state, and that course selection is a separate concern from session placement — selecting a course just makes its sessions available to add, it doesn’t add them itself. This keeps the conflict information consistent with the sessions that actually exist, and keeps “which courses am I taking” legible on its own.
I looked at the conventions of timetable-style interfaces and the existing ANU context to make the prototype feel like a believable university scheduling tool, while deliberately keeping the scope small enough to demonstrate one complete user flow: browse → select a course → add a session → spot a conflict → resolve it. This led to a searchable course browser, a “My Courses” area for selected courses and their addable sessions, a weekly timetable grid, clash indicators, and explicit conflict acknowledgement.
The prototype deliberately does not attempt to reproduce the full ANU timetabling system. It does not include authentication, a full enrolment or prerequisite system, automatic timetable import from MyTimetable, drag-and-drop scheduling, notifications, multi-user collaboration, ICS/CSV export, or an automatic conflict resolver. These would add substantial product and integration complexity without strengthening the core Crit 7 slice: catching a clash the student would otherwise have caused by accident.
Some parts of “good” are enforced automatically. The clash rule is covered by unit tests; course/session selection, persistence, and cascade removal are covered by database and API tests; and the Crit 7 user journey — select a course, add a session, select a conflicting course, add its session, resolve the clash, reload — is covered by an HTTP-level integration test. The tests also protect important invariants such as multiple simultaneous clashes, acknowledgement of only currently conflicting pairs, removing a course cascading its sessions and any acknowledgement involving them, and persistence across reloads.
Other parts remain judgement calls. The visual design of the weekly grid, the decision to seed a small fixed catalogue rather than scrape a live one, the 08:00–21:00 half-hour time range, and the choice to show an acknowledged conflict with ⚠ while removing it from the unresolved-conflict alert are product decisions rather than properties that can be completely captured by automated tests.
The rules behind these decisions live in CLAUDE.md, while the executable checks that protect the important behaviour live in spec/. Together, they turn the prototype’s definition of “good” into both documented design constraints and testable behaviour.