feat: Complete Phase 5 dashboard implementation
Implement full 5-tab Toronto Neighbourhood Dashboard with real data connectivity: Dashboard Structure: - Overview tab with livability scores and rankings - Housing tab with affordability metrics - Safety tab with crime statistics - Demographics tab with population/income data - Amenities tab with parks, schools, transit Figure Factories (portfolio_app/figures/): - bar_charts.py: ranking, stacked, horizontal bars - scatter.py: scatter plots, bubble charts - radar.py: spider/radar charts - demographics.py: donut, age pyramid, income distribution Service Layer (portfolio_app/toronto/services/): - neighbourhood_service.py: queries dbt marts for all tab data - geometry_service.py: generates GeoJSON from PostGIS - Graceful error handling when database unavailable Callbacks (portfolio_app/pages/toronto/callbacks/): - map_callbacks.py: choropleth updates, map click handling - chart_callbacks.py: supporting chart updates - selection_callbacks.py: dropdown handlers, KPI updates Data Pipeline (scripts/data/): - load_toronto_data.py: orchestration script with CLI flags Lessons Learned: - Graceful error handling in service layers - Modular callback structure for multi-tab dashboards - Figure factory pattern for reusable charts Closes: #64, #65, #66, #67, #68, #69, #70 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
# Sprint 9-10 - Graceful Error Handling in Service Layers
|
||||
|
||||
## Context
|
||||
Building the Toronto Neighbourhood Dashboard with a service layer that queries PostgreSQL/PostGIS dbt marts to provide data to Dash callbacks.
|
||||
|
||||
## Problem
|
||||
Initial service layer implementation let database connection errors propagate as unhandled exceptions. When the PostGIS Docker container was unavailable (common on ARM64 systems where the x86_64 image fails), the entire dashboard would crash instead of gracefully degrading.
|
||||
|
||||
## Solution
|
||||
Wrapped database queries in try/except blocks to return empty DataFrames/lists/dicts when the database is unavailable:
|
||||
|
||||
```python
|
||||
def _execute_query(sql: str, params: dict | None = None) -> pd.DataFrame:
|
||||
try:
|
||||
engine = get_engine()
|
||||
with engine.connect() as conn:
|
||||
return pd.read_sql(text(sql), conn, params=params)
|
||||
except Exception:
|
||||
return pd.DataFrame()
|
||||
```
|
||||
|
||||
This allows:
|
||||
1. Dashboard to load and display empty states
|
||||
2. Development/testing without running database
|
||||
3. Graceful degradation in production
|
||||
|
||||
## Prevention
|
||||
- **Always design service layers with graceful degradation** - assume external dependencies can fail
|
||||
- **Return empty collections, not exceptions** - let UI components handle empty states
|
||||
- **Test without database** - verify the app doesn't crash when DB is unavailable
|
||||
- **Consider ARM64 compatibility** - PostGIS images may not support all platforms
|
||||
|
||||
## Tags
|
||||
python, postgresql, service-layer, error-handling, dash, graceful-degradation, arm64
|
||||
Reference in New Issue
Block a user