# 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.