Schema overview
The database is organized around a few core tables:- user_detail — Subscribers: phone number, location (lat/lon, timezone), link to city, subscription state, and activity metrics.
- city_detail — Cached geocoding results (city, state, country, timezone, lat/lon) to avoid repeated API calls.
- message_log — Per-message delivery tracking (status, timing, cost, WhatsApp message ID); can reference user (via
message_textJSON) and city/api. - daily_metrics — One row per day: message counts, deliveries, new/unsubscribed users, active users, cost, timezones served.
- system_health_log — Periodic health snapshots (CPU, memory, disk, connections, queue size, response time, service status).
- api_detail — API definitions (name, call string, params); referenced by message logs.
- api_usage_log — Per-day, per-service API usage (call count, success/error, cost, response time).
- ritu_detail, ayanam_detail — Seasonal/astronomical metadata keyed by city and date ranges.
city_id. message_log can reference city_detail and api_detail. ritu_detail and ayanam_detail also reference city_detail.
Schema diagram (placeholder)
[Placeholder: A diagram of the database schema (tables and relationships) will be inserted here.]Model files
All SQLAlchemy models live under themodels/ package in the repo root:
| File | Table | Purpose |
|---|---|---|
models/user_detail.py | user_detail | Users: phone, location, timezone, city_id, state, subscription and activity fields. |
models/city_detail.py | city_detail | Cities: city, state, country, timezone, latitude, longitude. |
models/message_log.py | message_log | Message delivery logs: status, timing, cost, WhatsApp ID. |
models/daily_metrics.py | daily_metrics | Daily aggregates: sends, deliveries, subscribers, cost, timezones. |
models/system_health_log.py | system_health_log | Health checks: CPU, memory, disk, connections, queue, response time. |
models/api_detail.py | api_detail | API definitions. |
models/api_usage_log.py | api_usage_log | API usage per day/service. |
models/ritu_detail.py | ritu_detail | Ritu (season) data by city/date. |
models/ayanam_detail.py | ayanam_detail | Ayanam data by city/date. |
db instance and model classes via models/__init__.py, which imports from db (see below) and from each model module. The main app and admin portal import from models (e.g. from models import UserDetail, CityDetail).
How the codebase connects to the database
db.py(repo root) creates a single SQLAlchemy instance:app.py(main Flask app) sets the connection string and initializes the app with the DB and migrations:app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("DATABASE_URL")db.init_app(app)migrate = Migrate(app, db)
DATABASE_URLis the PostgreSQL connection string (e.g.postgresql+psycopg2://user:password@host:5432/dbname). In Docker Compose it is set for theweb,celery,beat, andadmin-portalservices.
admin_portal/app.py) uses the same models package and its own Flask app that also sets SQLALCHEMY_DATABASE_URI from DATABASE_URL and calls db.init_app(app). Celery tasks run with a Flask app context that provides the same db and models (see Backend and Scheduling).
How migrations work
Migrations are managed with Flask-Migrate (Alembic under the hood).- Config —
app.pyregistersMigrate(app, db). Alembic uses the Flask app’sdbandSQLALCHEMY_DATABASE_URIviamigrations/env.py, which gets the engine/URL fromcurrent_app.extensions['migrate'].db. - Migration scripts — Stored in
migrations/versions/. Each file is a revision (e.g.b73282c5dc65_initial_tables.py,add_user_profile_fields.py,add_notification_channel.py). They defineupgrade()anddowngrade()using Alembic’sopAPI. - Commands (run from repo root, typically inside the
webcontainer soDATABASE_URLpoints at the DB):- Create a new revision after changing models:
flask db revision -m "description"(then edit the generated file) or
flask db migrate -m "description"(auto-generate from model diff). - Apply all pending migrations:
flask db upgrade - Roll back one revision:
flask db downgrade
- Create a new revision after changing models:
docker compose exec web flask db upgrade (see Quickstart).
