mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-23 00:16:37 +00:00
component decomposition is done
This commit is contained in:
@@ -0,0 +1,338 @@
|
||||
# Route Data Manager
|
||||
|
||||
## Interface Definition
|
||||
|
||||
**Interface Name**: `IRouteDataManager`
|
||||
|
||||
### Interface Methods
|
||||
|
||||
```python
|
||||
class IRouteDataManager(ABC):
|
||||
@abstractmethod
|
||||
def save_route(self, route: Route) -> str:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def load_route(self, route_id: str) -> Optional[Route]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_waypoint(self, route_id: str, waypoint_id: str, waypoint: Waypoint) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_waypoint(self, route_id: str, waypoint_id: str) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_route_metadata(self, route_id: str) -> Optional[RouteMetadata]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_route(self, route_id: str) -> bool:
|
||||
pass
|
||||
```
|
||||
|
||||
## Component Description
|
||||
|
||||
### Responsibilities
|
||||
- Manage route persistence and retrieval
|
||||
- Coordinate with Route Database Layer for data operations
|
||||
- Handle waypoint CRUD operations within routes
|
||||
- Manage route metadata (timestamps, statistics)
|
||||
- Ensure data consistency and transaction management
|
||||
|
||||
### Scope
|
||||
- Business logic layer between REST API and Database Layer
|
||||
- Route lifecycle management
|
||||
- Waypoint batch operations
|
||||
- Query optimization for large route datasets
|
||||
- Caching layer for frequently accessed routes (optional)
|
||||
|
||||
## API Methods
|
||||
|
||||
### `save_route(route: Route) -> str`
|
||||
|
||||
**Description**: Persists a new route with initial waypoints and geofences.
|
||||
|
||||
**Called By**:
|
||||
- R01 Route REST API
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
Route:
|
||||
id: Optional[str] # Generated if not provided
|
||||
name: str
|
||||
description: str
|
||||
points: List[Waypoint]
|
||||
geofences: Geofences
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
route_id: str # UUID of saved route
|
||||
```
|
||||
|
||||
**Error Conditions**:
|
||||
- `DuplicateRouteError`: Route with same ID exists
|
||||
- `ValidationError`: Invalid route data
|
||||
- `DatabaseError`: Database connection or constraint violation
|
||||
|
||||
**Test Cases**:
|
||||
1. **New route**: Valid route → returns routeId, verifies in DB
|
||||
2. **Route with 1000 waypoints**: Large route → saves successfully
|
||||
3. **Duplicate ID**: Existing route ID → raises DuplicateRouteError
|
||||
4. **Transaction rollback**: DB error mid-save → no partial data persisted
|
||||
|
||||
---
|
||||
|
||||
### `load_route(route_id: str) -> Optional[Route]`
|
||||
|
||||
**Description**: Retrieves complete route data including all waypoints.
|
||||
|
||||
**Called By**:
|
||||
- R01 Route REST API
|
||||
- R03 Waypoint Validator (for context validation)
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
route_id: str
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
Route or None if not found
|
||||
```
|
||||
|
||||
**Error Conditions**:
|
||||
- `DatabaseError`: Database connection error
|
||||
- Returns `None`: Route not found (not an error condition)
|
||||
|
||||
**Test Cases**:
|
||||
1. **Existing route**: Valid ID → returns complete Route object
|
||||
2. **Non-existent route**: Invalid ID → returns None
|
||||
3. **Large route**: 3000 waypoints → returns all data efficiently
|
||||
4. **Concurrent reads**: Multiple simultaneous loads → all succeed
|
||||
|
||||
---
|
||||
|
||||
### `update_waypoint(route_id: str, waypoint_id: str, waypoint: Waypoint) -> bool`
|
||||
|
||||
**Description**: Updates a single waypoint within a route. Optimized for high-frequency GPS-Denied updates.
|
||||
|
||||
**Called By**:
|
||||
- R01 Route REST API
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
route_id: str
|
||||
waypoint_id: str
|
||||
waypoint: Waypoint
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
bool: True if updated, False if route/waypoint not found
|
||||
```
|
||||
|
||||
**Error Conditions**:
|
||||
- `ValidationError`: Invalid waypoint data
|
||||
- `DatabaseError`: Database error
|
||||
|
||||
**Test Cases**:
|
||||
1. **Update existing waypoint**: Valid data → returns True
|
||||
2. **Non-existent waypoint**: Invalid waypoint_id → returns False
|
||||
3. **Concurrent updates**: 100 simultaneous updates to different waypoints → all succeed
|
||||
4. **Update timestamp**: Automatically updates route.updated_at
|
||||
|
||||
---
|
||||
|
||||
### `delete_waypoint(route_id: str, waypoint_id: str) -> bool`
|
||||
|
||||
**Description**: Deletes a specific waypoint from a route.
|
||||
|
||||
**Called By**:
|
||||
- R01 Route REST API (rare, for manual corrections)
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
route_id: str
|
||||
waypoint_id: str
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
bool: True if deleted, False if not found
|
||||
```
|
||||
|
||||
**Error Conditions**:
|
||||
- `DatabaseError`: Database error
|
||||
|
||||
**Test Cases**:
|
||||
1. **Delete existing waypoint**: Valid IDs → returns True
|
||||
2. **Delete non-existent waypoint**: Invalid ID → returns False
|
||||
3. **Delete all waypoints**: Delete all waypoints one by one → succeeds
|
||||
|
||||
---
|
||||
|
||||
### `get_route_metadata(route_id: str) -> Optional[RouteMetadata]`
|
||||
|
||||
**Description**: Retrieves route metadata without loading all waypoints (lightweight operation).
|
||||
|
||||
**Called By**:
|
||||
- R01 Route REST API
|
||||
- Client applications (route listing)
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
route_id: str
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
RouteMetadata:
|
||||
route_id: str
|
||||
name: str
|
||||
description: str
|
||||
waypoint_count: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
```
|
||||
|
||||
**Error Conditions**:
|
||||
- Returns `None`: Route not found
|
||||
|
||||
**Test Cases**:
|
||||
1. **Get metadata**: Valid ID → returns metadata without waypoints
|
||||
2. **Performance**: Metadata retrieval < 50ms even for 3000-waypoint route
|
||||
|
||||
---
|
||||
|
||||
### `delete_route(route_id: str) -> bool`
|
||||
|
||||
**Description**: Deletes a route and all associated waypoints.
|
||||
|
||||
**Called By**:
|
||||
- R01 Route REST API
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
route_id: str
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
bool: True if deleted, False if not found
|
||||
```
|
||||
|
||||
**Error Conditions**:
|
||||
- `DatabaseError`: Database error
|
||||
|
||||
**Test Cases**:
|
||||
1. **Delete route**: Valid ID → deletes route and all waypoints
|
||||
2. **Cascade delete**: Verify all waypoints deleted
|
||||
3. **Non-existent route**: Invalid ID → returns False
|
||||
|
||||
## Integration Tests
|
||||
|
||||
### Test 1: Complete Route Lifecycle
|
||||
1. save_route() with 100 waypoints
|
||||
2. load_route() and verify all data
|
||||
3. update_waypoint() for 50 waypoints
|
||||
4. delete_waypoint() for 10 waypoints
|
||||
5. get_route_metadata() and verify count
|
||||
6. delete_route() and verify removal
|
||||
|
||||
### Test 2: High-Frequency Update Simulation (GPS-Denied Pattern)
|
||||
1. save_route() with 2000 waypoints
|
||||
2. Simulate per-frame updates: update_waypoint() × 2000 in sequence
|
||||
3. Verify all updates persisted correctly
|
||||
4. Measure total time < 200 seconds (100ms per update)
|
||||
|
||||
### Test 3: Concurrent Route Operations
|
||||
1. Create 10 routes concurrently
|
||||
2. Update different waypoints in parallel (100 concurrent updates)
|
||||
3. Delete 5 routes concurrently while updating others
|
||||
4. Verify data consistency
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
### Performance
|
||||
- **save_route**: < 300ms for routes with 100 waypoints
|
||||
- **load_route**: < 150ms for routes with 2000 waypoints
|
||||
- **update_waypoint**: < 50ms (critical path for GPS-Denied)
|
||||
- **get_route_metadata**: < 30ms
|
||||
- **delete_route**: < 200ms
|
||||
|
||||
### Scalability
|
||||
- Support 1000+ concurrent route operations
|
||||
- Handle routes with up to 3000 waypoints efficiently
|
||||
- Optimize for read-heavy workload (90% reads, 10% writes)
|
||||
|
||||
### Reliability
|
||||
- ACID transaction guarantees
|
||||
- Automatic retry on transient database errors (3 attempts)
|
||||
- Data validation before persistence
|
||||
|
||||
### Maintainability
|
||||
- Clear separation from database implementation
|
||||
- Support for future caching layer integration
|
||||
- Comprehensive error handling and logging
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Internal Components
|
||||
- **R03 Waypoint Validator**: Validates waypoints before persistence
|
||||
- **R04 Route Database Layer**: For all database operations
|
||||
|
||||
### External Dependencies
|
||||
- None (pure business logic layer)
|
||||
|
||||
## Data Models
|
||||
|
||||
### Route
|
||||
```python
|
||||
class Route(BaseModel):
|
||||
id: str # UUID
|
||||
name: str
|
||||
description: str
|
||||
points: List[Waypoint]
|
||||
geofences: Geofences
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
```
|
||||
|
||||
### RouteMetadata
|
||||
```python
|
||||
class RouteMetadata(BaseModel):
|
||||
route_id: str
|
||||
name: str
|
||||
description: str
|
||||
waypoint_count: int
|
||||
geofence_count: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
```
|
||||
|
||||
### Waypoint
|
||||
```python
|
||||
class Waypoint(BaseModel):
|
||||
id: str
|
||||
lat: float
|
||||
lon: float
|
||||
altitude: Optional[float]
|
||||
confidence: float
|
||||
timestamp: datetime
|
||||
refined: bool
|
||||
```
|
||||
|
||||
### Geofences
|
||||
```python
|
||||
class Polygon(BaseModel):
|
||||
north_west: GPSPoint
|
||||
south_east: GPSPoint
|
||||
|
||||
class Geofences(BaseModel):
|
||||
polygons: List[Polygon]
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user