SUrriculum is a fully client-side curriculum planner for Sabancı University undergraduate programs. It runs entirely in your browser (plain HTML/CSS/JS) and helps you:
- Build and maintain a semester-by-semester plan
- Track major / double major / minor requirements
- Import your transcript (Academic Records Summary) to prefill taken courses
- Use a term-selectable scheduler (SUchedule-style) to build a weekly timetable and sync it back into your plan
Live version: https://beficent.github.io/surriculum/
Note: Always verify graduation requirements using official sources.
-
Clone or download this repository.
-
From the repository root, start a local HTTP server:
python -m http.server 8000
-
Open http://localhost:8000/ in a modern browser.
-
Pick your program(s) and admit term(s) from the sidebar and start planning.
There is no build step, application server, or database. A small static HTTP
server is required because browser modules, data requests, PDF.js workers, and
offline caching do not work reliably when index.html is opened directly over
file://.
The core planner targets current evergreen browsers. PDF transcript import uses the locally bundled PDF.js 6.2.108 legacy build, whose practical upstream floor is Chrome 125+, Firefox ESR+, and Safari 18+ (mostly). Microsoft Edge follows its corresponding Chromium baseline. The full browser suite runs on Chromium, with an additional critical-flow gate for Firefox and WebKit.
All plans and progress are stored locally in your browser. Use the plan Export/Import flow to back up or move data between devices.
- Programs: select a main major, optional double major, and up to 3 minors.
- Admit terms:
- Verify the relevant dates in SUIS → Student Records → General Student Information.
- For the main major and every minor, usually use your initial university entry term. For most students, this means the minors use the same admit term as the main major.
- For a double major started before Fall 2026-2027, use the first term after the double-major application was accepted. For one started in Fall 2026-2027 or later, use your initial university entry term.
- Main major and double major each have an admit-term selector, and each minor slot (
Minor 1/2/3) has its own.
- Plans: keep up to 10 saved plans, reorder them by dragging in the plan menu, rename, export, import, and delete (while keeping at least 1 plan).
- Planner board: add semesters and courses, reorder semesters with the desktop drag handle or directional controls, restore oldest-to-newest display order with Sort Semesters, remove courses, and see each term's full SU workload. Card order is presentation-only: prerequisites, retakes, progress, GPA, and curriculum allocation use each semester's persisted academic term code. New and edited cards cannot duplicate an existing term; legacy duplicate-term plans remain lossless but ambiguous scheduler sync fails closed. Every positive-SU course card contributes to this load even when it is N/A for the primary program; that portion is shown separately, for example 15 SU (3 N/A). The full load turns red above the standard 8-SU Summer or 20-SU Fall/Spring threshold, but this is advisory and does not prevent an approved overload. Graduation-credit totals remain separate. On desktop, courses can be dragged between semesters with a visible insertion preview; the course move control also provides a keyboard destination picker.
- Course details: open a details view for planned courses using the course row actions. Catalog details include the university's prerequisite, corequisite, and General Requirements text when available.
- Import transcript: import Academic Records Summary (HTML/PDF) or a YÖK transcript PDF (not preferred).
- Graduation + summaries: check requirement progress and open detailed summaries for majors and minors.
- Current-term tools:
- Current term highlight
- Optional exact-term offered-course filtering for each planner semester
- Scheduler for picking sections and building weekly timetables by term
- Quality of life: dark/light theme, collapsible sidebar, touch-friendly behavior, custom modals (no default browser prompts), first-use guidance, and a concise one-time release summary for returning users.
If you hit a bug or want to improve the tool, open an issue/discussion or contact: bilal.gebenoglu@sabanciuniv.edu
- Choose your main major (required).
- Optionally choose a double major.
- Add up to 3 minors using the “Add minor” flow.
- Verify the dates in SUIS → Student Records → General Student Information, then set each selected program's admit term:
- Main major and minors: usually use your initial university entry term. For most students, the minor terms therefore match the main-major term.
- Double major before Fall 2026-2027: use the first term after your double-major application was accepted.
- Double major from Fall 2026-2027 onward: use your initial university entry term.
Course catalogs and requirement rules are loaded based on these selections.
- Use “+ New Semester” to add a term to your plan.
- Use “+ Add course” in a semester to pick a course from the catalog.
- Use a semester's desktop drag handle or its directional controls to reorder terms.
- Semester order is only visual. Academic chronology always follows the saved term codes; use Sort Semesters to restore an oldest-to-newest view.
- On desktop, drag a course to another semester or activate its move control and choose a destination. The move preserves the course record and recalculates both terms.
- Use per-course buttons (next to delete) to open details and other actions.
The course picker can combine search with program/category, course level, credit, exact-term offering, already-planned, and prerequisite filters. Its prerequisite checks use the target semester's canonical term code: ordinary prerequisites and prior-SU requirements look strictly earlier, while only explicit concurrent clauses can use the target term.
The suggestion list adapts to the selected semester's visible course pane. It uses extra room on tall cards, contracts inside short viewports, and opens below the search controls only when the space above is genuinely too limited.
Picker results and planned course cards can also show advisory offering-history tags such as No Fall offerings found, No Spring offerings found, No Summer offerings found, and Not offered every year. These are derived from deduplicated recorded offerings, not hardcoded course lists. Failed, empty, or sparse histories remain untagged, and an exact published target-term offering suppresses all historical warnings for that selection. The tags describe past evidence only; future availability can change.
Course and credit prerequisites are advisory planning guidance. A requirement such as SPS 303's 58 prior SU is checked against positive SU credits in strictly earlier planner semesters. Successful and still-planned eligible courses count, matching ordinary course-prerequisite planning; failed, withdrawn, grade NA, unsupported-grade, same-term, and later courses do not. The warning therefore says planned/completed, not officially earned. It does not remove a course or prevent an approved exception, and official enrollment eligibility must still be confirmed in SUIS.
This is an overall prior-SU check, not a program-allocation total. A course
categorized N/A for the selected major can still contribute when its own grade
is successful or pending; the separate transcript grade NA (Not Attended)
cannot.
If a course is missing from the catalog (or you want placeholders), you can add a custom course and set its credits (including .5). Its category is saved separately for every selected program: for example, the form shows CS Category, IE Category, and one category selector for each selected minor. Changing which program is the main or double major does not move those classifications between programs. Use the ? beside a selector to see how its available categories are allocated, including the difference between None and N/A. An official catalog classification always takes priority when that course is listed by the selected program and admit term.
Controls provides four course-picker defaults: Show course details, Hide courses planned by the selected semester, Only show courses offered in the semester, and Smart Sort. They are applied when a course picker opens. The offered-only control inside a picker is local to that semester: changing it does not rewrite the sidebar default or another open semester's picker.
In a Planner course picker, Hide courses planned in this or earlier semesters hides courses in the destination semester and academically earlier semesters; a course planned only in a later semester remains visible. In Scheduler, Hide courses planned before the selected term keeps the selected term's planned courses available for section selection.
The offered-only setting uses the destination semester's exact schedule. If that schedule is unavailable, it fails open and leaves courses visible; offering-history badges remain advisory and do not drive this filter.
Open Filters beside the course search for program, category, level, credit, and course-requirement controls. Planner credit and requirement choices persist independently from Scheduler choices.
Each course is scored based on how helpful it is for your selected programs. The
score uses the course's marginal value: alternatives, exclusions, named
requirements, and already-filled pools are applied first, so a course receives
the value of the highest requirement pool it can still advance. A catalog type
of None, N/A, or an unknown value contributes no type points.
Planner scoring counts only degree-eligible courses in semesters strictly before
the destination semester. Scheduler uses the same rule against its selected
term, even when that differs from the app's current term. This keeps later and
same-term plans from prematurely satisfying a requirement.
Base points (by course type, per program):
University: 36Required: 28Core: 18Area: 12Free: 0
Extra points:
+ 0.1 × (SU credits)per course+ 6when the course belongs to a named or predicate-based requirement group that is not yet fulfilled before the selected semester. Named/group candidates keep their published category value while that requirement remains useful.- For engineering majors only (Data Science is not treated as engineering):
+ 2 × (Basic Science credits)only if your Basic Science requirement is not fulfilled yet+ 1 × (Engineering credits)only if your Engineering requirement is not fulfilled yet
UniversityandRequiredpoints stop contributing once the relevant requirement is already fulfilled (per program). A HUM course also loses its University points once it no longer fills that program and admit term's remaining HUM requirement; it stays visible and selectable. Thus a second 200-level HUM is demoted when the rule still needs a 300-level HUM, but remains prioritized under the historical any-two-HUM rule. Missing SPS 303 does not promote unrelated extra HUM choices.
Program weighting:
- Main major:
× 1.2 - Double major:
× 0.8 - Each minor:
× 0.5(minors contribute at half weight)
Before comparing scores, Smart Sort puts courses that are actionable in the selected semester first. When prerequisite checking is enabled, a course with a definitively unmet prerequisite or prior-SU rule is placed after ready courses; a corequisite-only warning does not lower it. In Planner, courses known not to be offered in that exact semester follow known/unknown available courses. Missing, unknown, and manual-review data fail open. Courses within the same actionability group are ordered by score and then alphabetically.
Equivalences:
CS 210/DSA 210are treated as the same course for scoring/suggestions (canonicalized asDSA210).
Open Import Records in the header and upload one of:
- Academic Records Summary HTML (preferred): save as “Webpage, Complete”
- Academic Records Summary PDF: use your browser/system Save as PDF
- YÖK transcript PDF (not preferred): supported as an alternative import
Important notes:
- If you upload a Degree Evaluation document, SUrriculum rejects it and shows a dedicated warning explaining how to export the correct file.
- Erasmus/exchange courses with the transcript subject
LANGare retained with their actual recorded grade and credits. During review, identify whether the course is beginning/basic or higher-level. Language electives count as free electives only for programs whose degree rules permit them; FENS keeps them as effective N/A, where a letter grade can still affect CGPA. - At most two beginning/basic language courses receive free-elective and degree credit. Additional beginning/basic courses remain visible, including their recorded grade, but are labelled as excluded from degree credit. Higher-level language courses do not consume this two-course allowance.
- If you saved SIS pages as HTML only (instead of Webpage, Complete) and the file contains the known “no permission” page HTML, SUrriculum warns you to re-save correctly.
- If a PDF has no readable text layer, SUrriculum explains how to re-export it with the browser's Save as PDF, save Webpage, Complete HTML, or run OCR. Microsoft Print to PDF is a known source of image-only transcripts.
From the graduation/summary UI you can:
- Check graduation progress for your main major (and double major if selected).
- Open detailed summaries for majors and minors showing:
- Earned, current-term, future-planned, needs-grade, unsuccessful, and not-taken states
- Which requirements are satisfied or missing
- How overflow (upper → lower pool) courses are counted (color-coded)
- See earned and projected credit separately. Only the earned audit can report Complete; planned work can report Projected complete.
- See an Estimated class level based only on earned SU credits across the academic record, using the undergraduate thresholds: Freshman 0–33.99, Sophomore 34–63.99, Junior 64–93.99, and Senior 94 or more credits.
- See overall CGPA separately from the PGPA calculated for each selected program. Effective N/A courses remain in letter-grade CGPA but do not enter a program's PGPA.
- Count a posted successful current-term grade as earned immediately, including the period between grade publication and the application's next-term switch. Grades entered for future terms remain projections and cannot make the earned graduation audit pass.
Main-degree completion requires CGPA and main-program PGPA of at least 2.00. Double-major completion requires CGPA, main-program PGPA, and double-major PGPA of 3.20 (2.72 for pre-2019 admits). Minor completion requires CGPA and that minor's PGPA of 2.72, except Entrepreneurship at 2.50.
Open Scheduler from the sidebar. It is a SUchedule-style weekly grid that defaults to the current term and can switch between locally available schedule terms.
Key features:
- Search + browse courses for the selected scheduler term
- Pick section and place it on a compact weekday grid that adds weekend days or later hours only when the selected section or active preview needs them
- Corequisite bundling: courses with labs/recitations are treated as a bundle so you don’t “lose” the lab/recitation separately
- Time conflicts: overlapping classes render side-by-side instead of blocking each other
- Copy CRNs: copies the selected CRNs
- Update planner semester: replaces the courses in the matching planner semester with the scheduler’s selected main courses (labs/recitations are not added to the planner semester)
- Block hours:
- Enable block mode and click-drag to block time slots
- Courses that can’t fit around blocked hours can be filtered out, or optionally shown in red
- Optional helpers (toggles):
- Hide courses planned before the selected term
- Show course details in the list (credits/type)
- Check course prerequisites, including prior-SU and General Requirements rules, with an option to keep unmet courses visible
- Smart Sort (same scoring as the main planner)
- Hover preview (shows a translucent preview of how a course would look if added)
- Availability highlighting (taken / conflict-free / conflict-prone indicators)
Schedule data files:
- The scheduler reads from
courses/schedule/<TERM>.jsonl. - Course details also lazily read
courses/course_instructor_history.jsonl, which is derived from all saved schedule files. - Course details can also read
courses/course_section_history.jsonlfor per-section instructors and seat counts. - Generate/update these files using
python -m tools.data_pipeline.fetch_schedule(defaults to all terms from the current term onward, reconciles those offerings intocourses/all_coursepage_info.jsonl, and rebuilds derived history automatically).
Mobile note:
- The scheduler is usable on mobile, but works best in landscape.
- Some header actions collapse into a “…” menu on smaller widths.
- Transcript files are parsed inside your browser. SUrriculum does not upload the selected HTML or PDF, and it has no runtime analytics, telemetry, user account, or server-side plan storage.
- Plans, grades, custom courses, preferences, and scheduler selections are kept in this site's browser storage. The service worker may also cache the static application and public catalog data for offline use.
- Data does not automatically sync between browsers or devices. Export each important plan as a backup before clearing site data, resetting SUrriculum, or changing devices.
- PDF.js, Inter, and Font Awesome are served from this repository. The running application does not depend on a font, icon, or PDF-reader CDN.
- Public test fixtures in this repository are maintainer-owned or included with the contributor's consent. Choosing your own transcript in the application never adds it to the repository or publishes it.
Runtime ownership, module load order, state invariants, and the checklist for
adding a shipped script are documented in
docs/architecture.md. Keep index.html, the
service-worker shell, and the Pages artifact allowlist in sync.
Data is stored as .jsonl under courses/ and requirements/.
The active pipeline, release builder, and retained legacy utilities are grouped
under tools/ and are invoked as Python modules from the
repository root.
Install dependencies:
pip install -r requirements.txtUpdate course catalogs:
python -m tools.data_pipeline.fetch_coursesUpdate requirement rules:
python -m tools.data_pipeline.fetch_requirementsThe degree-detail scrapers reject successful HTTP responses unless the page's
displayed Admit Term exactly matches the requested YYYY01/02/03 term.
An unavailable-term fallback therefore cannot overwrite requirements. Complete
course-catalog rows merge into courses/terms.jsonl atomically while failed and
unrequested terms remain discoverable. Full minor-term refreshes publish only
after every selected minor succeeds; program-limited runs merge with the
existing snapshot instead of truncating it.
The 202601 IE degree summary was the first observed otherwise-valid page whose
Total ECTS cell contained an explicit dash while still publishing a valid
133-SU total. That may be a deliberate change in how newer curricula publish
requirements, not a source-data mistake. For compatibility with historical
undergraduate records, the scraper currently supplies 240 ECTS only when the SU
total is a valid positive integer and the ECTS cell is exactly a dash; blank,
zero, or malformed totals still fail closed. IE/202601 is therefore a reviewed
baseline, not proof that Total ECTS remains a published requirement.
For each newly refreshed admit term, record the set of majors whose Total ECTS
is an explicit dash. If that set differs from the reviewed baseline—especially
if a second 202601 major or any later admit term shows a dash—hold the generated
data PR for manual review, inspect all 12 undergraduate major pages for that
term, and compare them with the preceding term. If the omission is systematic,
verify the current university policy and update the schema, validation, and UI
to represent ECTS as unpublished or optional instead of continuing to
synthesize 240.
Scrape course pages for metadata (including prerequisite/corequisite and General Requirements rules, Basic Science/Engineering credit breakdowns, and “offered term” history):
python -m tools.data_pipeline.scrape_coursepagesThe same step also uses the newest program/minor catalog snapshots to fill
missing intrinsic fields after a verified scrape. For failed or unverified
course-page responses, it replaces intrinsic values with catalog-backed values
and clears any that cannot be verified. Program-specific classification fields
such as EL_Type and Faculty_Course remain in their program and admit-term
catalogs; they are never copied into the global course-page index.
Use python -m tools.data_pipeline.scrape_coursepages --refresh for a genuine full refresh of
existing records. Full refreshes bypass the local HTML cache; the automated data
workflow performs one every Monday and remains incremental on other days.
Requisite removals fail conservatively at field level. If an otherwise valid
course page changes a previously verified prerequisite or corequisite to an
empty value, the scraper retains the last known value, records the field in
retained_requisite_fields, and leaves the other freshly scraped metadata
intact. The reviewed retained-marker set is pinned by the data validation gate,
so every new disappearance requires inspection. Once a removal is confirmed as
intentional, accept it explicitly (the named course is fetched even during an
incremental run, bypasses the cache/work cap, and fails unless a valid fresh
page still shows the field as empty):
python -m tools.data_pipeline.scrape_coursepages \
--accept-requisite-removal DSA492:prerequisitesCommit an accepted removal together with the corresponding update to the
reviewed marker pin in tests/coursepage_requirements_data_test.py.
As of 2026-09-07, DSA 492 is the only provisional retention. SUIS now publishes
its 91 earned-SU General Requirement but returns an empty/malformed ordinary
prerequisite block, while the description still says prerequisite courses must
be completed. The previously published DSA201 AND (DSA210 OR CS210) rule is
therefore retained until repeated source evidence or university confirmation
shows that its removal was deliberate.
Regenerate the data manifest after any data update (no network requests). It
writes data/manifest.json, whose content-derived dataVersion keys the app's
service-worker cache — so returning users automatically pick up changed data, with
no manual cache bump:
python -m tools.data_pipeline.build_manifestUpdate schedule data from the current term onward:
python -m tools.data_pipeline.fetch_scheduleDaily schedule refreshes update section seat history in delta mode by default; use full mode when you explicitly want to refresh every current/future primary section detail page:
python -m tools.data_pipeline.fetch_schedule --section-history-mode fullScrape one specific term (or a custom list) instead:
python -m tools.data_pipeline.fetch_schedule --term 202502
python -m tools.data_pipeline.fetch_schedule --terms 202502,202503,202601Backfill historical schedule terms once (for example from Fall 2019 through the current term):
python -m tools.data_pipeline.fetch_schedule --from-term 201901Rebuild instructor history from already-downloaded schedule files without making any network requests:
python -m tools.data_pipeline.build_course_instructor_historyBackfill section-level seat history from already-downloaded schedule CRNs:
python -m tools.data_pipeline.build_course_section_history --all-terms --workers 8 --max-inflight 4Legacy JSON → JSONL migration (only needed if you still have .json files):
python -m tools.legacy.migrate_to_jsonl --delete-json- Graduation logic is complex: requirements are scraped and normalized, but edge cases exist. Always confirm with official program rules.
- Repeated attempts are represented as a planning replacement: when an exact
same-code course in an earlier term has a supported final grade, adding it to
a later term can offer a confirmed retake replacement.
F/U/NA/Ware accepted without a deadline; passingA-D(andS) use the three-regular-semester window, with Summer excluded from the count. The new attempt starts ungraded and the earlier planner card is removed. This is intentionally not complete attempt history: the university transcript retains both registrations, while SUrriculum keeps one.T, unfinished/unknown grades, future source terms, ambiguous duplicates, and different-code substitutions fail closed. Always verify official repeat eligibility and GPA replacement. The planner excludes Summer from its window count but cannot identify approved leave semesters, so it may conservatively decline a passing-grade repeat that the university would allow after leave. - PDFs need readable text: image-only files, including some Microsoft Print-to-PDF exports, must be re-exported with browser Save as PDF, saved as complete HTML, or processed with OCR.
- Scheduler scraping reliability: the university schedule endpoints can occasionally return server errors; re-run later or with delays.
- Minor rule parsing: minor pages vary; some rules are simplified into structured checks and may miss special cases.
- Browser verification is still asymmetric: the full automated browser suite focuses on Chromium; Firefox and WebKit run a smaller critical-flow gate.
- Post-3.1: replace full-page reloads for main-major, double-major, minor, and admit-term changes with one transactional in-place program switch. The switch should fetch and validate the next catalogs/requirements, atomically replace program state, recalculate and rerender every dependent view, and restore the previous state on failure. Whole-plan switching, import, reset, and deletion may keep their reload boundary because they change the active plan identity rather than only its academic configuration.
- More robust schedule scraping and section metadata (and smarter conflict-free suggestions).
- A first-class course-attempt model for retakes, repeated grades, and explicit substitutions.
- Richer course detail views (prerequisite parsing, nicer formatting, quick links).
- More term/year-aware rules for minors and program changes.
- Additional planner UX polish and small guidance popups.
- Optional recommendations and planning helpers.
This repository started as a fork of the original Surriculum project: https://github.com/melih-kiziltoprak/surriculum
Maintained by BEFICENT (Bilal M. G.) with major additions including double major support, Data Science and Analytics and several FASS programs, a large UI overhaul, updated course lists, improved requirement checks, multi-plan support, minor support, and the term-selectable scheduler.
This project is licensed under the GNU General Public License v3.0 (GPL-3.0).
See LICENSE.