If you are new to the codebase, start here for the responsibilities and interactions of the main components. The Course Data Architecture explains the data flows and publication boundaries in greater detail.

This page describes Sisukas as a running system: what each component owns, which data crosses component boundaries, and how those choices affect course discovery and planning. For the underlying planning models and algorithms, see Planning Architecture.

What Sisukas Is (Technically)#

Sisukas is a client-heavy course-planning application for Aalto students. It supports exploratory browsing and schedule comparison before registration in SISU, rather than replacing SISU as the system where students register for courses.

The frontend does much of the interactive work: it loads and indexes published course catalogues, filters courses, and manages planning interfaces. Backend services handle persistent user data, authentication and authorization, and computations that are exposed as APIs. SISU teaching information is retrieved separately when it is needed. That separation matters because a published catalogue, an upcoming lecture time, and a student’s saved plan have different freshness and ownership requirements.

The system is designed to remain responsive when large catalogue files have been cached, but it is not fully offline: live teaching data, authenticated persistence, and uncached content still depend on network services.

Core Components#

The main components are independently deployed or operated and have distinct responsibilities.

Frontend (Course Browser)#

Location: frontend/course-browser/

The Svelte frontend presents course discovery, search and filtering, academic-year and curriculum views, planning interfaces, study-group selection, schedule comparison, and other user-facing workflows. It builds searchable indexes from active and historical course catalogues and caches large published files in IndexedDB, with hash-based background revalidation.

When detailed teaching information is required, the frontend calls sisu-wrapper for study groups, offerings, and events rather than relying on the scheduled catalogue for live scheduling data. It can also retrieve runtime course snapshots from the main backend to supplement historical discovery when a course is missing from the published catalogue.

IndexedDB caching improves responsiveness and resilience, but does not guarantee complete offline operation or immediate freshness. A cached catalogue may be usable while network-dependent operations are unavailable. Likewise, cached teaching details should not be confused with a promise that upstream schedules never change.

Main Backend API#

Location: backend/

The Express backend exposes authenticated resources such as plans, favourites, grades, and transcript import, as well as analytics and course-snapshot endpoints. It uses Better Auth for user sessions and Drizzle with PostgreSQL for persistence. Middleware establishes session context; protected routes also need resource-specific authorization checks. A separate administrative token mechanism protects designated admin operations.

Schedule analytics are performed through backend endpoints using submitted planning and event data. This is different from fetching the current SISU teaching schedule: the browser can request teaching data through the wrapper, while analytics operate on the data provided for a calculation.

The backend also participates in missing-course recovery. Its POST /api/course-snapshots/resolve route calls the wrapper’s course-resolution endpoint and persists eligible results as expiring PostgreSQL snapshots. Accordingly, it is not correct to say that the backend never contacts sisu-wrapper.

The backend does not run the scheduled canonical catalogue publication workflow. Database-backed state, runtime snapshot records, and published catalogue files have separate lifecycles.

Filters API#

Location: filters-api/

The filters API is a small service for saving and resolving shareable filter configurations. A saved configuration is identified by a stable identifier that can be embedded in a URL. Unlike a saved plan, it is not modeled as user-owned planning state; the identifier is used to retrieve the filter definition.

This service is deliberately separate from authenticated plan persistence and from schedule computation. Its role is to make sets of filtering choices shareable and recoverable without mixing them with a student’s personal plan.

SISU Wrapper#

Location: sisu-wrapper/

The FastAPI wrapper adapts data from SISU Kori into endpoints consumed by Sisukas. It provides study-group and offering details for scheduling and supports course-code resolution for missing-course recovery. The frontend calls the wrapper directly for on-demand teaching information; the backend calls its resolution endpoint when creating runtime snapshots.

This path is time-sensitive and may fail independently of the last successfully published course catalogue. The wrapper is an adapter to an external source, not the canonical course catalogue store.

Course Data Pipeline (Batch System)#

Locations: scripts/, .github/workflows/check_course_updates.yml

A separate GitHub Actions workflow fetches course realisations from the Aalto Course API, transforms and validates the results, and reconciles them against the previously published catalogue. The reconciliation step accounts for removals, reactivations, and historical archive candidates, including safeguards against unexpectedly large archive transitions. Validated active and historical datasets, hashes, and related artifacts are published to Google Cloud Storage (GCS).

The workflow is scheduled daily and also supports the configured push and manual triggers. Its processing occurs outside ordinary user requests: browsing a course or viewing a schedule does not start the publication job. Conversely, the pipeline does not require the browser or backend to be active to publish a new catalogue.

The previous published datasets are inputs to reconciliation, so this process is not simply an unconditional overwrite using the latest upstream response. See Data Pipeline for the operational sequence.

External Systems and Storage#

Aalto’s Course API supplies course-realisations data for scheduled ingestion. SISU Kori supplies teaching details and course relationships used by the runtime wrapper and historical discovery. GCS distributes the published active and historical catalogues to browsers. PostgreSQL stores application data and runtime course snapshots. Curriculum metadata is also curated in YAML and review data; it does not originate automatically from the daily course-data fetch.

The components share information but do not share one universal data source of truth.

Data Classes (Critical Distinction)#

Data classExamplesHow it is obtainedLifecycle and authority
Published catalogueActive courses.json, historical historical.jsonAalto Course API → validation/reconciliation → GCSCanonical published Sisukas catalogue; versioned through publication and hash updates
Runtime teaching detailsStudy groups, offerings, teaching eventsSISU Kori → sisu-wrapper → frontendTime-sensitive; requested as needed and potentially changed upstream
Runtime recovery snapshotsResolved missing course instancesSISU Kori → wrapper → backend → PostgreSQL → frontendExpiring, best-effort supplementary records; not automatically canonical
Curriculum metadataProgramme/module membership and curated referencesRepository YAML and review processIndependently maintained metadata used for discovery and validation
User-owned statePlans, favourites, gradesAuthenticated frontend ↔ backend ↔ PostgreSQLPersistent, user-scoped; requires access checks
Shareable filtersSaved filter definitionsFrontend ↔ filters APIAddressable by identifier; distinct from user-owned plans
Derived resultsConflict analytics, schedule rankingsBackend computation from supplied planning dataRecomputed; not an independent upstream source

“Canonical” here refers to the published Sisukas course catalogue, not to the claim that a cached or normalized record is always the most up-to-date information available from Aalto. The wrapper and runtime snapshots serve different purposes and should not silently overwrite that catalogue.

How the System Is Used (End-to-End)#

Different user actions cross different boundaries. A course search should not require the same services as an authenticated plan update or a live schedule lookup.

1. Course Discovery (Primarily Client-Side)#

The frontend downloads the published active and, when needed, historical catalogue from GCS. The loader uses IndexedDB to reuse previously downloaded data and checks hashes for updates. Course parsers validate entries, and frontend stores build the indexes used for browsing and filtering.

Curated curriculum metadata influences programme- and module-based views. Routine catalogue filtering does not require a backend query for every search interaction. A first-time load still depends on obtaining the published files over the network; a previously cached copy may be older than the latest publication.

2. Planning and Persistence (User-Scoped and Shareable State)#

For authenticated planning data, the frontend submits requests to the main backend. Session middleware identifies the user, route handlers check authorization, and PostgreSQL persists the user-scoped records. The frontend updates its presentation from the resulting application state.

Shareable filter configurations are different: they are saved through the filters API and recovered using a URL identifier. They are not the same kind of resource as an authenticated plan and should not inherit the plan’s ownership assumptions.

Transcript import and grade storage are also backend responsibilities, illustrating why the main backend should not be described merely as a scheduling calculator.

3. Live Scheduling and Evaluation#

When the user inspects teaching details or needs study-group choices, the frontend requests information through sisu-wrapper. The frontend’s normalized study-group/event models are then used to prepare scheduling interactions. The backend’s analytics endpoints can evaluate supplied selections for conflicts and rankings without being responsible for refreshing SISU teaching information on every calculation.

Avoid a blanket invariant that teaching information is fetched exactly once per course instance: caching and refresh behavior should be established from the relevant store and service implementation. What matters architecturally is the separation between obtaining teaching data and deriving schedule results from it.

4. Recovery of Missing Courses#

When a course is absent from the published datasets, the backend can resolve the code through sisu-wrapper and store eligible returned records in PostgreSQL with an expiry period. The frontend can merge supported snapshots into its historical index on a best-effort basis.

A successful runtime recovery does not automatically add the course to historical.json on GCS. Canonical publication and historical maintenance use separate procedures, and the proposed delayed promotion workflow should not be mistaken for a deployed daily job.

Runtime vs. Batch Systems#

CategoryComponentsWhen it runs
Scheduled / batchGitHub Actions course ingestion and publicationDaily or configured/manual triggers, independently of user sessions
Runtime (browser)Course browsing, filtering, planning UI, IndexedDB cachingDuring user interaction and frontend loading
Runtime (server)Main backend, filters API, sisu-wrapperOn API requests; services may persist records even if request handlers are short-lived
ExternalAalto Course API, SISU KoriAccessed by the scheduled pipeline or the runtime wrapper according to purpose

The distinction is both temporal and functional. A published catalogue can remain available even if live SISU teaching endpoints temporarily fail; conversely, updating teaching details does not require rebuilding the entire course catalogue.

Authority vs. Derivation#

There is no single authority for every piece of information in a plan.

CategoryExamplesHow to interpret it
Upstream sourceAalto course realisations, SISU teaching eventsProvided by external systems and normalized by Sisukas
Published canonical dataActive/historical GCS cataloguesValidated and published Sisukas view of course records
User-authored stateSaved plans, selected groups, gradesUser-scoped state persisted by the application
Supplementary recovery dataRuntime course snapshotsNoncanonical records that can help restore missing course references
Derived computationConflicts, analytics, existing schedule-pair rankingsOutputs calculated from available plan and teaching inputs; the broader assembler is proposed
Proposed calendar decisionsActive courses, group preferences, attendance overridesPlanned user-owned state, not an implemented persistence contract

Derived results should expose scheduling trade-offs rather than silently decide them for a user. For details on what has been implemented and what remains a design proposal, consult the corresponding Concepts and Planning Architecture pages.

What Sisukas Explicitly Does Not Do#

Sisukas does not register students for courses in SISU, guarantee that all teaching information is up to date without a refresh, or silently resolve every scheduling conflict. It is designed as a complementary planning workspace. Likewise, a runtime snapshot is not a substitute for the validated catalogue publication process.

These limits are deliberate boundaries, not merely missing UI features: Sisukas owns the planning experience, while registration and original academic records remain with the relevant Aalto systems.

Last updated: