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>
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
-
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 bothplanemapper-provisionandplanemapper-radarcommands are available on PATH And running either command logs "not implemented" and exits with code 0 -
Given the project is installed When
pytestis run Then the test suite discovers tests and exits with 0 failures (empty stubs acceptable) -
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.servicefiles;pyproject.toml,requirements.txt,requirements-dev.txtAndsrc/planemapper/data/airports.csvis accessible viaimportlib.resourcesAndruff check .passes with zero violations
Tasks / Subtasks
-
Task 1: Create
pyproject.toml(AC: #1, #3)- 1.1 Set
[build-system]to usesetuptoolswithfind_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]withplanemapper-radar = "planemapper.main:main"andplanemapper-provision = "planemapper.provision:main" - 1.4 Add
[tool.setuptools.package-data]entry soplanemapper/data/airports.csvis included in the installed package - 1.5 Add
[tool.ruff]section:line-length = 100,target-version = "py311", and an import boundary rule preventingplanemapper.mainfrom importingplanemapper.provisioning.*
- 1.1 Set
-
Task 2: Create
requirements.txtandrequirements-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, addgpiozero[mock]
- 2.1
-
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.py—main()function that logs "not implemented" and returns; must NOT import fromplanemapper.provisioning.* - 3.8
src/planemapper/provision.py—main()function that logs "not implemented" and returns
- 3.1
-
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
- 4.1
-
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
- 5.1
-
Task 6: Bundle
airports.csvdata file (AC: #3)- 6.1 Download
airports.csvfrom OurAirports (https://ourairports.com/data/airports.csv) and place atsrc/planemapper/data/airports.csv - 6.2 Confirm
pyproject.tomlpackage-data entry coversdata/airports.csv - 6.3 Smoke-test
importlib.resourcesaccess in a scratch script or test to confirm the file is reachable afterpip install -e .
- 6.1 Download
-
Task 7: Create
systemd/unit files (AC: #3)- 7.1
systemd/planemapper-provision.service:Type=oneshot, runsplanemapper-provision; intended to run at first boot / post-reset; include[Install]target - 7.2
systemd/planemapper-radar.service:Restart=always,After=planemapper-provision.service; runsplanemapper-radar
- 7.1
-
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 onepass-body test function so pytest can discover them - 8.5
tests/provisioning/__init__.py(empty) plustest_location.py,test_tiles.py,test_config.py,test_provision_loop.pywith stub test functions
- 8.1
-
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-radarandplanemapper-provision; confirm each logs "not implemented" and exits 0 - 9.3 Run
pytestand confirm zero failures - 9.4 Run
ruff check .and confirm zero violations - 9.5 Run
ruff format --check .and confirm zero formatting issues
- 9.1 Run
Dev Notes
Critical Context
Architecture constraints:
- Package layout uses
src/layout:src/planemapper/— ensurepyproject.tomlspecifiespackage-dir = {"" = "src"}sopip install -e .finds the package. - The
main.pyentry point must not import anything fromplanemapper.provisioning.*. This boundary is enforced by ruff; any violation will causeruff check .to fail. airports.csvmust be bundled as package data and accessed viaimportlib.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 Pythonlogging, notprint) and return (exit code 0). Do not raiseNotImplementedError.
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; guardsplanemapper-radar.servicestartupplanemapper-radar.service:Restart=always,After=planemapper-provision.service— long-running radar loop
ruff configuration:
line-length = 100target-version = "py311"- Import boundary rule:
planemapper.mainmay not import fromplanemapper.provisioning.*(useruff'sflake8-tidy-importsor equivalentbanned-module-level-importssetting)
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.