138 lines
8.2 KiB
Markdown
138 lines
8.2 KiB
Markdown
# MVP Routing Implementation
|
||
|
||
## Overview
|
||
Implement the Minimum Viable Product for the multimodal trip planning service, focusing on core routing functionality for single transport mode (trains) with maximum 1 transfer. This foundation will enable subsequent stages adding multimodality, deeper search, and station closure detection.
|
||
|
||
**Problem it solves**: Users can search for train routes between cities with up to 1 transfer, with basic GeoJSON map visualization and proper API caching to respect Yandex.Schedules API quota limits.
|
||
|
||
**Key benefits**:
|
||
- Core routing engine within API quota constraints
|
||
- Cache-aside pattern prevents API overuse
|
||
- GeoJSON output enables immediate map visualization
|
||
- TDD-guaranteed correctness for critical routing logic
|
||
|
||
## Context (from discovery)
|
||
- **Files/components involved**: `internal/routing` (graph, search algorithm, MCT rules), `internal/yandex` (API client with rate limiter, retries, circuit breaker), `internal/cache` (Redis cache-aside), `cmd/api` (HTTP handlers), `cmd/cron` (station status detection)
|
||
- **Related patterns**: Lazy graph expansion with hub stations, BFS/Dijkstra with depth limiting (4-5 transfers max), Pareto-front ranking (time, transfers, cost), cache-aside with multi-layer TTL
|
||
- **Dependencies**: PostgreSQL for station/city directories, Redis for cache TTL, Yandex.Schedules API (`/search`, `/schedule`, `/nearest_stations`, `/stations_list`)
|
||
|
||
## Development Approach
|
||
- **Testing approach**: TDD (tests first) - user preference confirmed
|
||
- Complete each task fully before moving to the next
|
||
- Make small, focused changes with tests
|
||
- **CRITICAL: every task MUST include new/updated tests** for code changes in that task
|
||
- tests are not optional - they are a required part of the checklist
|
||
- write unit tests for new functions/methods
|
||
- write unit tests for modified functions/methods
|
||
- add new test cases for new code paths
|
||
- update existing test cases if behavior changes
|
||
- tests cover both success and error scenarios
|
||
- **CRITICAL: all tests must pass before starting next task** - no exceptions
|
||
- **CRITICAL: update this plan file when scope changes during implementation**
|
||
- Run tests after each change
|
||
- Maintain backward compatibility
|
||
|
||
## Testing Strategy
|
||
- **Unit tests**: required for every task (see Development Approach above)
|
||
- **E2E tests**: project has UI-based e2e tests considerations:
|
||
- UI changes → add/update e2e tests in same task as UI code
|
||
- Backend changes supporting UI → add/update e2e tests in same task
|
||
- Treat e2e tests with same rigor as unit tests (must pass before next task)
|
||
- Store e2e tests alongside unit tests (or in designated e2e directory)
|
||
|
||
## Progress Tracking
|
||
- Mark completed items with `[x]` immediately when done
|
||
- Add newly discovered tasks with ➕ prefix
|
||
- Document issues/blockers with ⚠️ prefix
|
||
- Update plan if implementation deviates from original scope
|
||
- Keep plan in sync with actual work done
|
||
|
||
## What Goes Where
|
||
- **Implementation Steps** (`[ ]` checkboxes): tasks achievable within this codebase - code changes, tests, documentation updates
|
||
- **Post-Completion** (no checkboxes): items requiring external action - manual testing, changes in consuming projects, deployment configs, third-party verifications
|
||
- **Checkbox placement**: Checkboxes belong only in Task sections (`### Task N:` or `### Iteration N:`). Do not put checkboxes in Success criteria, Overview, or Context — they cause extra loop iterations.
|
||
|
||
## Implementation Steps
|
||
|
||
### Task 1: Set up project structure and dependencies
|
||
- [ ] Initialize Go module (`go mod init trip-planner`) if not already done
|
||
- [ ] Add dependencies: `github.com/go-redis/redis/v8`, `github.com/jmoiron/sqlx`, `github.com/golang-jason/jason` (or similar)
|
||
- [ ] Configure Docker Compose for local development (API, Redis, PostgreSQL)
|
||
- [ ] Write basic Go project structure with go.mod, main.go, and internal packages
|
||
- [ ] Verify `go fmt ./...` and `go vet ./...` pass
|
||
- [ ] Run initial tests - must pass
|
||
|
||
### Task 2: Implement Yandex API client with rate limiter and circuit breaker
|
||
- [ ] Create `internal/yandex/client.go` with Yandex API wrapper
|
||
- [ ] Implement token bucket rate limiter (configurable TPS limit)
|
||
- [ ] Implement circuit breaker pattern (states: closed, open, half-open)
|
||
- [ ] Add retry with exponential backoff for transient errors
|
||
- [ ] Write tests for rate limiter (token consumption, refill rate)
|
||
- [ ] Write tests for circuit breaker (state transitions, trip to open state)
|
||
- [ ] Write tests for retry (success after backoff, exhaustion)
|
||
- [ ] Run tests - must pass before task 3
|
||
|
||
### Task 3: Implement cache-aside layer for reference data and search results
|
||
- [ ] Create `internal/cache/store.go` with Redis cache interface
|
||
- [ ] Implement cache keys: `cities:{code}`, `stations:{id}`, `search:{from}:{to}:{date}`
|
||
- [ ] Implement cache-aside pattern: Redis → miss → Postgres/API → write-back to Redis
|
||
- [ ] Set TTL policies: cities/stations 30 days, search near-term 2-6 hours, search far-term 7 days
|
||
- [ ] Write tests for cache operations (get, set, invalidate, TTL expiry)
|
||
- [ ] Write tests for cache-aside pattern (cache hit, cache miss → API call → cache write)
|
||
- [ ] Run tests - must pass before task 4
|
||
|
||
### Task 4: Implement routing graph and search algorithm (max 1 transfer)
|
||
- [ ] Create `internal/routing/graph.go` with Node and Edge types
|
||
- [ ] Implement Node types: Station, City; Edge kinds: Flight (real), Synthetic
|
||
- [ ] Build graph from station directory (Postgres + Redis cache)
|
||
- [ ] Implement BFS/Dijkstra search with 1-transfer depth limit
|
||
- [ ] Apply MCT (Minimum Connection Time) rules from transfer_rules table
|
||
- [ ] Write tests for graph construction (node/edge creation, directory loading)
|
||
- [ ] Write tests for search algorithm (successful 1-transfer route, no-route case, 2-transfer rejected)
|
||
- [ ] Write tests for MCT rule application (different node types, city tiers, check-in types)
|
||
- [ ] Run tests - must pass before task 5
|
||
|
||
### Task 5: Implement API handlers for MVP endpoints
|
||
- [ ] Create `cmd/api/handlers.go` with HTTP handlers
|
||
- [ ] Implement `GET /v1/cities?query=` - city autocomplete from cached directory
|
||
- [ ] Implement `GET /v1/cities/{id}/stations` - city stations including neighbors if main closed
|
||
- [ ] Implement `POST /v1/routes/search` - body: from_city_id, to_city_id, date; response: Pareto-optimal routes (time, transfers)
|
||
- [ ] Implement `GET /v1/routes/{search_id}/{route_id}/geojson` - geometry for map visualization
|
||
- [ ] Implement `GET /v1/stations/{id}/status` - current station status
|
||
- [ ] Write handlers tests (success cases, error cases, input validation)
|
||
- [ ] Write integration tests (handler → cache → routing → API client flow)
|
||
- [ ] Run tests - must pass before task 6
|
||
|
||
### Task 6: Implement cron job for station status detection
|
||
- [ ] Create `cmd/cron/station_status.go` daily cron job
|
||
- [ ] Query `/schedule` for each monitored station, count flights on upcoming dates
|
||
- [ ] Implement closure detection: N consecutive days of zero trips (N=3 recommended) → status `closed`
|
||
- [ ] Implement reactivation: status `active` when >0 trips appear
|
||
- [ ] Write tests for cron logic (status transition, zero-flight detection, reactivation)
|
||
- [ ] Run tests - must pass before task 7
|
||
|
||
### Task 7: End-to-end integration and full test suite
|
||
- [ ] Write integration tests connecting all components: API → cache → routing → Yandex client
|
||
- [ ] Write synthetic timetable fixtures for routing tests (no real API calls)
|
||
- [ ] Run full test suite: `go test ./... -cover`
|
||
- [ ] Verify coverage meets project standard (80%+)
|
||
- [ ] Fix any failing tests
|
||
- [ ] Run `go fmt ./...` and `go vet ./...` - all issues must be fixed
|
||
- [ ] Final verification: manual API endpoint testing with curl or Postman
|
||
|
||
## Post-Completion
|
||
*Items requiring manual intervention or external systems - no checkboxes, informational only*
|
||
|
||
**Manual verification**:
|
||
- Test API endpoints with sample requests
|
||
- Verify GeoJSON output format for map visualization
|
||
- Test cache hit/miss scenarios
|
||
- Test station status cron job behavior
|
||
|
||
**External system updates**:
|
||
- Docker Compose setup for local development (`docker-compose up -d`)
|
||
- Gitea Actions workflow `.gitea/workflows/deploy.yml` CI/CD pipeline
|
||
- Docker image build and push configuration
|
||
- Watchtower configuration for auto-updates
|
||
|
||
*Note: ralphex automatically moves completed plans to `docs/plans/completed/`* |