114 lines
5.2 KiB
Markdown
114 lines
5.2 KiB
Markdown
# Development Guide
|
|
|
|
## Prerequisites
|
|
|
|
- Node.js 20 or newer
|
|
- npm 9 or newer
|
|
- Android Studio or Xcode for native mobile builds
|
|
- Expo/EAS tooling when building or submitting mobile apps
|
|
|
|
## Install
|
|
|
|
```bash
|
|
npm install
|
|
cp .env.example .env
|
|
```
|
|
|
|
The root workspace owns dependency installation. Avoid installing separately inside workspaces unless you are intentionally changing that workspace's dependency list.
|
|
|
|
## Environment
|
|
|
|
| Variable | Default | Purpose |
|
|
| --- | --- | --- |
|
|
| `PORT` | `3000` through Next dev defaults | Web server port when the runtime honors it. |
|
|
| `HAFAS_URL` | `https://fahrplan.oebb.at/bin/mgate.exe` | ÖBB HAFAS endpoint. |
|
|
| `HAFAS_TIMEOUT_MS` | `10000` | HAFAS request timeout. |
|
|
| `HAFAS_VER`, `HAFAS_LANG`, `HAFAS_AID`, `HAFAS_CLIENT_*` | ÖBB app-compatible defaults | HAFAS request envelope metadata. |
|
|
| `NOMINATIM_URL` | `https://nominatim.openstreetmap.org` | Geocoding endpoint. |
|
|
| `NOMINATIM_USER_AGENT` | `TimeToLeave/2.0` | Required Nominatim user agent. |
|
|
| `OSRM_URL` | `https://router.project-osrm.org` | Bike and foot routing base URL. |
|
|
| `WIENER_LINIEN_API_URL` | `https://api.wienerlinien.at/darwin-v2` | Wiener Linien live data base URL. |
|
|
| `OEBB_GTFS_URL` | ÖBB 2026 GTFS ZIP | Optional HAFAS response enrichment source. |
|
|
| `CORS_ALLOWED_ORIGINS` | `http://localhost:3000` fallback | Allowed browser origins for `/api/*`. |
|
|
| `API_RATE_LIMIT_MAX_REQUESTS` | `120` | Per-IP API requests per window. |
|
|
| `API_RATE_LIMIT_WINDOW_MS` | `60000` | Rate-limit window length. |
|
|
| `DEPLOYMENT_URL` | local fallback in OAuth code | Public app URL for Google OAuth redirects. |
|
|
| `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `GOOGLE_REDIRECT_URI` | none | Enables Google Calendar sync. |
|
|
| `APP_VERSION` | `0.1.0` | Version returned by `/api/health`. |
|
|
| `EXPO_PUBLIC_API_BASE_URL` | empty | Mobile backend URL. Required for physical devices unless the empty base URL is intentionally proxied. |
|
|
|
|
## Commands
|
|
|
|
| Command | Description |
|
|
| --- | --- |
|
|
| `npm run dev` | Start the web app with `next dev`. |
|
|
| `npm run build` | Build the web app. |
|
|
| `npm run start` | Start the built web app. |
|
|
| `npm run dev:mobile` | Start the Expo dev server. |
|
|
| `npm run android` | Run the Expo app on Android from the root script. |
|
|
| `npm run ios` | Run the Expo app on iOS from the root script. |
|
|
| `npm run lint` | Run ESLint across web, mobile, core, and api-client. |
|
|
| `npm run typecheck` | Run TypeScript checks across all workspaces. |
|
|
| `npm run test` | Run web Vitest tests and mobile Jest tests. |
|
|
|
|
Workspace-specific examples:
|
|
|
|
```bash
|
|
npm run test -w apps/web
|
|
npm run test -w apps/mobile
|
|
npm run typecheck -w packages/core
|
|
npm run typecheck -w packages/api-client
|
|
```
|
|
|
|
## Web Routes
|
|
|
|
| Route | Description |
|
|
| --- | --- |
|
|
| `/` | Departure desk with next upcoming event, train/bike mode selector, live journeys, route sections, reminders, and nearby Wiener Linien departures. |
|
|
| `/calendar` | Calendar import/management with URL, file, Google OAuth, and batch destination editing. |
|
|
|
|
The web add/edit event flow is implemented by `apps/web/src/app/add-event/AddEventModal.tsx`, not a standalone route.
|
|
|
|
## API Routes
|
|
|
|
| Endpoint | Methods | Notes |
|
|
| --- | --- | --- |
|
|
| `/api/health` | `GET` | Returns `{ ok, ts, version }`. |
|
|
| `/api/hafas` | `GET`, `POST` | GET is a simple trip search. POST validates and forwards `TripSearch` or `LocMatch`. |
|
|
| `/api/geocode` | `GET` | Requires `name`; optional `countrycodes`. Returns the first result. |
|
|
| `/api/bike-route` | `GET` | Requires `fromLat`, `fromLng`, `toLat`, `toLng`. |
|
|
| `/api/walk-route` | `GET` | Same coordinate contract as bike route, using OSRM foot profile. |
|
|
| `/api/calendar` | `GET` | Requires an allowed remote ICS `url`; optional `days`. |
|
|
| `/api/calendar/parse` | `POST` | Parses raw ICS text from the request body. |
|
|
| `/api/calendar/google` | `GET` | Requires Google OAuth token cookie; optional day horizon. |
|
|
| `/api/auth/google` | `GET` | Starts OAuth. |
|
|
| `/api/auth/google/callback` | `GET` | Completes OAuth. |
|
|
| `/api/auth/google/status` | `GET` | Reports configuration and connection state. |
|
|
| `/api/auth/google/disconnect` | `POST` | Clears OAuth token cookie. |
|
|
| `/api/wienerlinien/stops` | `GET` | Requires `lat`, `lng`; optional `radius`, capped server-side. |
|
|
| `/api/wienerlinien/monitor` | `GET` | Accepts repeated `stopIds`, capped server-side. |
|
|
|
|
## Docker
|
|
|
|
The web app includes Docker support:
|
|
|
|
```bash
|
|
cd apps/web
|
|
docker-compose up --build
|
|
```
|
|
|
|
## Testing Notes
|
|
|
|
- Web tests use Vitest, jsdom, and Testing Library.
|
|
- Mobile tests use Jest, jest-expo, and React Native Testing Library.
|
|
- Route, geocoding, HAFAS, calendar, routing, reminder, and UI component tests are present across the repo.
|
|
- Run `npm run typecheck` after changing shared types because both apps consume `packages/core`.
|
|
|
|
## Development Rules
|
|
|
|
- Use `@timetoleave/core` for shared behavior.
|
|
- Use `@timetoleave/api-client` for client-to-backend calls that are shared by web and mobile.
|
|
- Keep backend validation close to route handlers, then delegate external service behavior to `apps/web/src/lib`.
|
|
- Never parse HAFAS date/time values with ad hoc `Date` logic; use `parseHafasTime()` and `hafasDateTime()`.
|
|
- This repo uses Next.js 16. Read the relevant `node_modules/next/dist/docs/` material before changing Next.js framework code.
|