Files
planeMapper/_bmad-output/implementation-artifacts/1-1-project-scaffold-and-verified-entry-points.md
T
Matt Edholm 85c8acf767 Implement story 1.1: project scaffold and verified entry points
Creates the complete src/planemapper/ layout with all module stubs,
provisioning and renderer subpackages, airports.csv data bundle,
systemd unit files, and full test scaffold. All three quality gates
pass: pytest 12/12, ruff check zero violations, ruff format clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 22:26:53 -04:00

7.8 KiB

Story 1.1: Project Scaffold & Verified Entry Points

Status: review

Story

As a developer, I want a verified project scaffold with the src/planemapper/ layout, both console entry points installable, all module stubs in place, systemd unit files, and pytest running without error, So that every subsequent story has a consistent, working foundation to build on.

Acceptance Criteria

  1. Given the repository is cloned on a Pi Zero 2W running Raspberry Pi OS Bookworm When pip install -e . is run Then it completes without errors and both planemapper-provision and planemapper-radar commands are available on PATH And running either command logs "not implemented" and exits with code 0

  2. Given the project is installed When pytest is run Then the test suite discovers tests and exits with 0 failures (empty stubs acceptable)

  3. Given the project structure When a developer inspects the repository Then all files from the Architecture directory structure exist: src/planemapper/ with __init__.py, constants.py, models.py, main.py, provision.py, fetcher.py, gpio_ctrl.py, display.py, provisioning/ (7 modules), renderer/ (8 modules), data/airports.csv; systemd/ with both .service files; pyproject.toml, requirements.txt, requirements-dev.txt And src/planemapper/data/airports.csv is accessible via importlib.resources And ruff check . passes with zero violations

Tasks / Subtasks

  • Task 1: Create pyproject.toml (AC: #1, #3)

    • 1.1 Set [build-system] to use setuptools with find_packages
    • 1.2 Set requires-python = ">=3.11" and list pinned runtime dependencies (Pillow==12.2.0, gpiozero==2.0.1, Flask==3.1.3, requests==2.33.1)
    • 1.3 Add [project.scripts] with planemapper-radar = "planemapper.main:main" and planemapper-provision = "planemapper.provision:main"
    • 1.4 Add [tool.setuptools.package-data] entry so planemapper/data/airports.csv is included in the installed package
    • 1.5 Add [tool.ruff] section: line-length = 100, target-version = "py311", and an import boundary rule preventing planemapper.main from importing planemapper.provisioning.*
  • Task 2: Create requirements.txt and requirements-dev.txt (AC: #1, #3)

    • 2.1 requirements.txt: pin Pillow==12.2.0, gpiozero==2.0.1, Flask==3.1.3, requests==2.33.1
    • 2.2 requirements-dev.txt: pin pytest==9.0.3, ruff==0.15.11, add gpiozero[mock]
  • Task 3: Create top-level src/planemapper/ module stubs (AC: #1, #3)

    • 3.1 src/planemapper/__init__.py — empty or version string only
    • 3.2 src/planemapper/constants.py — stub with module docstring and placeholder constants
    • 3.3 src/planemapper/models.py — stub with module docstring
    • 3.4 src/planemapper/fetcher.py — stub with module docstring
    • 3.5 src/planemapper/gpio_ctrl.py — stub with module docstring
    • 3.6 src/planemapper/display.py — stub with module docstring
    • 3.7 src/planemapper/main.pymain() function that logs "not implemented" and returns; must NOT import from planemapper.provisioning.*
    • 3.8 src/planemapper/provision.pymain() function that logs "not implemented" and returns
  • Task 4: Create provisioning/ subpackage stubs (AC: #3)

    • 4.1 src/planemapper/provisioning/__init__.py
    • 4.2 src/planemapper/provisioning/portal.py
    • 4.3 src/planemapper/provisioning/location.py
    • 4.4 src/planemapper/provisioning/tiles.py
    • 4.5 src/planemapper/provisioning/airspace.py
    • 4.6 src/planemapper/provisioning/wifi.py
    • 4.7 src/planemapper/provisioning/config.py
  • Task 5: Create renderer/ subpackage stubs (AC: #3)

    • 5.1 src/planemapper/renderer/__init__.py
    • 5.2 src/planemapper/renderer/renderer.py
    • 5.3 src/planemapper/renderer/projection.py
    • 5.4 src/planemapper/renderer/basemap.py
    • 5.5 src/planemapper/renderer/aircraft.py
    • 5.6 src/planemapper/renderer/airspace.py
    • 5.7 src/planemapper/renderer/colours.py
    • 5.8 src/planemapper/renderer/icons.py
  • Task 6: Bundle airports.csv data file (AC: #3)

    • 6.1 Download airports.csv from OurAirports (https://ourairports.com/data/airports.csv) and place at src/planemapper/data/airports.csv
    • 6.2 Confirm pyproject.toml package-data entry covers data/airports.csv
    • 6.3 Smoke-test importlib.resources access in a scratch script or test to confirm the file is reachable after pip install -e .
  • Task 7: Create systemd/ unit files (AC: #3)

    • 7.1 systemd/planemapper-provision.service: Type=oneshot, runs planemapper-provision; intended to run at first boot / post-reset; include [Install] target
    • 7.2 systemd/planemapper-radar.service: Restart=always, After=planemapper-provision.service; runs planemapper-radar
  • Task 8: Create tests/ structure (AC: #2)

    • 8.1 tests/conftest.py — empty or with a minimal shared fixture comment
    • 8.2 tests/fixtures/aircraft_sample.json — minimal valid JSON stub (empty list acceptable)
    • 8.3 tests/fixtures/airspace_sample.geojson — minimal valid GeoJSON stub
    • 8.4 Top-level test stubs: test_fetcher.py, test_models.py, test_projection.py, test_colours.py, test_icons.py, test_renderer.py, test_pipeline.py, test_gpio_ctrl.py — each contains at least one pass-body test function so pytest can discover them
    • 8.5 tests/provisioning/__init__.py (empty) plus test_location.py, test_tiles.py, test_config.py, test_provision_loop.py with stub test functions
  • Task 9: Verify quality gates pass (AC: #1, #2, #3)

    • 9.1 Run pip install -e . and confirm both entry-point commands exist on PATH
    • 9.2 Run planemapper-radar and planemapper-provision; confirm each logs "not implemented" and exits 0
    • 9.3 Run pytest and confirm zero failures
    • 9.4 Run ruff check . and confirm zero violations
    • 9.5 Run ruff format --check . and confirm zero formatting issues

Dev Notes

Critical Context

Architecture constraints:

  • Package layout uses src/ layout: src/planemapper/ — ensure pyproject.toml specifies package-dir = {"" = "src"} so pip install -e . finds the package.
  • The main.py entry point must not import anything from planemapper.provisioning.*. This boundary is enforced by ruff; any violation will cause ruff check . to fail.
  • airports.csv must be bundled as package data and accessed via importlib.resources, not via a raw file path relative to the source tree, so it works correctly after installation.
  • All stub main() functions must log "not implemented" (using Python logging, not print) and return (exit code 0). Do not raise NotImplementedError.

Pinned dependency versions (do not deviate):

  • Runtime: Pillow==12.2.0, gpiozero==2.0.1, Flask==3.1.3, requests==2.33.1
  • Dev: pytest==9.0.3, ruff==0.15.11, gpiozero[mock]
  • Python: >=3.11

Systemd unit design:

  • planemapper-provision.service: Type=oneshot — runs once and exits; guards planemapper-radar.service startup
  • planemapper-radar.service: Restart=always, After=planemapper-provision.service — long-running radar loop

ruff configuration:

  • line-length = 100
  • target-version = "py311"
  • Import boundary rule: planemapper.main may not import from planemapper.provisioning.* (use ruff's flake8-tidy-imports or equivalent banned-module-level-imports setting)

Testing stance for this story:

  • Tests are stubs only — each file must have at least one discoverable test function (even if it just calls pass) so pytest exits 0 with no collection errors.
  • No actual logic needs to be tested in Story 1.1; that begins in Story 1.2 onwards.