| # OmniDiag β Entity Relationship Diagram |
|
|
| ## Overview |
|
|
| The OmniDiag database consists of **7 tables** supporting multi-disease clinical decision support with role-based access control, patient records, prediction history, expert review workflow, and immutable audit logging. |
|
|
| --- |
|
|
| ## Entity Relationship Diagram |
|
|
| ``` |
| ββββββββββββββββββββββββ ββββββββββββββββββββββββ ββββββββββββββββββββββββββββ |
| β roles β β user_roles β β users β |
| ββββββββββββββββββββββββ€ ββββββββββββββββββββββββ€ ββββββββββββββββββββββββββββ€ |
| β PK β id: Integer βββββββββ FK β role_id: Integerβ β PK β id: UUID β |
| β β name: String(50)β β FK β user_id: UUID ββββββββΊβ β email: String(255) β |
| β β description β β β assigned_at β β β hashed_password: Str β |
| ββββββββββββββββββββββββ ββββββββββββββββββββββββ β β full_name: String(255)β |
| β β is_active: Boolean β |
| β β created_at: DateTime β |
| β β updated_at: DateTime β |
| βββββββββββββ¬βββββββββββββββ |
| β |
| βββββββββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββ |
| β β β |
| βΌ βΌ βΌ |
| ββββββββββββββββββββββββ ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ |
| β patients β β predictions β β audit_logs β |
| ββββββββββββββββββββββββ€ ββββββββββββββββββββββββββββ€ ββββββββββββββββββββββββββββ€ |
| β PK β id: UUID β β PK β id: UUID β β PK β id: BigInteger β |
| β β mrn: String(50) ββββββββββββββββββββββββ FK β patient_id: UUID β β FK β user_id: UUID β |
| β β full_name: Str β β β disease: Str(100) β β β endpoint: Str(255) β |
| β β date_of_birth β β β input_features: JSONβ β β method: String(10) β |
| β β gender: Str(10) β β β prediction: Integer β β β status_code: Integer β |
| β β contact_email β β β confidence: Float β β β ip_address: Str(45) β |
| β FK β created_by: UUIDβ β β diagnosis: Str(100) β β β duration_ms: Float β |
| β β created_at β β β shap_chart: JSON β β β created_at: DateTime β |
| β β deleted_at β β FK β created_by: UUID β ββββββββββββββββββββββββββββ |
| ββββββββββββββββββββββββ β β created_at: DateTimeβ |
| βββββββββββββ¬βββββββββββββββ |
| β |
| β (1:1) |
| βΌ |
| ββββββββββββββββββββββββββββ |
| β review_queue β |
| ββββββββββββββββββββββββββββ€ |
| β PK β id: UUID β |
| β FK β prediction_id: UUID β |
| β β uncertainty_score β |
| β FK β reviewer_id: UUID β |
| β β label: Integer β |
| β β reviewed_at β |
| β β status: String(20) β |
| β β created_at: DateTimeβ |
| ββββββββββββββββββββββββββββ |
| ``` |
|
|
| --- |
|
|
| ## Table Definitions |
|
|
| ### 1. `roles` |
|
|
| Defines role-based access control levels. |
|
|
| | Column | Type | Constraints | Description | |
| |--------|------|-------------|-------------| |
| | `id` | `Integer` | `PK`, `autoincrement` | Auto-incrementing ID | |
| | `name` | `String(50)` | `UNIQUE`, `NOT NULL` | Role name: `super_admin`, `doctor`, `nurse`, `viewer` | |
| | `description` | `String(255)` | `nullable` | Human-readable description | |
|
|
| **Seed data:** |
| ```sql |
| INSERT INTO roles (name, description) VALUES |
| ('super_admin', 'Full system access β user management, audit review, model administration'), |
| ('doctor', 'Clinical access β predict, explain, counterfactuals, patient records'), |
| ('nurse', 'Limited clinical access β predict, view patient records'), |
| ('viewer', 'Read-only access β view predictions and patient data'); |
| ``` |
|
|
| --- |
|
|
| ### 2. `users` |
|
|
| System users (doctors, nurses, admins). |
|
|
| | Column | Type | Constraints | Description | |
| |--------|------|-------------|-------------| |
| | `id` | `UUID` | `PK`, `default=uuid4` | UUID primary key | |
| | `email` | `String(255)` | `UNIQUE`, `NOT NULL`, `INDEX` | Login email | |
| | `hashed_password` | `String(255)` | `NOT NULL` | bcrypt-hashed password | |
| | `full_name` | `String(255)` | `NOT NULL` | Display name | |
| | `is_active` | `Boolean` | `default=True` | Soft disable account | |
| | `created_at` | `DateTime(tz)` | `server_default=now()` | Account creation timestamp | |
| | `updated_at` | `DateTime(tz)` | `onupdate=now()` | Last profile update | |
|
|
| **Relationships:** |
| - `roles` (many-to-many via `user_roles` join table) |
| - `predictions` (one-to-many, as `created_by`) |
| - `patients` (one-to-many, as `created_by`) |
| - `audit_logs` (one-to-many) |
| - `review_queue` (one-to-many, as `reviewer_id`) |
|
|
| --- |
|
|
| ### 3. `user_roles` |
| |
| Association (join) table linking users to roles (many-to-many). |
| |
| | Column | Type | Constraints | Description | |
| |--------|------|-------------|-------------| |
| | `user_id` | `UUID` | `FK β users.id`, `PK (composite)` | Reference to user | |
| | `role_id` | `Integer` | `FK β roles.id`, `PK (composite)` | Reference to role | |
| | `assigned_at` | `DateTime` | `server_default=now()` | When the role was assigned | |
|
|
| **Foreign Keys:** |
| - `user_id` β `users.id` (`ON DELETE CASCADE`) |
| - `role_id` β `roles.id` (`ON DELETE CASCADE`) |
|
|
| --- |
|
|
| ### 4. `patients` |
|
|
| Patient demographic records with soft-delete support. |
|
|
| | Column | Type | Constraints | Description | |
| |--------|------|-------------|-------------| |
| | `id` | `UUID` | `PK`, `default=uuid4` | UUID primary key | |
| | `mrn` | `String(50)` | `UNIQUE`, `NOT NULL`, `INDEX` | Medical Record Number | |
| | `full_name` | `String(255)` | `NOT NULL` | Patient's full name | |
| | `date_of_birth` | `Date` | `nullable` | Date of birth | |
| | `gender` | `String(10)` | `nullable` | Gender identity | |
| | `contact_email` | `String(255)` | `nullable` | Contact email | |
| | `created_by` | `UUID` | `FK β users.id`, `nullable` | Who registered this patient | |
| | `created_at` | `DateTime(tz)` | `server_default=now()` | Registration timestamp | |
| | `deleted_at` | `DateTime` | `nullable` | Soft-delete timestamp (GDPR) | |
|
|
| **Foreign Keys:** |
| - `created_by` β `users.id` (`SET NULL`) |
|
|
| **Relationships:** |
| - `predictions` (one-to-many) |
|
|
| --- |
|
|
| ### 5. `predictions` |
|
|
| Every prediction made by the system, linked to a patient (or anonymous). |
|
|
| | Column | Type | Constraints | Description | |
| |--------|------|-------------|-------------| |
| | `id` | `UUID` | `PK`, `default=uuid4` | UUID primary key | |
| | `patient_id` | `UUID` | `FK β patients.id`, `nullable` | Patient (nullable for anonymous) | |
| | `disease` | `String(100)` | `NOT NULL`, `INDEX` | Disease key (e.g., `heart_disease`) | |
| | `input_features` | `JSON` | `NOT NULL` | Raw patient data dict sent to model | |
| | `prediction` | `Integer` | `NOT NULL` | Model output: `0` (negative) or `1` (positive) | |
| | `confidence` | `Float` | `NOT NULL` | Probability score `0.0`β`1.0` | |
| | `diagnosis` | `String(100)` | `nullable` | Human label: `"Positive"` / `"Negative"` | |
| | `shap_chart_data` | `JSON` | `nullable` | Stored SHAP values (if explain was called) | |
| | `created_by` | `UUID` | `FK β users.id`, `nullable` | Who initiated the prediction | |
| | `created_at` | `DateTime(tz)` | `server_default=now()` | Prediction timestamp | |
|
|
| **Foreign Keys:** |
| - `patient_id` β `patients.id` (`SET NULL`) |
| - `created_by` β `users.id` (`SET NULL`) |
|
|
| **Relationships:** |
| - `patient` (many-to-one) |
| - `created_by` user (many-to-one) |
| - `review_queue` (one-to-one) |
|
|
| --- |
|
|
| ### 6. `review_queue` |
| |
| Uncertain predictions (confidence 40β60%) flagged for expert review. |
| |
| | Column | Type | Constraints | Description | |
| |--------|------|-------------|-------------| |
| | `id` | `UUID` | `PK`, `default=uuid4` | UUID primary key | |
| | `prediction_id` | `UUID` | `FK β predictions.id`, `UNIQUE` | The uncertain prediction | |
| | `uncertainty_score` | `Float` | `nullable` | Entropy value | |
| | `reviewer_id` | `UUID` | `FK β users.id`, `nullable` | Assigned reviewer | |
| | `label` | `Integer` | `nullable` | Expert annotation: `0` or `1` | |
| | `reviewed_at` | `DateTime` | `nullable` | When the review occurred | |
| | `status` | `String(20)` | `default="pending"` | `"pending"` \| `"reviewed"` \| `"skipped"` | |
| | `created_at` | `DateTime(tz)` | `server_default=now()` | When added to queue | |
|
|
| **Foreign Keys:** |
| - `prediction_id` β `predictions.id` (`CASCADE`) |
| - `reviewer_id` β `users.id` (`SET NULL`) |
|
|
| --- |
|
|
| ### 7. `audit_logs` |
| |
| Immutable log of every authenticated API request for compliance. |
| |
| | Column | Type | Constraints | Description | |
| |--------|------|-------------|-------------| |
| | `id` | `BigInteger` | `PK`, `autoincrement` | Auto-incrementing ID | |
| | `user_id` | `UUID` | `FK β users.id`, `nullable` | Who made the request | |
| | `endpoint` | `String(255)` | `NOT NULL` | API path (e.g., `/api/v4/heart_disease/predict`) | |
| | `method` | `String(10)` | `NOT NULL` | HTTP method: `GET`, `POST`, etc. | |
| | `status_code` | `Integer` | `nullable` | HTTP response status code | |
| | `ip_address` | `String(45)` | `nullable` | Client IP (supports IPv6) | |
| | `duration_ms` | `Float` | `nullable` | Request duration in milliseconds | |
| | `created_at` | `DateTime(tz)` | `server_default=now()`, `INDEX` | Request timestamp | |
|
|
| **Foreign Keys:** |
| - `user_id` β `users.id` (`SET NULL`) |
|
|
| --- |
|
|
| ## Referential Integrity Summary |
|
|
| | FK Constraint | From | To | On Delete | |
| |---------------|------|----|-----------| |
| | `user_roles.user_id` β `users.id` | `user_roles` | `users` | `CASCADE` | |
| | `user_roles.role_id` β `roles.id` | `user_roles` | `roles` | `CASCADE` | |
| | `patients.created_by` β `users.id` | `patients` | `users` | `SET NULL` | |
| | `predictions.patient_id` β `patients.id` | `predictions` | `patients` | `SET NULL` | |
| | `predictions.created_by` β `users.id` | `predictions` | `users` | `SET NULL` | |
| | `review_queue.prediction_id` β `predictions.id` | `review_queue` | `predictions` | `CASCADE` | |
| | `review_queue.reviewer_id` β `users.id` | `review_queue` | `users` | `SET NULL` | |
| | `audit_logs.user_id` β `users.id` | `audit_logs` | `users` | `SET NULL` | |
|
|
| --- |
|
|
| ## Indexes |
|
|
| | Table | Column(s) | Type | Purpose | |
| |-------|-----------|------|---------| |
| | `users` | `email` | Unique + B-tree | Fast login lookup | |
| | `patients` | `mrn` | Unique + B-tree | Fast MRN search | |
| | `predictions` | `disease` | B-tree | Filter predictions by disease | |
| | `predictions` | `patient_id` | B-tree | Lookup predictions by patient | |
| | `audit_logs` | `created_at` | B-tree | Time-range audit queries | |
| | `review_queue` | `prediction_id` | Unique + B-tree | One-to-one enforcement | |
| | `review_queue` | `status` | B-tree | Filter by review status | |
|
|