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