Production-grade FastAPI platform for weather ingestion, historical observation storage, and yearly aggregation.
The application uses clean architecture, a repository layer, PostgreSQL, Alembic migrations, and scheduled ingestion to keep yearly statistics synchronized with raw weather observations.
Represents one daily station observation.
id: primary keystation_id: NOAA station identifierobservation_date: observation datemax_temp_c: daily maximum temperature in Celsiusmin_temp_c: daily minimum temperature in Celsiusprecipitation_cm: daily precipitation in centimeterssource_file: source file name for lineagecreated_at: insert timestamp
Represents one yearly aggregate per station.
id: primary keystation_id: NOAA station identifieryear: aggregate yearavg_max_temp_c: yearly average maximum temperatureavg_min_temp_c: yearly average minimum temperaturetotal_precipitation_cm: yearly precipitation totalobservation_count: number of observations included in the aggregatecreated_at: insert timestamp
WeatherObservationCreateandWeatherObservationReadWeatherYearlyStatCreateandWeatherYearlyStatReadPaginatedWeatherObservationReadPaginatedWeatherYearlyStatReadHTTPErrorResponse,ValidationErrorResponse
flowchart LR
U[Users / Postman] -->|HTTPS| ALB[Application Load Balancer]
ALB --> API[ECS Fargate API Service]
API --> RDS[(RDS PostgreSQL)]
API --> CW[CloudWatch Logs / Metrics]
EB[EventBridge Schedule] --> ING[ECS Fargate Ingestion Task]
ING --> S3[(S3 Raw Weather Files)]
ING --> RDS
ING --> CW
RDS --> BAK[AWS Backup / Snapshots]
S3 --> V[Versioning + Lifecycle]
src/weather_platform/api- API routers and dependenciessrc/weather_platform/services- application servicessrc/weather_platform/repositories- persistence abstractions and SQLAlchemy implementationssrc/weather_platform/models- SQLAlchemy ORM modelssrc/weather_platform/schemas- Pydantic DTOssrc/weather_platform/ingestion- ingestion orchestrationsrc/weather_platform/config- settings and database wiringsrc/weather_platform/utils- shared utilitiesmigrations- Alembic environment and revisionstests- unit and integration tests
copy .env.example .env
make installmake migrateProcess all weather files from wx_data into the configured PostgreSQL database:
make ingestOr run the script directly:
.venv\Scripts\python.exe scripts/process_wx_data.pymake runOr run directly:
.venv\Scripts\python.exe -m uvicorn weather_platform.main:app --reloaddocker compose up --buildThis starts PostgreSQL and the API container. The compose file overrides the API database URL so the container connects to the internal db host.
Base path: /api/v1/weather
POST /observations- Create or update a daily observationGET /observations/{station_id}/{observation_date}- Retrieve one observationGET /observations- Query observations with pagination and filters
Query parameters for GET /observations:
skip: pagination offsetlimit: page size, capped at 1000station_id: optional station filterstart_date: optional inclusive lower boundend_date: optional inclusive upper bound
POST /yearly-stats- Create or update a yearly aggregateGET /yearly-stats/{station_id}- List yearly aggregates for one stationGET /stats- Query yearly stats with pagination and filters
Query parameters for GET /stats:
skip: pagination offsetlimit: page size, capped at 1000station_id: optional station filterstart_year: optional inclusive lower boundend_year: optional inclusive upper bound
200- Successful retrieval201- Successful create or idempotent upsert404- Observation not found422- Validation error500- Internal error
http://localhost:8000/docshttp://localhost:8000/redochttp://localhost:8000/api/v1/weather/observations?skip=0&limit=100
- ALB for public API traffic
- Amazon ECS (Fargate launch type) for FastAPI service
- EventBridge → ECS Fargate task for scheduled ingestion
- RDS PostgreSQL (Multi-AZ) for transactional storage
- S3 for raw weather data and retention
- CloudWatch for logs, metrics, alarms, and dashboards
- AWS Secrets Manager for secure configuration (DB creds, API keys)
- Put ALB in public subnets and application/database workloads in private subnets.
- Use a separate ECS task definition for ingestion so batch failures do not affect the API.
- Store secrets in AWS Secrets Manager or SSM Parameter Store.
- Enable RDS backups, Multi-AZ, and KMS encryption.
- Enable S3 versioning and lifecycle policies for raw file retention.
- Build and test the application in GitHub Actions.
- Build a Docker image and push it to ECR.
- Deploy to staging ECS.
- Run smoke tests against staging.
- Approve and deploy the same image tag to production ECS.
- Trigger ingestion on schedule through EventBridge.
- Use idempotent observation upserts.
- Recompute yearly stats after ingestion so derived data stays current.
- Configure ECS health checks and automatic task replacement.
- Use CloudWatch alarms for API errors, task restarts, and ingestion failures.
- Keep raw input files in S3 so ingestion can be replayed.
copy .env.example .env
make install
make migrate
make ingest
make run