Files
trip-planner/CLAUDE.md
Vladimir Zagainov b14682f424 fix: address code review findings
- Create README.md with project overview, quick start, Docker deployment, CI/CD info
- Update CLAUDE.md with Deployment section
- Fix cmd/api/main.go to use REDIS_ADDR env var with fallback
- Fix Dockerfile to use golang:1.22-alpine instead of golang:1.26-alpine
- Fix .gitea/workflows/deploy.yml to include Docker registry prefix in image tags
2026-08-19 01:11:55 +03:00

7.4 KiB
Raw Permalink Blame History

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

This is a multimodal trip planning service that uses Yandex.Schedules API to provide routing across different transport modes (planes, trains, buses). The service implements lazy graph expansion to work within API quota constraints and provides route visualization on maps.

Technology Stack

  • Backend: Go
  • Database: PostgreSQL (with PostGIS optional for geometry)
  • Cache/Queue: Redis (native TTL)
  • Frontend Map: Leaflet + OpenStreetMap tiles
  • Task Scheduler: cron (internal cmd/cron or system cron)

Project Structure

/cmd
  /api        — HTTP server
  /cron       — Reference data updates, station status detection
/internal
  /yandex     — Yandex API client, rate limiter, retries, circuit breaker
  /cache      — Interface + Redis implementation (cache-aside), user preferences
  /storage    — PostgreSQL repositories, transfer rules, station neighbors
  /routing    — Graph, search algorithm, MCT rules, search cache, route status
  /airports   — Neighboring stations, closure detection
  /geo        — GeoJSON assembly for maps
  /metrics    — Observability metrics (cache hits/misses, API quota, circuit breaker, search duration)

Common Development Commands

Running the API Server

go run ./cmd/api

Running Cron Jobs

go run ./cmd/cron

Running Tests

# Run all tests
go test ./...

# Run tests for a specific package
go test ./internal/routing

# Run tests with coverage
go test ./... -cover

Database Migrations

(Assuming standard Go migration tools)

# Apply migrations
goose up

# Rollback migration
goose down

# Check migration status
goose status

Code Formatting

# Format Go code
go fmt ./...

# Check for formatting issues
go vet ./...

Deployment

Docker Deployment

The project uses a multi-stage Dockerfile:

  • Builder stage: golang:1.22-alpine to build api and cron binaries
  • Runtime stage: alpine:latest with minimal footprint (~27MB)

Docker Compose

The docker-compose.yml includes:

  • api service: Go HTTP server on port 8080
  • cron service: Go cron binary for reference data updates and station status detection
  • postgres: PostgreSQL 15-alpine with postgres_data volume
  • redis: Redis 7-alpine with redis_data volume
  • watchtower: nickfedor/watchtower for automatic container updates (interval: 60s)

CI/CD Pipeline

Gitea Actions workflow (.gitea/workflows/deploy.yml) provides:

  • Checkout code
  • Setup Go 1.22+
  • Go modules cache
  • Lint with golangci-lint v1.54.2
  • Run tests with race detector: go test -v -race ./...
  • Docker Buildx setup
  • Docker login to registry
  • Build and push Docker image with tags: latest and commit SHA

API Endpoints (from specification)

  • GET /v1/cities?query= — City autocomplete
  • GET /v1/cities/{id}/stations — City stations (including neighbors if main closed)
  • POST /v1/routes/search — Search for routes (Pareto-optimal results)
  • GET /v1/routes/{search_id}/{route_id}/geojson — Get route geometry for map
  • GET /v1/stations/{id}/status — Station status
  • POST /internal/admin/stations/{id}/status — Manual station status override (requires auth)
  • GET /v1/preferences/saved-cities?user_id= — Get user's saved cities
  • POST /v1/preferences/saved-cities?user_id= — Add a city to user's saved cities
  • DELETE /v1/preferences/saved-cities/{city_code}?user_id= — Remove a city from user's saved cities
  • GET /v1/preferences/search-history?user_id= — Get user's search history
  • POST /v1/preferences/search-history?user_id= — Add a search to user's history
  • GET /metrics — Get observability metrics (cache hit rates, API quota, circuit breaker trips, search duration)

Key Architectural Features

1. Lazy Graph Expansion

Due to Yandex.Schedules API limitations (no full timetable dump), the service uses:

  • Hub stations (major transport nodes) as anchor points
  • BFS/Dijkstra with depth limiting (4-5 transfers max)
  • On-demand /search requests only for relevant station pairs
  • Aggressive caching to minimize API calls

2. Caching Strategy

Multi-layer TTL approach:

  • City/station directory: 30 days (Postgres + Redis hot cache)
  • /nearest_stations: 30 days (static coordinates)
  • /search: 2-6 hours (near-term), 7 days (far-term dates)
  • /schedule (for closure detection): 1 day
  • /thread: Not cached or 1-5 min TTL (real-time status)

3. Multimodal Routing

  • Graph edges: Real (actual scheduled trips) and Synthetic (city<74><79>↔airport transfers)
  • Transport type stored as attribute for display/filtering
  • Transfer rules based on node type, city tier, and check-in type
  • Pareto-front ranking (time, transfers, cost) rather than single "optimal" route

4. Station Closure Detection

  • Daily cron job checks /schedule for each monitored station
  • N consecutive days of zero trips triggers closure status (N=3 recommended)
  • Automatic fallback to neighboring stations when closed
  • Immediate reactivation when trips resume

5. Map Visualization

  • Routes served as pre-built GeoJSON FeatureCollections
  • Real segments: Solid lines (color by transport type)
  • Synthetic segments: Dashed lines
  • Transfer points: Markers with popup info (connection time, type)
  • Frontend: Leaflet + OSM tiles (no vendor lock-in)

6. User Preferences Cache

  • Saved cities and search history stored per user in Redis
  • 7-day TTL for preference data
  • Accessed via /v1/preferences/ endpoints

7. Observability Metrics

  • Cache hit/miss counts per layer (cache, search, cache_aside)
  • API quota remaining tracking
  • Circuit breaker trip counts
  • Search count and duration histogram (avg in milliseconds)
  • Available via GET /metrics endpoint

8. Search Cache Service

  • Cache-aside pattern for Yandex /search API calls
  • Near-term dates: 3-hour TTL
  • Far-term dates: 7-day TTL
  • Reduces API quota consumption through aggressive caching

9. Transfer Rules / MCT System

  • Minimum Connection Time rules stored in transfer_rules table
  • Rule keys include: airport_internal, airport_internal_through, airport_internal_separate, station_internal, airport_to_city
  • Base MCT is 30 minutes (1800 seconds)
  • Rule keys with suffixes (e.g., _through, _separate) match base keys

10. Route Change Notifications

  • CheckAndRescheduleRoute checks for significant route changes
  • Detects cancellations (edge duration > 1 day) or major delays (duration > 2x normal)
  • Re-searches route when changes detected, returns updated itinerary

Development Guidelines

Error Handling

  • Use circuit breaker pattern in /internal/yandex for API protection
  • Degrade gracefully to stale cache when API unavailable
  • Always provide clear error messages to users

Testing

  • Unit test routing logic with synthetic timetable fixtures
  • Mock external API calls in tests
  • Test cache-aside patterns thoroughly
  • Validate MCT (Minimum Connection Time) calculations

Performance

  • Target: <3-5s for cached routes, <15s for cold cache with multiple segments
  • Monitor: Cache hit rates, API quota consumption, circuit breaker trips
  • Provide progress indicators for long-running searches

Security

  • Validate all inputs (especially for admin endpoints)
  • Protect admin endpoints with proper authentication
  • Never store API keys or secrets in code/repository