HFU Digital Docs
CourseKitStarPlan

StarPlan Package

Framework-agnostic StarPlan ingestion — iCal parsing, RRULE normalization, content-hash change detection, room/instructor extraction, and study-block alignment

@hfu.digital/coursekit-starplan is the third package in CourseKit. It's framework-agnostic (no NestJS, no React, no Prisma) and contains the building blocks for ingesting an institution's StarPlan timetable feed and producing data that the backend (@hfu.digital/coursekit-nestjs) can store and materialize.

NestJS consumers typically wrap this package inside a service that orchestrates:

  1. Fetch programs/semesters via StarPlanClient (or your own HTTP layer)
  2. Fetch each semester's iCal feed
  3. Parse it with parseIcal
  4. Normalize each event's rrule with normalizeRrule
  5. Extract structured room / instructor metadata with the extractors
  6. Compute a stable contentHash to detect changes across syncs
  7. Diff against the previous snapshot with detectChanges
  8. Persist the result via your CourseKit Prisma adapter

Install

bun add @hfu.digital/coursekit-starplan@2026.04.1

This package has one runtime dependency: rrule (used inside normalizeRrule). It works in Node.js and modern browsers.

Public surface

ModuleExports
clientStarPlanClient, StarPlanClientOptions, StarPlanProgram, StarPlanSemester
parserparseIcal, ParsedVEvent, ParseIcalOptions, groupBySchedule, groupBySummary
recurrencenormalizeRrule, isValidRrule, NormalizedRecurrence
extractorsextractRoom, ExtractedRoom, RoomExtractorConfig, extractInstructor, InstructorExtractorConfig
identitygenerateContentHash, hashIcalFeed
study-blocksHFU_STUDY_BLOCKS, HFU_STUDY_BLOCK_CONFIG, StudyBlock, StudyBlockConfig, getStudyBlockFromTime, getStudyBlockTimeRange
changesdetectChanges, ChangeAction, ChangeRecord, DetectChangesOptions

Quick example

import {
    StarPlanClient,
    parseIcal,
    normalizeRrule,
    extractRoom,
    extractInstructor,
    generateContentHash,
    hashIcalFeed,
    detectChanges,
} from '@hfu.digital/coursekit-starplan';

const client = new StarPlanClient({
    baseUrl: 'https://splan.hs-furtwangen.de',
    planningUnit: '5',
});

const semesters = await client.fetchSemesters('SOME_PROGRAM_ID');
const ical = await client.fetchIcal(semesters[0].id);

if (hashIcalFeed(ical) === lastSeenIcalHash) return; // no change

const events = parseIcal(ical).map((ev) => ({
    id: generateContentHash({
        semesterId: semesters[0].id,
        summary: ev.summary,
        weekday: ev.weekday,
        studyBlock: ev.studyBlock,
        startTime: ev.dtstart,
    }),
    title: ev.summary,
    startTime: ev.dtstart,
    rrule: ev.rrule ? (normalizeRrule(ev.rrule)?.normalized ?? null) : null,
    room: extractRoom(ev.location),
    instructor: extractInstructor(ev.description),
}));

const diff = detectChanges('starplan-event', previousSnapshot, events);

When to use this package

  • You sync from HFU StarPlan (or any iCal-based timetable feed) into a CourseKit-backed schedule.
  • You want change detection that survives the upstream changing iCal UID values.
  • You want HFU's six-block daily grid out of the box, or you need a configurable equivalent for another institution.

On this page