Problem
The scheduler currently requires login to use. Every plan is saved to the DB and identified by a planId in the URL. This means users who aren't signed in can't use the scheduler at all, which is a barrier to entry — ideally a user should be able to explore the scheduler and generate schedules before committing to creating an account.
Additionally, all plan state currently flows through the DB. There's no clean separation between "persisting a plan" and "managing filter state", which makes the codebase harder to extend and causes prop drilling throughout the component tree.
Solution
Introduce a guest flow where the URL is the source of truth instead of the DB, and extract plan persistence logic into a usePlanPersistence hook that abstracts over both flows. Components should be unaware of which flow is active.
- Logged in — plan loads from DB on mount, changes autosave to DB, URL always reflects current state
- Guest — all state lives in URL params, no DB writes, refresh restores state from URL
In both flows, the URL should always be kept in sync with the current state by the hook. The URL is the single source of truth for what the user sees — the DB is just a persistence layer that mirrors it for logged in users.
Deliverables
usePlanPersistence hook owning plan loading, autosave, and guest vs logged in decision
- Guest flow working end to end including login transition
generator/page.tsx and AddCoursesModal updated to handle both URL schemas
Notes
usePlanPersistence could possibly depend on creating a useSchedulerFilters hook for filters and setFilters. If useSchedulerFilters has not yet been extracted from SchedulerWrapper, that work should be done as part of this ticket first. (Ofc only if deemed to be needed).
- A minimal
SchedulerContext providing planId and isGuest is acceptable if prop drilling becomes painful during implementation. Full context is a separate future ticket.
Problem
The scheduler currently requires login to use. Every plan is saved to the DB and identified by a
planIdin the URL. This means users who aren't signed in can't use the scheduler at all, which is a barrier to entry — ideally a user should be able to explore the scheduler and generate schedules before committing to creating an account.Additionally, all plan state currently flows through the DB. There's no clean separation between "persisting a plan" and "managing filter state", which makes the codebase harder to extend and causes prop drilling throughout the component tree.
Solution
Introduce a guest flow where the URL is the source of truth instead of the DB, and extract plan persistence logic into a
usePlanPersistencehook that abstracts over both flows. Components should be unaware of which flow is active.In both flows, the URL should always be kept in sync with the current state by the hook. The URL is the single source of truth for what the user sees — the DB is just a persistence layer that mirrors it for logged in users.
Deliverables
usePlanPersistencehook owning plan loading, autosave, and guest vs logged in decisiongenerator/page.tsxandAddCoursesModalupdated to handle both URL schemasNotes
usePlanPersistencecould possibly depend on creating auseSchedulerFiltershook forfiltersandsetFilters. IfuseSchedulerFiltershas not yet been extracted fromSchedulerWrapper, that work should be done as part of this ticket first. (Ofc only if deemed to be needed).SchedulerContextprovidingplanIdandisGuestis acceptable if prop drilling becomes painful during implementation. Full context is a separate future ticket.