agenda/AGENTS.md
Edward Betts 53f4252b92 Refactor bus/coach loading and rendering to share code.
Extract `load_road_transport()` as a shared helper for bus and coach,
combining the near-identical route rendering blocks in `get_trip_routes`
and `Trip.elements()` into single `in ("coach", "bus")` branches.
Document transport type patterns in AGENTS.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 12:52:28 +00:00

3.5 KiB

Development Guidelines

Project Overview

This is a personal agenda web application built with Flask that tracks various events and important dates:

  • Events: birthdays, holidays, travel itineraries, conferences, waste collection schedules
  • Space launches, meteor showers, astronomical events
  • Financial information (FX rates, stock market)
  • UK-specific features (holidays, waste collection, railway schedules)
  • Authentication via UniAuth
  • Frontend uses Bootstrap 5, Leaflet for maps, FullCalendar for calendar views

Python Environment

  • Always use python3 directly, never python
  • All Python code should include type annotations
  • Use typing.Any instead of Any in type hints (import from typing module)
  • Run mypy --strict (fix any type errors in the file) and black on modified code after creating or modifying Python files
  • Avoid running black .
  • Main entry point: python3 web_view.py (Flask app on port 5000)
  • Tests: Use pytest (tests in /tests/ directory)

Project Structure

  • agenda/ - Main Python package with modules for different event types
  • web_view.py - Flask web application entry point
  • templates/ - Jinja2 HTML templates
  • static/ - CSS, JS, and frontend assets
  • config/ - Configuration files
  • personal-data/ - User's personal data (not in git)

Git Workflow

  • Avoid committing unrelated untracked files (e.g., node_modules/, build artifacts)
  • Only commit relevant project files
  • Personal data directory (personal-data/) is excluded from git

Notes

  • Trip stats new-country badges come from agenda.stats.calculate_yearly_stats via year_stats.new_countries (first-visit year, excluding PREVIOUSLY_VISITED).
  • Trip stats are calculated in agenda/stats.py:
    • travel_legs() extracts airlines, airports, and stations from individual trip travel legs
    • calculate_yearly_stats() aggregates stats per year including flight/train counts, airlines, airports, stations
    • calculate_overall_stats() aggregates yearly stats into overall totals for the summary section

Travel type patterns

Transport types: flight, train, ferry, coach, bus.

Road transport (bus and coach) share a common loader load_road_transport() in trip.py. load_coaches and load_buses are thin wrappers that pass type name, YAML filenames, and CO2 factor (coach: 0.027 kg/km, bus: 0.1 kg/km). Both use from_station/to_station fields and support scalar or dict-keyed GeoJSON route filenames in the stop/station data.

Ferry is loaded separately: uses from_terminal/to_terminal fields and GeoJSON routes come from the terminal's routes dict (always a dict, not scalar).

Route rendering (get_trip_routes): bus and coach are handled in a single combined block (they use the same pattern — from_station/to_station, {type}_routes/ folder). Ferry always has a geojson file and renders as type "train" for the map renderer.

Trip elements (Trip.elements() in types.py): bus and coach are handled in a single combined block using item["type"] in ("coach", "bus"). Ferry is separate because it uses from_terminal/to_terminal and always requires arrive (not optional).

Location collection (get_locations): bus → bus_stop, coach → coach_station, ferry → ferry_terminal (all separate map pin types).

CO2 factors (kg CO2e per passenger per km): train 0.037, coach 0.027, ferry 0.02254, bus 0.1.

Schengen tracking: ferry journeys are tracked for Schengen compliance; bus and coach are not.