risk_monitor.db). Tables are created automatically on startup via Base.metadata.create_all(bind=engine).
Business
Table name:businesses
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
id | Integer | No | Primary key, auto-incremented |
name | String(255) | No | Business display name, required on creation |
industry | String(100) | Yes | Industry category; used by the risk engine for modifiers |
country | String(100) | Yes | Country of operation; used by the risk engine for modifiers |
created_at | DateTime | No | UTC timestamp set automatically on insert |
Relationship
risk_evaluations is a one-to-many relationship to RiskEvaluation, ordered by evaluated_at descending. Accessing business.risk_evaluations[0] always returns the most recent evaluation.
RiskEvaluation
Table name:risk_evaluations
Columns
| Column | Type | Nullable | Description |
|---|---|---|---|
id | Integer | No | Primary key, auto-incremented |
business_id | Integer | No | Foreign key to businesses.id |
risk_score | Float | No | Final computed score, 0.0–100.0 rounded to 1 decimal place |
risk_level | String(20) | No | One of: low, medium, high, critical |
factors | Text | Yes | JSON string containing the score component breakdown |
evaluated_at | DateTime | No | UTC timestamp set automatically on insert |
Relationship
business is a many-to-one back-reference to Business.
The factors JSON text pattern
SQLite has no native JSON column type. Thefactors column stores a serialised JSON string produced by json.dumps() in the risk engine:
json.loads() before passing it to templates:
Parsed factors structure
Database setup
The database engine and session factory are defined inapp/database.py:
check_same_thread=False is required for SQLite when the session is used across threads, which FastAPI’s dependency injection can trigger. Each request gets its own session via the get_db dependency, which ensures the session is closed after the response is returned.
Tests use a separate
test_risk_monitor.db database so seed data in the main database is never affected by test runs.Architecture overview
Request flow, HTMX partials pattern, and design decisions
Risk engine
How risk scores are computed from the industry and country fields