# TimeToLeave > Know when to leave the house so you're never late for your next meeting. TimeToLeave is a web app that tells you **when to leave** for upcoming events based on real-time Austrian train (ÖBB) schedules — and optionally compares train journeys with bicycle routes. ## Features - **Real-time train journeys** — Query the ÖBB HAFAS API for live departure times, delays, and platform information. - **Calendar import** — Import events from any ICS calendar (CalDAV, Google Calendar, etc.). - **Bicycle routing** — Compare train journeys with bicycle routes powered by OSRM, including distance, duration, and turn-by-turn directions. - **Train vs bicycle comparison** — See both travel modes side by side for each event, so you can decide what works best. - **Calendar month view** — Browse events in a month grid, see event indicators on dates, and drill into train/bike details per day. - **Geolocation support** — Use your browser's current location as the origin station. - **Countdown & status indicators** — Visual countdown timers and live status badges so you know exactly when to go. ## Architecture Built with **Next.js App Router** (v16), **React 19**, **TypeScript**, and **Tailwind CSS v4**. ``` src/ ├── app/ # Next.js App Router pages & layout │ ├── api/ # Server-side API routes │ │ ├── hafas/ # ÖBB train journey search │ │ ├── calendar/ # ICS calendar parsing │ │ ├── geocode/ # Nominatim geocoding │ │ ├── bike-route/ # OSRM bicycle routing │ │ └── health/ # Server health check │ ├── ui/ # Shared UI components │ ├── page.tsx # Home page │ └── layout.tsx # Root layout ├── hooks/ # Custom React hooks │ ├── useJourneys.ts # Fetch train journeys per event │ ├── useBikeRoute.ts # Fetch bicycle routes │ ├── useCalendar.ts # Calendar import & parsing │ ├── useEventsStore.tsx # Events state management │ ├── useGeolocation.ts # Browser geolocation │ ├── useOriginStation.ts # Origin station selection │ ├── useClock.ts # Live clock for countdowns │ └── useServerHealth.ts # API health monitoring ├── lib/ # Shared utilities & clients │ ├── hafas-client.ts # ÖBB HAFAS API client │ ├── geocoding-client.ts # Nominatim geocoding client │ ├── bike-routing-client.ts# OSRM bicycle routing client │ ├── calendar-utils.ts # ICS parsing utilities │ ├── countdown-utils.ts # Countdown time calculations │ ├── formatting.ts # Date/time formatting helpers │ └── constants.ts # App-wide constants ├── types/ # TypeScript type definitions └── test/ # Test utilities ``` ## Getting Started ### Prerequisites - Node.js 20+ - npm (or yarn / pnpm) ### Installation ```bash npm install ``` ### Development ```bash npm run dev ``` The app will be available at [http://localhost:3000](http://localhost:3000). ### Build & Start ```bash npm run build npm start ``` ### Docker Deployment Build and run with Docker Compose: ```bash docker compose up --build -d ``` The app will be available on port `3000` by default. Override the port or any other variable by creating a `.env` file at the project root: ```env PORT=8080 HAFAS_URL=https://fahrplan.oebb.at/bin/mgate.exe NOMINATIM_URL=https://nominatim.openstreetmap.org NOMINATIM_USER_AGENT=TimeToLeave/2.0 OSRM_URL=https://router.project-osrm.org ``` The `Dockerfile` uses a 3-stage build (deps → builder → runner) with `output: "standalone"`, producing a small final image that runs as a non-root user. Stop and remove the container with `docker compose down`. ### Testing ```bash npm test # Run tests once npm run test:watch # Run tests in watch mode ``` ### Linting & Type Checking ```bash npm run lint npm run typecheck ``` ## Environment Variables The following environment variables can be configured (defaults are provided for development): | Variable | Description | Default | |----------|-------------|---------| | `HAFAS_URL` | ÖBB HAFAS API endpoint | `https://fahrplan.oebb.at/bin/mgate.exe` | | `NOMINATIM_URL` | Nominatim geocoding endpoint | `https://nominatim.openstreetmap.org` | | `NOMINATIM_USER_AGENT` | User-Agent for Nominatim requests | `TimeToLeave/2.0` | | `OSRM_URL` | OSRM routing endpoint | `https://router.project-osrm.org` | ## Tech Stack | Category | Technology | |----------|-----------| | Framework | [Next.js 16](https://nextjs.org/) (App Router) | | UI | [React 19](https://react.dev/) + [Tailwind CSS v4](https://tailwindcss.com/) | | Language | [TypeScript 5](https://www.typescriptlang.org/) | | Train Data | [ÖBB HAFAS API](https://fahrplan.oebb.at/) | | Geocoding | [Nominatim](https://nominatim.openstreetmap.org/) | | Bicycle Routing | [OSRM](https://project-osrm.org/) | | Calendar | [node-ical](https://www.npmjs.com/package/node-ical) | | Dates | [date-fns](https://date-fns.org/) | | Testing | [Vitest](https://vitest.dev/) + [React Testing Library](https://testing-library.com/) | ## How It Works 1. **Add events** — Manually enter events or import from an ICS calendar URL. 2. **Pick an origin** — Use your current location or search for a departure station. 3. **Get journey info** — The app queries ÖBB for real-time train schedules and optionally calculates bicycle routes via OSRM. 4. **Decide when to leave** — Each event shows a countdown, the best available train, and (if enabled) a bicycle alternative with estimated travel time. ## License MIT