65 lines
2.5 KiB
Markdown
65 lines
2.5 KiB
Markdown
# MultiTrain
|
|
|
|
Search train connections from **multiple start stations to multiple destination stations** in one query. Results are merged, deduplicated, and ranked; each station can carry a **penalty in minutes** (e.g. "Wien Meidling +10 because it takes me longer to get there") that is added to a journey's duration for ranking only — displayed times stay real.
|
|
|
|
Data comes from [Transitous](https://transitous.org), a community-run [MOTIS](https://github.com/motis-project/motis) instance aggregating open timetable data from many carriers (ÖBB, DB, and many more). Please respect their fair-use policy: set a `USER_AGENT` that identifies you.
|
|
|
|
## Development
|
|
|
|
```bash
|
|
nix develop # provides node 22 + npm + typescript-language-server
|
|
npm install
|
|
npm run dev # dev server on http://127.0.0.1:3000
|
|
```
|
|
|
|
Note: `tsx watch` does not detect file changes on Windows-mounted drives (`/mnt/*` in WSL) — restart manually there.
|
|
|
|
## Architecture
|
|
|
|
Lightweight hexagonal: `src/model` is the pure domain core (domain model, `JourneySource` port, search use case — fan-out over station pairs, merge, dedupe, penalty scoring). `src/adapter` holds the Fastify HTTP adapter and the Transitous adapter (the only place touching the MOTIS client libraries). `src/main.ts` wires everything by hand.
|
|
|
|
## API
|
|
|
|
- `GET /api/locations?query=wien` — station suggestions
|
|
- `POST /api/search` — body:
|
|
|
|
```json
|
|
{
|
|
"from": [{ "query": "Wien Hbf", "penalty": 0 }, { "query": "Wien Meidling", "penalty": 10 }],
|
|
"to": [{ "query": "München Hbf", "penalty": 0 }],
|
|
"departure": "2026-07-11T08:00:00Z"
|
|
}
|
|
```
|
|
|
|
`departure` and `arrival` are mutually exclusive; omit both to depart now.
|
|
|
|
## Configuration (environment)
|
|
|
|
| Variable | Default | Purpose |
|
|
|---|---|---|
|
|
| `PORT` | `3000` | HTTP port |
|
|
| `HOST` | `127.0.0.1` | Bind address |
|
|
| `USER_AGENT` | `multitrain` | Sent to the MOTIS API — please personalize |
|
|
| `MOTIS_BASE_URL` | api.transitous.org | Self-hosted MOTIS instance |
|
|
|
|
## Deployment on NixOS
|
|
|
|
```nix
|
|
# flake inputs
|
|
inputs.multitrain.url = "github:you/multitrain"; # or a path/git url
|
|
|
|
# NixOS configuration
|
|
{
|
|
imports = [ inputs.multitrain.nixosModules.default ];
|
|
|
|
services.multitrain = {
|
|
enable = true;
|
|
port = 3000;
|
|
host = "127.0.0.1";
|
|
userAgent = "multitrain (you@example.org)";
|
|
# motisBaseUrl = "https://motis.example.org";
|
|
};
|
|
}
|
|
```
|
|
|
|
`nix build` produces the server as `result/bin/multitrain`. After changing `package-lock.json`, refresh `npmDepsHash` in `flake.nix` (`nix run nixpkgs#prefetch-npm-deps -- package-lock.json`).
|