# Tunisia Socioeconomic Dashboard
An interactive dashboard over Tunisia's National Institute of Statistics (INS)
data — population, employment & living conditions, prices & economy, and
education & health, by governorate (and by delegation where available).
The INS publishes a data portal at `dataportal.ins.tn` with no documented
public API. This project reverse-engineers its internal XML query endpoints
into a typed Python client, builds a reproducible ETL pipeline on top of it,
and serves the result through a Streamlit app.
## Architecture
```
src/tn_dashboard/
├── ins_api/ # low-level client for dataportal.ins.tn + cached catalog
├── geo/ # governorate/delegation name matching + SVG map projection
└── etl/ # indicator scoring, dataset build, DuckDB schema
scripts/run_etl.py # end-to-end job: API -> data/tunisia.duckdb
app/
├── streamlit_app.py # orchestration only — reads data/tunisia.duckdb, no network calls
├── data_helpers.py # pure data-shaping (what to show), unit tested without Streamlit
├── theme.py # colors, embedded fonts, HTML component builders
├── map_component.py # custom SVG choropleth for st.components.v1.html
└── assets/fonts/ # subsetted Futura, embedded as base64 (no CDN)
config/indicators.yaml # human-curated indicator registry
tests/ # unit tests against fixed API-response fixtures (no live calls)
```
The ETL job and the dashboard are fully decoupled: `run_etl.py` is the only
thing that talks to the INS API and (re)builds `data/tunisia.duckdb`; the
Streamlit app only ever reads from that file. `data/raw/ins_catalog/*.json`
caches the INS source/indicator/region catalogs so the pipeline doesn't
depend on the live server being reachable to run its tests.
### Why a custom map instead of folium
The map is a hand-built SVG choropleth (`tn_dashboard.geo.svg` projects the
shapefile to path data; `map_component.py` renders it in a sandboxed iframe
via `st.components.v1.html …