Skip to the content.

Architecture

System context

The project separates data acquisition from API delivery. External source availability therefore does not determine whether read requests can be served.

flowchart LR
    WB[World Bank API] -->|explicit refresh| CLI[Flask refresh-data CLI]
    FX[Versioned fixtures] -->|deterministic refresh| CLI
    CLI --> VAL[Source validation and normalization]
    VAL --> TX[SQLite transaction]
    TX --> C[(countries)]
    TX --> P[(population_observations)]
    CLI --> R[(ingestion_runs)]
    C --> API[Flask read API]
    P --> API
    R --> API
    DQ[SQL data-quality checks] --> API
    C --> DQ
    P --> DQ
    R --> DQ
    API --> CLIENT[API consumer]

Request and ingestion paths

Ingestion path

refresh-data command
→ World Bank client or fixture client
→ source-shape validation
→ semantic normalization
→ constrained SQLite transaction
→ ingestion status update

Read path

HTTP request
→ query/path validation
→ SQLite read model
→ stable JSON response

The read path never performs a live World Bank request.

Component responsibilities

Component Responsibility
country_api/world_bank.py Retrieve live or fixture-shaped World Bank responses
country_api/validation.py Validate request values and normalize source records
country_api/service.py Coordinate refresh runs and ingestion status transitions
country_api/database.py Manage transactions, read models, summaries and quality checks
country_api/routes.py Expose versioned HTTP endpoints and stable response contracts
sql/schema.sql Define relational tables, constraints and indexes
sql/data_quality_queries.sql Define named, reviewable data-quality checks
openapi/openapi.yaml Describe the public HTTP contract

Design decisions

Explicit refresh instead of source calls in routes

This limits latency variance, avoids coupling API availability to an external service and makes failure states observable through ingestion_runs.

SQLite as a bounded persistence layer

SQLite is appropriate for a small portfolio project because it demonstrates relational modelling, constraints, SQL querying and transactions without adding operational infrastructure that does not support the learning objective.

Versioned fixtures in automated tests

CI must remain deterministic and must not depend on network access, changing source data or external rate limits. Fixtures preserve the relevant source shape while keeping test expectations stable.

SQL checks as version-controlled evidence

Data-quality rules are stored in a dedicated SQL file and executed by the application. This keeps quality logic inspectable by both Python and SQL reviewers.

Scope boundary

The architecture intentionally excludes authentication, a frontend, container orchestration, caching and cloud deployment. Those capabilities would not strengthen the current evidence as much as the implemented focus on controlled ingestion, data modelling, validation, observability and API contracts.