PROJECT / 2025
LiTHePlan
LIU Course Planner
Course planning tool for Linköping University master's students. Browse 339 courses across 15 civil engineering programs, build validated 90hp study plans, and share profiles with advisors.
- stack
- TypeScript · Next.js 16 · React 19 · Tailwind CSS v4 · shadcn/ui · Supabase · PostgreSQL · Upstash Redis · Zod v4 · @hello-pangea/dnd · Sentry · Playwright
How it works
courses
339 courses, 15 programsyour plan
pick 90 creditschecks
overlaps and exclusionsshare
a profile for your advisor

01 / Overview
An unofficial course planning tool for civil engineering master's students at LiU. Course info for terms 7-9 is normally scattered across multiple university portals — LiTHePlan pulls 339 courses into one place with filtering, scheduling conflict detection, and degree requirement validation. Users can build study plans as guests (localStorage) or sign in for cloud sync and shareable profile URLs.
02 / Key features
- –Multi-faceted filtering: term, block, pace, campus, program, subject area, and examination type — with filter state persisted to localStorage and deep-linkable via URL params
- –Dual conflict detection: scheduling overlaps (block collisions within a period, with special handling for 50%-pace courses) and mutual exclusion parsing from bilingual free-text course notes
- –Profile builder with drag-and-drop (hello-pangea/dnd) for organizing courses across terms 7-9, plus real-time validation against 90hp total and 60hp advanced-level requirements
- –Hybrid storage: guests get full functionality via localStorage, authenticated users get Supabase cloud sync with realtime subscriptions and automatic fallback
- –Related course recommendations powered by a PL/pgSQL scoring function (weighted by program overlap, subject area, level, and campus)
- –Cmd+K command palette for fast course search and navigation across the app
03 / Challenges
- –Swedish university scheduling is surprisingly complex: courses span multiple terms, periods, and blocks at different paces (50%/100%), and the combinations create a tricky constraint space for conflict detection
- –Course restriction data lives in unstructured bilingual free-text notes — parsing mutual exclusions from Swedish and English sentences reliably required careful regex work
- –Making the profile system feel seamless whether you're a guest or signed in, with localStorage and Supabase sync staying consistent without the UI caring which backend is active
04 / Solution
Built with Next.js 16 and React 19 on Supabase (Postgres + Auth + Realtime). The API layer uses Zod v4 for strict input validation and Upstash Redis for per-IP rate limiting. Conflict detection runs two separate systems: one checks block-level scheduling overlaps with special 50%-pace logic, another parses the notes field with regex for mutual-exclusion phrases in Swedish and English. Profile state goes through a useReducer-based context that abstracts over localStorage and Supabase, so components never know where the data lives. Course recommendations use a PL/pgSQL function with weighted scoring (program overlap, subject area, level, campus) to avoid sorting in the application layer. RLS policies lock down personal data while still allowing shared profile viewing.
05 / Outcome
Live at litheplan.tech. Students can browse all 339 master's courses for civil engineering, build 90hp study plans with real-time conflict checking and requirement validation, and share their profiles with advisors via URL. The hybrid storage model means zero sign-up friction — guests get the full experience, and signing in just adds cloud persistence and sharing.
06 / Screens
01 / 04



