Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This guide explains how automation agents and human contributors should work with the StationAPI repository so releases stay predictable, auditable, and safe. Update this file whenever you change the workflow or behavior it documents.

## Project Layout
- `src/` – The Worker itself (`stationapi-worker`, wasm32 only). `lib.rs` holds the endpoints, `index.rs` parses the embedded CSVs into in-memory indexes, `repository.rs` implements the repository traits against those indexes, and `graphql/` holds the async-graphql types and resolvers.
- `src/` – The Worker itself (`stationapi-worker`, wasm32 only). `lib.rs` holds the endpoints, `index.rs` parses the embedded CSVs into in-memory indexes, `repository.rs` implements the repository traits against those indexes, and `graphql/` holds the async-graphql types and resolvers. `index.rs` also holds the spatial grid used by every coordinate lookup — see **Coordinate lookups** below.
- `schema/public.graphql` – The published GraphQL schema. CI diffs the Worker's SDL against this file, so an unintended change fails the build.
- `build.rs` – Stages `generated/*.csv` (falling back to `data/*.csv`) into `OUT_DIR` and pre-converts `station_station_types` into a fixed-width binary.
- `wrangler.jsonc` – Staging and production deployment settings.
Expand Down Expand Up @@ -56,7 +56,7 @@ The Worker is the workspace root package. `stationapi`, `preprocessor`, and `dat
- `data_validator` currently verifies that `5!station_station_types.csv` references valid station and type IDs, and that order-sensitive station sequences in `3!stations.csv` stay intact under `ORDER BY e_sort, station_cd` (e.g. the Toei Oedo Line's Tochomae rows, whose misordering silently drops the station from ETA estimation). Extend the validator when new cross-references or order-sensitive spots are introduced and keep the process fail-fast (panic on invalid data).

## Testing and Quality
- **Tests** – `make test` runs the unit tests for every native crate. They need no external services.
- **Tests** – `make test` runs the unit tests for every native crate, plus `cargo test -p stationapi-worker`. The Worker only *runs* on Workers, but `src/index.rs` is a pure in-memory data structure that builds and executes natively, so its tests (including the grid-versus-full-scan differential check) run here. They need no external services.
- **Type checks** – `make check` covers the native crates and the wasm32 target separately. The Worker also compiles for the host, but only runs on Workers.
- **Linting and formatting** – `make fmt` and `make clippy` before committing (clippy covers the wasm32 target too). Resolve new Clippy warnings unless an existing `#![allow]` covers the case.
- **Schema** – Changing a GraphQL type changes the SDL. Update `schema/public.graphql` in the same change; CI compares it against the running Worker's `/__schema` and fails on any difference. That diff is exactly the client-visible impact.
Expand All @@ -67,6 +67,8 @@ The Worker is the workspace root package. `stationapi`, `preprocessor`, and `dat
- **Stations** – `station`, `stations`, `stationGroupStations`, `stationsNearby`, `lineStations`, `stationsByName`, `lineGroupStations`, `lineListStations`, `lineGroupListStations`. `QueryInteractor` enriches stations with lines, companies, station numbers, and train types. `lineStations` resolves the line's local train-type group (rail `kind` 0/1 or a `priority > 0` type); when no such group exists — bus lines only carry `BusRoute` (`kind` 7, `priority` 0) variants — it falls back to the line's plain typeless station list so bus stop listings never return empty.
- **Lines** – `line`, `lines`, `linesByName`. Results include company data and computed line symbols based on repository helpers.
- **Routes** – `routes`, `connectedRoutes`, `estimateArrivalTimes`, `trainRoute`. Paging tokens are currently empty (pagination not implemented).
- **`trainRoute`** – Takes the line group's stops from the repository *before* any enrichment, slices them to the requested `fromStationId`–`toStationId` range (reversing when the request runs backwards), and only then attaches lines, companies, station numbers, train types, and nearby bus routes. Enrichment is per-station and independent, so slicing first does not change any segment; enriching the whole line group first made a three-station request cost the same as a 250-station one. Keep the order — the cost of this query must stay proportional to the requested range, not to the line group.
- **Coordinate lookups** – `index::nearest` (k nearest, used by `stationsNearby`) and `index::within_radius` (everything inside a radius, used by the nearby-bus-stop enrichment) both go through a per-transport-type grid index (`Grid`, CSR over 0.05° cells) instead of scanning the whole station table. `nearest` searches a radius, widens it while fewer than `limit` stations fall inside, and stops once the radius covers the index — anything outside a radius that already holds `limit` hits cannot be in the top `limit`. It orders purely by distance: `stationsNearby` is specified as nearest-first, so rail and bus are not separated even when `transportType` is omitted (the pre-Workers SQL sorted on `transport_type` first, which put a rail station kilometres away ahead of a bus stop at the same address). Ties on distance break on `station_cd` so the order does not depend on an unstable sort. Every station lookup by coordinates runs on every request that enriches rail stations with nearby bus routes, so keep new coordinate queries on the grid rather than adding another full scan.
- **Train types** – `stationTrainTypes`, `routeTypes`. Train types aggregate by line group and include related lines plus optional train type metadata. Rail variants use `TrainTypeKind::{Default, Branch, Rapid, Express, LimitedExpress, HighSpeedRapid, CommuterRapid}` (0-6); bus variants use `BusRoute` (7), which represents a `(route_id, shape_id)` operation pattern (e.g. 循環 / 短ターン / 支線) generated automatically from the configured GTFS bus feeds (Toei Bus, Seibu Bus, Keio Bus) and the converted Tokyu Bus JSON.
- **Default rail train types** – `preprocessor` fills every active rail line containing at least one station with no `station_station_types` row with a deterministic, complete all-stop group. The generated rows exist only in `generated/*.csv`; canonical CSV files remain unchanged. `type_cd=100` represents 「普通」 and `type_cd=101` represents 「各駅停車」. An existing 100/101 assignment on the line takes precedence; otherwise the label is selected per line through `LOCAL_SERVICE_RAIL_LINE_IDS` in `preprocessor/src/rail.rs`. Generated `line_group_cd` values use `1,000,000,000 + line_cd`; generation fails on a collision. Bus lines are excluded and continue to use their GTFS-derived `BusRoute` groups.
- **GTFS bus integration** – `preprocessor/src/gtfs/` reads the GTFS feeds into an in-memory representation and then projects them onto the shared `stations` / `lines` / `types` / `station_station_types` tables (`gtfs/integrate.rs`). Only routes, stops, trips, and stop_times are read; calendar, shapes, feed_info, and agencies do not affect the output. Every configured GTFS feed is imported, including Seibu Bus and Keio Bus (both downloaded from ODPT with `ODPT_ACCESS_TOKEN`). Tokyu Bus ordinary-route `BusroutePattern`, `BusstopPole`, and `BusTimetable` JSON are converted into the same representation; pattern IDs become `shape_id` values so route variants remain queryable as bus TrainTypes. The Tokyu-operated Ota, Shinagawa, and Meguro community buses use their official GTFS feeds and matching JSON routes are excluded to prevent duplicates. `ODPT_ACCESS_TOKEN` is required for authenticated sources; without it those feeds are skipped with a warning rather than failing the build. Stops whose Tokyu JSON records omit coordinates remain available to name and route queries but not coordinate searches. `transport_type` (0: rail, 1: bus) on both `stations` and `lines` keeps rail and bus records queryable side by side. GTFS IDs are namespaced per feed before import to avoid cross-operator collisions. `line_cd` (100,000,000+), `station_cd` / `station_g_cd` (200,000,000+), and bus `type_cd` / `line_group_cd` (100,000,000+) are all deterministic fnv1a hashes that stay clear of the rail data ranges. Disable the entire bus pipeline with `DISABLE_BUS_FEATURE=true`.
Expand Down
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ help:
@echo " ODPT_ACCESS_TOKEN - Required by all bus feeds except Toei"
@echo " DISABLE_BUS_FEATURE - Set to true to build rail-only data"

# worker は wasm32 用の crate なので、ネイティブのテストからは外す。
# worker は Workers 上でしか動かないが、索引 (src/index.rs) はネイティブでも
# 動く純粋なデータ構造なので、そのユニットテストはここで走らせる。
test:
cargo test -p stationapi -p stationapi-preprocessor -p data_validator
cargo test -p stationapi-worker

check:
cargo check -p stationapi -p stationapi-preprocessor -p data_validator
Expand Down
4 changes: 3 additions & 1 deletion docs/nearby-bus-stops.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ enum TransportType {
| **Bus** | バス停のみを返す |
| **RailAndBus** | 鉄道駅とバス停の両方を返す。`lines`配列にも近傍バス路線を含める |

**注**: `stationsNearby` の並びは常に近い順です。`transportType` を指定しない場合も鉄道とバスを分けず、距離だけで並べます。

## 対象API

| クエリ | 近傍バス停対応 | 備考 |
Expand Down Expand Up @@ -123,5 +125,5 @@ async fn get_nearby_bus_lines(&self, ref_lat: f64, ref_lon: f64) -> Result<Vec<L

## 注意事項

- バス路線検索は最大50件のバス停候補を取得し、その中から300m以内のものをフィルタリング
- バス路線検索は300m以内のバス停を近い順に見て、有効な路線を持つものを最大50件採用
- 鉄道駅の `lines` 配列に近傍バス路線が追加されるのは、未指定または `transportType: RailAndBus` の場合
Loading
Loading