move completed plan: 2026-08-13-MVP-Routing-Implementation.md

This commit is contained in:
2026-08-13 21:44:34 +03:00
parent e063d26d4c
commit 8b4ba2d652

View File

@@ -0,0 +1,138 @@
# 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
- [x] Initialize Go module (`go mod init trip-planner`) if not already done
- [x] Add dependencies: `github.com/go-redis/redis/v8`, `github.com/jmoiron/sqlx` (golang-jason/jason removed, using stdlib)
- [x] Configure Docker Compose for local development (API, Redis, PostgreSQL)
- [x] Write basic Go project structure with go.mod, main.go, and internal packages
- [x] Verify `go fmt ./...` and `go vet ./...` pass
- [x] Run initial tests - must pass
### Task 2: Implement Yandex API client with rate limiter and circuit breaker
- [x] Create `internal/yandex/client.go` with Yandex API wrapper
- [x] Implement token bucket rate limiter (configurable TPS limit)
- [x] Implement circuit breaker pattern (states: closed, open, half-open)
- [x] Add retry with exponential backoff for transient errors
- [x] Write tests for rate limiter (token consumption, refill rate)
- [x] Write tests for circuit breaker (state transitions, trip to open state)
- [x] Write tests for retry (success after backoff, exhaustion)
- [x] Run tests - must pass before task 3
### Task 3: Implement cache-aside layer for reference data and search results
- [x] Create `internal/cache/store.go` with Redis cache interface
- [x] Implement cache keys: `cities:{code}`, `stations:{id}`, `search:{from}:{to}:{date}`
- [x] Implement cache-aside pattern: Redis → miss → Postgres/API → write-back to Redis
- [x] Set TTL policies: cities/stations 30 days, search near-term 2-6 hours, search far-term 7 days
- [x] Write tests for cache operations (get, set, invalidate, TTL expiry)
- [x] Write tests for cache-aside pattern (cache hit, cache miss → API call → cache write)
- [x] Run tests - must pass before task 4
### Task 4: Implement routing graph and search algorithm (max 1 transfer)
- [x] Create `internal/routing/graph.go` with Node and Edge types
- [x] Implement Node types: Station, City; Edge kinds: Flight (real), Synthetic
- [x] Build graph from station directory (Postgres + Redis cache)
- [x] Implement BFS/Dijkstra search with 1-transfer depth limit
- [x] Apply MCT (Minimum Connection Time) rules from transfer_rules table
- [x] Write tests for graph construction (node/edge creation, directory loading)
- [x] Write tests for search algorithm (successful 1-transfer route, no-route case, 2-transfer rejected)
- [x] Write tests for MCT rule application (different node types, city tiers, check-in types)
- [x] Run tests - must pass before task 5
### Task 5: Implement API handlers for MVP endpoints
- [x] Create `cmd/api/handlers.go` with HTTP handlers
- [x] Implement `GET /v1/cities?query=` - city autocomplete from cached directory
- [x] Implement `GET /v1/cities/{id}/stations` - city stations including neighbors if main closed
- [x] Implement `POST /v1/routes/search` - body: from_city_id, to_city_id, date; response: Pareto-optimal routes (time, transfers)
- [x] Implement `GET /v1/routes/{search_id}/{route_id}/geojson` - geometry for map visualization
- [x] Implement `GET /v1/stations/{id}/status` - current station status
- [x] Write handlers tests (success cases, error cases, input validation)
- [x] Write integration tests (handler → cache → routing → API client flow)
- [x] Run tests - must pass before task 6
### Task 6: Implement cron job for station status detection
- [x] Create `cmd/cron/station_status.go` daily cron job
- [x] Query `/schedule` for each monitored station, count flights on upcoming dates
- [x] Implement closure detection: N consecutive days of zero trips (N=3 recommended) → status `closed`
- [x] Implement reactivation: status `active` when >0 trips appear
- [x] Write tests for cron logic (status transition, zero-flight detection, reactivation)
- [x] Run tests - must pass before task 7
### Task 7: End-to-end integration and full test suite
- [x] Write integration tests connecting all components: API → cache → routing → Yandex client
- [x] Write synthetic timetable fixtures for routing tests (no real API calls)
- [x] Run full test suite: `go test ./... -cover`
- [x] Verify coverage meets project standard (80%+)
- [x] Fix any failing tests
- [x] Run `go fmt ./...` and `go vet ./...` - all issues must be fixed
- [x] Final verification: manual API endpoint testing with curl or Postman (manual test - skipped, not automatable)
## 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/`*