Skip to content
prbhagamPublic

About

A travel management system for Europe Study Abroad students juggling delayed train schedules with academic commitments.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Clockwork

An academic-aware travel planner for Georgia Tech-Europe students.

Standard map and booking apps optimize for the cheapest or fastest route. Clockwork optimizes for the one thing that actually matters to a student on a weekend trip: getting back in time for class, rested, even if a train runs late.

It plans your trip backward from your next class or deadline — scoring every itinerary for academic risk, flagging tight connections, thin buffers, reservation traps, and last-train risk, and always showing you a backup.


What it does

  • Manage academic commitments — recurring classes and one-off deadlines/exams.
  • Plan both legs of a weekend trip — choose your outbound and return trains independently, from any origin (not just your home base).
  • Risk scoring on both ends — each itinerary gets a Safe / Tight / Risky / Won't-make-it badge and a 0–100 safety score, driven by:
    • Deadline buffer — arrival + station→campus time vs. your commitment.
    • Delay-adjusted arrival — a pessimistic delay model re-checks the deadline.
    • Connection risk — flags dangerously short transfers.
    • Last-train / no-fallback — warns when there's no later train if this one is disrupted, and surfaces the latest safe departure.
    • Reservation traps — high-speed trains (TGV/AVE/…) your pass covers but that still need a paid, sellable seat reservation.
    • Schedule conflicts — flags commitments you'd still be travelling through, on either leg.
    • Readiness — late-night arrivals before an early commitment.
  • Backup routes — earlier fallbacks for the recommended return.
  • Live or offline data — swap between a curated offline dataset and live European rail data with one env var.

Architecture

Next.js 16 (App Router) + React 19 + TypeScript, Tailwind 4
├── src/app/            UI (Server Components) + Server Actions + /api/stations
├── src/lib/            auth (jose JWT cookie + bcrypt), Prisma client, guards, actions
└── src/core/           framework-agnostic domain (unit-tested, no Next/React)
    ├── providers/      TrainProvider interface → SeedProvider | TransitousProvider
    ├── risk.ts         the risk engine (assessRisk + assessOutbound)
    ├── conflicts.ts    schedule-clash detection
    ├── planner.ts      arrive-by / forward search + ranking + id resolution
    └── ...             stations, pass-rules, time helpers

The domain logic in src/core/ has no framework imports, so the risk engine is unit-testable in isolation and the data provider is swappable.

Train data

There is no official Eurail/Interrail timetable API — a pass is simply valid on most trains. So data flows through a TrainProvider interface:

  • SeedProvider (default) — offline, deterministic. Synthesizes journeys from ~14 Berlin corridors in src/data/seed/corridors.ts. Used in tests/CI and for demos.
  • TransitousProvider — live data from Transitous (a public, community-run MOTIS instance). Wrapped in a FallbackProvider that automatically degrades to the seed dataset on any error.

Deutsche Bahn's own endpoints (db-vendo-client) are intentionally not used — DB hard-blocks unofficial clients (OPS_BLOCKED). Transitous is openly documented (but requires a descriptive User-Agent).

Station ids are provider-specific (seed uses IBNR ids; Transitous uses MOTIS ids). The planner resolves a leftover seed id to the active provider by name at plan time, so switching providers doesn't break existing home bases.

Auth & database

  • Custom credentials auth: bcrypt password hashing + a signed jose JWT in an httpOnly cookie (no NextAuth).
  • Prisma 6 with SQLite for development (prisma/schema.prisma). For production, change the datasource provider to postgresql and point DATABASE_URL at a Postgres instance.

Getting started

npm install
npx prisma db push      # create the SQLite dev database
npm run seed:user       # optional: demo@gatech.edu / password12345
npm run dev

Open http://localhost:3000.

Live data

TRAIN_PROVIDER=transitous npm run dev

When switching to live data, re-pick your stations via the search typeahead (or set your home base in onboarding) so ids match the active provider.

Environment variables

Variable Default Notes
DATABASE_URL file:./dev.db SQLite for dev; a Postgres URL for production.
AUTH_SECRET dev placeholder Change in production — signs session cookies.
TRAIN_PROVIDER seed seed (offline) or transitous (live, with seed fallback).
TRANSITOUS_BASE api.transitous.org Override the MOTIS endpoint if needed.

See .env for the full list.

Scripts

Command What it does
npm run dev Start the dev server.
npm run build Production build (also typechecks all routes).
npm test Vitest unit suite (risk engine, providers, conflicts).
npm run db:push Sync the Prisma schema to the database.
npm run db:studio Open Prisma Studio.
npm run seed:user Create a demo user with sample commitments.

Testing

npm test

The suite (20 tests) covers the risk-engine truth tables (buffer thresholds, connection detection, delay-adjusted flips, last-train, reservation flagging), seed-provider arrive-by correctness, conflict detection, outbound scoring, and live→seed fallback. It always runs against the seed provider, so it never depends on a live upstream.

Notes for developers

  • After any prisma db push / schema change, restart the dev server — Next's hot reload doesn't re-require the regenerated Prisma client, so an old client stays cached and rejects new columns.
  • To stop a backgrounded dev server: lsof -ti tcp:3000 | xargs kill.

Roadmap

  • .ics calendar import for commitments
  • Google OAuth
  • Delay-history tuning from real data
  • Shareable trip view

About

A travel management system for Europe Study Abroad students juggling delayed train schedules with academic commitments.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages