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: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ api_descriptor.pb
tmp.sql
.vscode/
data/ToeiBus-GTFS/
data/SeibuBus-GTFS/
data/TokyuBus-OtaCity-GTFS/
data/TokyuBus-ShinagawaCity-GTFS/
data/TokyuBus-MeguroCity-GTFS/
data/TokyuBus-ODPT/
data/KeioBus-GTFS/
scripts/.osm_cache/
scripts/.gtfs_cache/
__pycache__/
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This guide explains how automation agents and human contributors should work wit
- Environment variables:
- `DATABASE_URL` – SQLx connection string (e.g., `postgres://stationapi:stationapi@localhost/stationapi`).
- `DISABLE_GRPC_WEB` – `false` enables gRPC-Web; set to `true` for pure gRPC/HTTP2.
- `ODPT_ACCESS_TOKEN` – ODPT consumer key used to download authenticated GTFS feeds such as Seibu Bus.
- `ODPT_ACCESS_TOKEN` – ODPT consumer key used to download authenticated data such as Seibu Bus GTFS, Keio Bus GTFS, Tokyu Bus JSON, and the Tokyu-operated Ota, Shinagawa, and Meguro community bus GTFS feeds.
- `HOST` and `PORT` – listen address (defaults to `[::1]:50051`; Docker uses `0.0.0.0:50051`).
- `.env.test` exports `TEST_DATABASE_URL`, `RUST_LOG`, `RUST_BACKTRACE`, and `RUST_TEST_THREADS=1` for integration tests.
- Recommended: keep shared defaults in `.env`, copy overrides to `.env.local`, and rely on startup loading both files.
Expand Down Expand Up @@ -53,8 +53,8 @@ This guide explains how automation agents and human contributors should work wit
- **Stations** – `GetStationById`, `GetStationByIdList`, `GetStationsByGroupId`, `GetStationsByCoordinates`, `GetStationsByLineId`, `GetStationsByName`, `GetStationsByLineGroupId`. `QueryInteractor` enriches stations with lines, companies, station numbers, and train types.
- **Lines** – `GetLineById`, `GetLinesByIdList`, `GetLinesByName`. Results include company data and computed line symbols based on repository helpers.
- **Routes** – `GetRoutes`, `GetRoutesMinimal`. The minimal variant returns `RouteMinimalResponse` with deduplicated `LineMinimal` data; paging tokens are currently empty (pagination not implemented).
- **Train types** – `GetTrainTypesByStationId`, `GetRouteTypes`. 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 Toei Bus GTFS feed.
- **GTFS bus integration** – At startup, `src/import.rs::integrate_gtfs_to_stations()` ingests GTFS feeds into `gtfs_*` tables and then projects them onto the shared `stations` / `lines` / `types` / `station_station_types` tables. Every configured feed is imported, including Seibu Bus (downloaded from ODPT with `ODPT_ACCESS_TOKEN`). `transport_type` (0: rail, 1: bus) on both `stations` and `lines` keeps the two worlds 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`.
- **Train types** – `GetTrainTypesByStationId`, `GetRouteTypes`. 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.
- **GTFS bus integration** – At startup, `src/import.rs::integrate_gtfs_to_stations()` ingests GTFS feeds into `gtfs_*` tables and then projects them onto the shared `stations` / `lines` / `types` / `station_station_types` tables. 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 `gtfs_*` 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. 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`.
- **TTS metadata** – `Station`, `StationMinimal`, `Line`, and `TrainType` expose `name_ipa` / `name_roman_ipa` plus `name_tts_segments` for multi-segment pronunciation output. Use `name_tts_segments` when clients need per-token SSML construction for mixed-language names such as `Kasai-Rinkai Park`.
- **Connected routes** – `GetConnectedRoutes`. `QueryInteractor::get_connected_stations` is not implemented yet and returns an empty vector; update the use-case and infrastructure layers together when adding real logic.
- Changes to the service contract require coordinated updates to `proto/stationapi.proto`, regenerated code via `tonic-build`, and corresponding adjustments in both presentation and use-case layers.
Expand Down
31 changes: 31 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ We follow Rust best practices for testing:

- Bus-related data provided by [Tokyo Metropolitan Bureau of Transportation (Toei)](https://www.kotsu.metro.tokyo.jp/), licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
- Bus-related data provided by [Seibu Bus Co., Ltd. (西武バス)](https://www.seibubus.co.jp/) via the [Public Transportation Open Data Center](https://ckan.odpt.org/), licensed under the [Public Transportation Open Data Basic License](https://developer.odpt.org/terms)
- Bus-related data provided by [Keio Dentetsu Bus Co., Ltd. (京王電鉄バス)](https://www.keio-bus.com/) via the [Public Transportation Open Data Center](https://ckan.odpt.org/), licensed under the [Public Transportation Open Data Basic License](https://developer.odpt.org/terms)
- Bus data provided by [Tokyu Bus Corporation (東急バス)](https://www.tokyubus.co.jp/) via the [Public Transportation Open Data Center](https://ckan.odpt.org/), licensed under the [Public Transportation Open Data Basic License](https://developer.odpt.org/terms)
- Station data provided by [駅データ.jp](https://www.ekidata.jp/)
- Speed calibration data (`speed_table.rs`) derived from GTFS timetables provided by Kyoto City Transportation Bureau (京都市交通局), Yokohama City Transportation Bureau (横浜市交通局), Tokyo Metro (東京メトロ), Metropolitan Intercity Railway (首都圏新都市鉄道), Tokyo Tama Intercity Monorail (多摩都市モノレール), and Tokyo Waterfront Area Rapid Transit (東京臨海高速鉄道) via the [Public Transportation Open Data Center](https://ckan.odpt.org/), licensed under the [Public Transportation Open Data Basic License](https://developer.odpt.org/terms); by [Tokyo Metropolitan Bureau of Transportation (Toei)](https://www.kotsu.metro.tokyo.jp/), licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/); and by Hakodate City Enterprise Bureau Transportation Department (函館市企業局交通部), licensed under [GTFS-RUL (ODPT)](https://gtfs-jp.org/GTFS-RUL(ODPT).pdf)
- Average inter-station distances (`average_distance`) computed from railway track geometry © [OpenStreetMap contributors](https://www.openstreetmap.org/copyright), licensed under [ODbL](https://opendatacommons.org/licenses/odbl/)
2 changes: 2 additions & 0 deletions data/1!companies.csv
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ company_cd,rr_cd,company_name,company_name_k,company_name_h,company_name_r,compa
11,21,東武鉄道,トウブテツドウ,東武鉄道株式会社,東武,Tobu,Tobu Railway,http://www.tobu.co.jp/,2,0,11
12,22,西武鉄道,セイブテツドウ,西武鉄道株式会社,西武,Seibu,Seibu Railway,http://www.seibu-group.co.jp/railways/,2,0,12
253,99,西武バス,セイブバス,西武バス株式会社,西武バス,Seibu Bus,Seibu Bus,https://www.seibubus.co.jp/,0,0,12
254,99,京王バス,ケイオウバス,京王電鉄バス株式会社,京王バス,Keio Bus,Keio Bus,https://www.keio-bus.com/,0,0,14
255,99,東急バス,トウキュウバス,東急バス株式会社,東急バス,Tokyu Bus,Tokyu Bus Corporation,https://www.tokyubus.co.jp/,0,0,16
13,23,京成電鉄,ケイセイデンテツ,京成電鉄株式会社,京成,Keisei,Keisei Electric Railway,http://www.keisei.co.jp/,2,0,13
14,24,京王電鉄,ケイオウデンテツ,京王電鉄株式会社,京王,Keio,Keio,http://www.keio.co.jp/,2,0,14
15,25,小田急電鉄,オダキュウデンテツ,小田急電鉄株式会社,小田急,Odakyu,Odakyu Electric Railway,http://www.odakyu.jp/,2,0,15
Expand Down
4 changes: 2 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,11 @@ CREATE INDEX idx_performance_station_name_trgm ON stations

### バス (GTFS) データの統合

`stations` / `lines` / `types` / `station_station_types` は鉄道とバスの両方を保持し、`stations.transport_type` / `lines.transport_type` (0: 鉄道, 1: バス) でフィルタリングします。バスデータの取り込みは `src/import.rs` の `integrate_gtfs_to_stations()` が起動時に実行し、ODPT 公開の GTFS を `gtfs_*` テーブルに展開してから既存テーブルへ統合します。Seibu Bus を含む設定済みの全GTFSフィードを使用します。Seibu Bus のダウンロードには `.env.local` の `ODPT_ACCESS_TOKEN` を使用します。
`stations` / `lines` / `types` / `station_station_types` は鉄道とバスの両方を保持し、`stations.transport_type` / `lines.transport_type` (0: 鉄道, 1: バス) でフィルタリングします。バスデータの取り込みは `src/import.rs` の `integrate_gtfs_to_stations()` が起動時に実行し、ODPT 公開のデータを `gtfs_*` テーブルに展開してから既存テーブルへ統合します。都営バス・西武バス・京王バスを含む設定済みの全GTFSフィードを直接読み込みます。東急バスの一般路線は `BusroutePattern` / `BusstopPole` / `BusTimetable` JSONをGTFS相当の路線・停留所・便・停車時刻へ変換し、路線パターンIDを `shape_id` として扱います。ODPTのJSON APIは全事業者分の大きな配列を返すため、レスポンスをファイルへストリーミングし、1件ずつ東急バス分だけ抽出した7日間キャッシュを `data/TokyuBus-ODPT/` に保持します。大田区(たまちゃんバス)・品川区(しなバス)・目黒区(さんまバス)は公式GTFSを使用し、JSON側の同一路線を除外して重複を防ぎます。認証付きデータ(西武バス・京王バスのGTFSや東急バスのJSON)のダウンロードには `.env.local` の `ODPT_ACCESS_TOKEN` を使用します。なお、ODPT JSONで座標が欠落している一般路線停留所は名称・路線検索には含まれますが、座標検索には含められません

| 鉄道側の概念 | バス側の対応 |
|---|---|
| `companies` | GTFS フィードごとに会社を決定。Toei Bus は東京都交通局 (`company_cd=119`)、Seibu Bus は西武バス (`company_cd=253`) |
| `companies` | データソースごとに会社を決定。Toei Bus は東京都交通局 (`company_cd=119`)、Seibu Bus は西武バス (`company_cd=253`)、Keio Bus は京王バス (`company_cd=254`)、東急バスのJSON変換データとコミュニティバス3フィードは東急バス (`company_cd=255`) |
| `lines` | GTFS `routes` を 1:1 で `lines` に登録。`line_cd` はフィード接頭辞付き `route_id` の fnv1a ハッシュで 100,000,000+ 空間に決定的に生成 |
| `stations` | GTFS `stops` (親停留所) を `(stop_id, route_id)` 単位で `stations` に登録。`station_cd` / `station_g_cd` もフィード接頭辞付き ID から 200,000,000+ 空間にハッシュ生成 |
| `types` | GTFS の `(route_id, shape_id)` バリエーション (フルループ / 短ターン / 支線など) を `kind = TrainTypeKind::BusRoute (= 7)` の TrainType として登録。**停留所集合が完全に同じ shape ペア (上下方向違いのみ) は 1 つの TrainType に畳み、`direction = Both` を設定**。`type_name` は循環なら `<headsign> (循環)`、双方向ペアなら `<A> ⇔ <B>`、片方向なら `<始発停留所> → <headsign>` |
Expand Down
2 changes: 1 addition & 1 deletion stationapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ tonic-health = "0.12.3"
tonic-reflection = "0.12.3"
csv = "1.3.1"
chrono = ">=0.4.20"
reqwest = { version = "0.12.12", default-features = false, features = ["blocking", "rustls-tls"] }
reqwest = { version = "0.12.12", default-features = false, features = ["blocking", "rustls-tls", "gzip"] }
zip = ">=2.3.0"
metrics = "0.24"
metrics-exporter-prometheus = "0.16"
Expand Down
Loading
Loading