Files
gps-denied-onboard/.planning/codebase/STRUCTURE.md
T
Yuzviak 2dd60a0e37 Add codebase map to .planning/codebase/
7 structured documents covering stack, integrations, architecture,
structure, conventions, testing, and concerns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 20:26:52 +03:00

249 lines
12 KiB
Markdown

# Codebase Structure
**Analysis Date:** 2026-04-01
## Directory Layout
```
gps-denied-onboard/
├── src/
│ └── gps_denied/ # Main package
│ ├── __init__.py # Package version
│ ├── __main__.py # Entry point (uvicorn runner)
│ ├── app.py # FastAPI app factory + lifespan
│ ├── config.py # Pydantic-settings configuration classes
│ ├── api/
│ │ ├── __init__.py
│ │ ├── deps.py # FastAPI dependency providers (singletons)
│ │ └── routers/
│ │ ├── __init__.py
│ │ └── flights.py # All /flights/* endpoints
│ ├── core/
│ │ ├── processor.py # FlightProcessor — main orchestrator
│ │ ├── pipeline.py # ImageInputPipeline — image ingestion/queuing
│ │ ├── vo.py # SequentialVisualOdometry (SuperPoint+LightGlue)
│ │ ├── satellite.py # SatelliteDataManager (tile fetch/cache)
│ │ ├── gpr.py # GlobalPlaceRecognition (AnyLoc/DINOv2)
│ │ ├── metric.py # MetricRefinement (LiteSAM homography alignment)
│ │ ├── graph.py # FactorGraphOptimizer (GTSAM/mock pose graph)
│ │ ├── chunk_manager.py # RouteChunkManager (disconnected segments)
│ │ ├── recovery.py # FailureRecoveryCoordinator (tracking loss handling)
│ │ ├── rotation.py # ImageRotationManager (360° sweep, heading tracking)
│ │ ├── coordinates.py # CoordinateTransformer (ENU↔GPS, pixel→GPS)
│ │ ├── models.py # ModelManager + MockInferenceEngine
│ │ ├── results.py # ResultManager (DB + SSE publish)
│ │ └── sse.py # SSEEventStreamer (per-flight async queues)
│ ├── db/
│ │ ├── __init__.py
│ │ ├── engine.py # Async SQLAlchemy engine + session factory
│ │ ├── models.py # ORM table definitions (8 tables)
│ │ └── repository.py # FlightRepository DAO (all SQL operations)
│ ├── schemas/
│ │ ├── __init__.py # GPSPoint, CameraParameters, Polygon, Geofences
│ │ ├── flight.py # Flight CRUD request/response schemas
│ │ ├── image.py # ImageBatch, ImageData, ProcessedBatch schemas
│ │ ├── vo.py # Features, Matches, Motion, RelativePose
│ │ ├── gpr.py # TileCandidate, DatabaseMatch
│ │ ├── metric.py # AlignmentResult, ChunkAlignmentResult, Sim3Transform
│ │ ├── satellite.py # TileCoords, TileBounds
│ │ ├── graph.py # Pose, OptimizationResult, FactorGraphConfig
│ │ ├── chunk.py # ChunkHandle, ChunkStatus enum
│ │ ├── rotation.py # RotationResult, HeadingHistory
│ │ ├── model.py # InferenceEngine base schema
│ │ └── events.py # SSEMessage, SSEEventType, FrameProcessedEvent, etc.
│ └── utils/
│ └── mercator.py # Slippy map tile math (lat/lon↔tile x/y/bounds)
├── _docs/
│ ├── _autopilot_state.md # GSD planning state tracker
│ ├── 01_solution/
│ │ └── solution.md # Master architecture document (finalized draft 06)
│ └── 02_document/
│ └── tests/ # Test scenario specifications (43 scenarios)
├── .planning/
│ └── codebase/ # GSD mapping documents (this directory)
├── .venv/ # Python virtual environment (committed or local)
├── pyproject.toml # Project metadata and dependencies
└── flight_data.db # SQLite DB (runtime artifact, not committed)
```
## Directory Purposes
**`src/gps_denied/`:**
- Purpose: Top-level Python package; everything importable from here
- Key files: `app.py` (create_app factory), `config.py` (all settings), `__main__.py` (entrypoint)
**`src/gps_denied/api/`:**
- Purpose: HTTP API surface only — routing, request/response handling, dependency injection
- Contains: One router (`flights.py`) with 9 endpoints, `deps.py` with 3 singleton providers
- Key files: `routers/flights.py` (all endpoints), `deps.py` (ProcessorDep, SessionDep, RepoDep)
**`src/gps_denied/core/`:**
- Purpose: All processing logic — state machines, algorithms, pipeline components
- Module count: 14 files
- Key files: `processor.py` (orchestrator), `models.py` (inference abstraction), `graph.py` (pose graph)
- Note: Each component has a matching `I*` ABC interface defined in the same file
**`src/gps_denied/db/`:**
- Purpose: Database access only — no business logic
- Contains: Engine setup, ORM models, one repository class
- Key files: `models.py` (8 ORM tables), `repository.py` (all DB operations)
**`src/gps_denied/schemas/`:**
- Purpose: Pydantic data contracts; shared across API, core, and DB layers
- Contains: 12 schema files covering every domain concept
- Key files: `__init__.py` (GPSPoint, CameraParameters — imported everywhere), `flight.py` (largest — all REST schemas)
**`src/gps_denied/utils/`:**
- Purpose: Pure utility functions with no side effects
- Contains: `mercator.py` — Mercator projection math for tile coordinate conversion
- Used by: `satellite.py` exclusively
**`_docs/`:**
- Purpose: Architecture documentation and planning artifacts — not source code
- Key files: `01_solution/solution.md` (the authoritative design doc), `_autopilot_state.md` (GSD planning tracker)
## Key File Locations
**Entry Points:**
- `src/gps_denied/__main__.py`: Invoked by `python -m gps_denied`; starts uvicorn
- `src/gps_denied/app.py`: `create_app()` factory; `app` module-level instance used by uvicorn
**Configuration:**
- `src/gps_denied/config.py`: All settings via `pydantic-settings`; reads from `.env` and env vars
- `DB_URL` → SQLAlchemy connection string (default: SQLite)
- `TILES_ZOOM_LEVEL`, `TILES_CACHE_DIR`, `TILES_API_KEY` → satellite tile provider
- `MODEL_WEIGHTS_DIR`, `MODEL_SUPERPOINT_PATH`, etc. → model file paths
- `RECOVERY_*`, `ROTATION_*` → algorithm thresholds
**Core Orchestration:**
- `src/gps_denied/core/processor.py`: `FlightProcessor` — only class that calls other pipeline components
**Dependency Wiring:**
- `src/gps_denied/api/deps.py`: Single location where singletons (`FlightProcessor`, `SSEEventStreamer`) are created and wired; `ProcessorDep` type alias used in all routers
**Database Schema:**
- `src/gps_denied/db/models.py`: All 8 ORM tables with cascade deletes; ground truth for DB schema
**Pydantic Contracts:**
- `src/gps_denied/schemas/__init__.py`: `GPSPoint` and `CameraParameters` — imported by nearly every module
## Naming Conventions
**Files:**
- `snake_case.py` throughout
- Core components named after their function: `vo.py`, `gpr.py`, `metric.py`, `graph.py`
- Interfaces co-located with implementation in the same file (`ISequentialVisualOdometry` and `SequentialVisualOdometry` both in `vo.py`)
**Classes:**
- Implementation classes: `PascalCase` noun phrases (`FlightProcessor`, `RouteChunkManager`)
- Interfaces: `I` prefix + implementation name (`IRouteChunkManager`)
- ORM models: suffixed with `Row` (`FlightRow`, `WaypointRow`)
- Pydantic models: suffixed with `Request`/`Response` for API schemas; bare names for internal data
**Functions:**
- `snake_case`
- Async functions throughout API and DB layers; sync in core (except `process_frame` which is async)
**Constants/Enums:**
- `TrackingState`: `str, Enum` with lowercase values (`"normal"`, `"lost"`, `"recovery"`)
- `SSEEventType`: `str, Enum` with snake_case values
- `ChunkStatus`: `str, Enum`
## Where to Add New Code
**New API endpoint:**
- Add route function to `src/gps_denied/api/routers/flights.py`
- Add request/response Pydantic models to `src/gps_denied/schemas/flight.py`
- Add business logic method to `src/gps_denied/core/processor.py`
- If new router prefix needed: create `src/gps_denied/api/routers/{name}.py` and register in `app.py`
**New pipeline component:**
- Create `src/gps_denied/core/{component_name}.py`
- Define `I{ComponentName}(ABC)` interface and `{ComponentName}` implementation in same file
- Add schemas to `src/gps_denied/schemas/{component_name}.py`
- Add component instantiation to `app.py` lifespan block
- Inject via `FlightProcessor.attach_components()` and call from `process_frame()`
**New database table:**
- Add `{Name}Row(Base)` to `src/gps_denied/db/models.py`
- Add CRUD methods to `src/gps_denied/db/repository.py`
- Add foreign key + relationship to `FlightRow` if flight-scoped
**New configuration setting:**
- Add field to the appropriate `BaseSettings` subclass in `src/gps_denied/config.py`
- Use `ENV_PREFIX__FIELD_NAME` env var pattern
**New schema type:**
- Add to `src/gps_denied/schemas/{relevant_file}.py` or create new file
- If broadly shared (like `GPSPoint`), add to `src/gps_denied/schemas/__init__.py`
**Utility functions:**
- Add to `src/gps_denied/utils/mercator.py` if geospatial math
- Create `src/gps_denied/utils/{name}.py` for other pure utilities
## Special Directories
**`.venv/`:**
- Purpose: Python virtual environment
- Generated: Yes (via `python -m venv` or uv)
- Committed: Present in tree (check `.gitignore`)
**`_docs/`:**
- Purpose: Architecture docs, test specs, GSD planning artifacts
- Generated: No (hand-authored)
- Committed: Yes
**`.planning/`:**
- Purpose: GSD (Get Stuff Done) planning system — phase plans, codebase maps
- Generated: By GSD commands
- Committed: Yes (used by CI/planning tools)
**`.image_storage/` (runtime):**
- Purpose: Disk storage for uploaded UAV images per flight
- Created by: `ImageInputPipeline.store_images()`
- Path: Relative to process CWD; configurable via `ImageInputPipeline(storage_dir=...)`
**`.satellite_cache/` (runtime):**
- Purpose: diskcache directory for satellite tiles
- Created by: `SatelliteDataManager.__init__()`
- Size limit: 10GB default
## Module Dependency Graph (simplified)
```
api/routers/flights.py
→ api/deps.py
→ core/processor.py
→ core/pipeline.py (image ingestion)
→ core/results.py (DB + SSE publish)
→ core/sse.py (event streaming)
→ [via attach_components]
→ core/vo.py → core/models.py
→ core/gpr.py → core/models.py
→ core/metric.py → core/models.py
→ core/graph.py (optional: gtsam)
→ core/chunk_manager.py → core/graph.py
→ core/recovery.py → core/chunk_manager.py
→ core/gpr.py
→ core/metric.py
→ core/rotation.py
→ db/repository.py
→ db/models.py
→ core/sse.py
→ db/engine.py
core/satellite.py (standalone — not wired into processor yet)
core/coordinates.py (standalone — not wired into processor yet)
utils/mercator.py → only used by core/satellite.py
schemas/* → imported by all layers (no internal imports)
config.py → imported by db/engine.py, and anywhere settings needed
```
**Notably standalone (not connected to processor):**
- `src/gps_denied/core/satellite.py`: `SatelliteDataManager` — instantiated nowhere in `app.py` or `processor.py`; satellite tiles fetched inline with mock in `processor.py`
- `src/gps_denied/core/coordinates.py`: `CoordinateTransformer` — not instantiated in the pipeline; `convert_object_to_gps` in processor returns a hardcoded stub (`GPSPoint(lat=48.0, lon=37.0)`)
---
*Structure analysis: 2026-04-01*