From 36d982fb3b01fd8181b216b57fba2c42e9404d1f Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Mon, 17 Nov 2025 23:29:03 +0100 Subject: Add copilot instructions --- .github/copilot-instructions.md | 97 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 .github/copilot-instructions.md (limited to '.github') diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..8b93bf2 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,97 @@ +# Busurbano: AI Coding Agent Guide + +Busurbano is a public transit app for urban buses in Spain (currently Vigo). It provides real-time arrival estimates, scheduled timetables, bus stop mapping, and delay data collection. + +## Architecture Overview + +**Three-component system:** +1. **Backend** (`src/Costasdev.Busurbano.Backend`): ASP.NET Core 9 Web API serving transit data +2. **Frontend** (`src/frontend`): React 19 SPA using react-router v7 (SSR disabled), MapLibre GL, Vite +3. **Python utilities**: GTFS processing (`gtfs_vigo_stops`), delay collection daemon (`delay_collector`), stop data downloaders + +**Data flow:** +- Frontend fetches stop metadata from static JSON (`/stops/vigo.json`) + real-time estimates from backend `/api/vigo/*` endpoints +- Backend uses [`Costasdev.VigoTransitApi`](https://github.com/arielcostas/VigoTransitApi) for live data, pre-processed Protobuf files (`.pb`) for GTFS schedules/shapes +- Delay collector daemon polls `/api/vigo/GetConsolidatedCirculations` every 30s during service hours, stores to PostgreSQL + +## Critical Patterns + +**Backend scheduling logic (`Controllers/VigoController.cs`):** +- `GetConsolidatedCirculations` merges real-time estimates with GTFS schedules via fuzzy matching (line + normalized route name) +- Uses EPSG:25829 (UTM zone 29N) for geometric calculations, transforms to WGS84 for API responses +- Schedule files organized by date: `{ScheduleBasePath}/{yyyy-MM-dd}/{stopId}.pb` +- Shape traversal (`Services/ShapeTraversalService.cs`) calculates bus positions by reverse-walking GTFS shape geometries from stop location minus distance + +**Frontend multi-region setup (`app/data/RegionConfig.ts`):** +- All region-specific config (endpoints, bounds, colors) defined in `REGIONS` constant +- `RegionId` type enforces compile-time region safety +- localStorage keys namespaced by region: `favouriteStops_{region}`, `customStopNames_{region}`, `recentStops_{region}` + +**Stop overrides (`stop_downloader/*/overrides.yaml`):** +- YAML files override stop names, locations, amenities, hide stops, or add alerts +- `new: true` flag creates stops not in transit API (auto-removed after processing) + +**Protobuf types (`src/common/stop_schedule.proto`):** +- Auto-generated C# types in `Backend/Types/StopSchedule.cs` (DO NOT EDIT marker) +- Shared `.proto` compiles to both C# and Python where needed + +## Development Workflows + +**Run entire stack:** +```bash +npm run dev # Starts both frontend (port 5173) and backend (port 7240) via npm script +``` + +**Frontend only:** +```bash +cd src/frontend +npm run dev # Vite dev server with proxy to backend at https://localhost:7240 +``` + +**Backend only:** +```bash +dotnet run --project src/Costasdev.Busurbano.Backend +``` + +**Formatting/linting:** +- Frontend: `npm run format` (Prettier), `npm run lint:fix` (ESLint) in `src/frontend` +- Python: `ruff format .` and `ruff check .` (configured in `pyproject.toml`) +- C#: Auto-format on save via EditorConfig (`.editorconfig` at root) + +**Delay collector:** +```bash +cd src/delay_collector +# Requires PostgreSQL; see DB_SETUP.md for schema setup +# Configure via environment: DB_HOST, DB_NAME, DB_USER, DB_PASSWORD, FREQUENCY_SECONDS +python main.py +``` + +## Key Conventions + +- **No TypeScript barrel exports**: Direct imports from specific files (e.g., `~/components/LineIcon` not `~/components`) +- **Date normalization**: Backend uses `Europe/Madrid` timezone consistently, filters out unparseable times (hour >= 24) +- **Route name matching**: Normalize via `RemoveDiacritics()` + alphanumeric-only before comparing GTFS terminus vs. API route +- **Coordinate systems**: GTFS shapes in EPSG:25829 meters, API responses in WGS84 lat/lng +- **Config separation**: Backend config via `appsettings.json` + user secrets (`App:ScheduleBasePath`), frontend via `RegionConfig.ts` +- **Protobuf over JSON for schedules**: Smaller payloads, faster parsing; JSON used for initial timetable endpoint backward compatibility + +## External Dependencies + +- **[VigoTransitApi](https://github.com/arielcostas/VigoTransitApi)**: NuGet package wrapping datos.vigo.org real-time API +- **Open data license**: All Vigo transit data under [ODC-BY](https://opendefinition.org/licenses/odc-by/); attribution required +- **MapLibre + OpenFreeMap**: Self-hosted tile server config in frontend, not Mapbox + +## Common Pitfalls + +- Do NOT edit `Types/StopSchedule.cs` directly (regenerate from `.proto`) +- Frontend expects backend at `https://localhost:7240` in dev (Vite proxy config) +- Schedule `.pb` files must exist for date or `GetConsolidatedCirculations` fails with 404 +- Stop metadata changes require regenerating `stops/vigo.json` (manual process, no build step) +- Delay collector silently pauses outside `SERVICE_START_HOUR` to `SERVICE_END_HOUR` (default 7 AM–11 PM Madrid time) + +## Files to Ignore + +**Generated/lock files (unless making intentional automated changes):** +- `package-lock.json` — Only edit when explicitly updating dependencies +- `stops/.json` — Auto-generated from Python scripts, edit source data instead +- `public/maps/styles/*.json` — MapLibre style configs, managed separately -- cgit v1.3