Схема базы данных
ER-диаграмма (основные сущности)
erDiagram
Tenant ||--o{ User : has
Tenant ||--o{ Patient : has
Tenant ||--o{ Department : has
Department ||--o{ Patient : contains
Patient ||--o{ Document : has
Patient ||--o{ Prediction : has
Patient ||--o{ DicomStudy : has
User ||--o{ Document : uploads
User }o--|| Department : belongs
User ||--o{ ChatSession : has
ChatSession ||--o{ ChatMessage : contains
User ||--o{ Progress : tracks
DicomStudy ||--o{ DicomSeries : contains
DicomSeries ||--o{ DicomFrame : contains
Document ||--o{ ParsedData : extracts
Tenant ||--o{ Subscription : has
User ||--o| UserPreference : has
User ||--o| TelegramUser : links
Note
ClinicalCase и Test — справочники сценариев/экзаменов (без обязательного FK на User). Векторное хранилище RAG — Chroma (не таблица Postgres).
Основные таблицы
tenants
| Поле |
Тип |
Описание |
| id |
INTEGER PK |
|
| name |
VARCHAR |
Название клиники |
| subdomain |
VARCHAR UNIQUE |
Поддомен для входа |
users
| Поле |
Тип |
Описание |
| id |
INTEGER PK |
|
| tenant_id |
FK |
Клиника |
| email |
VARCHAR UNIQUE |
|
| role |
ENUM |
RBAC-роль (student, resident, doctor, …) |
| department_id |
FK nullable |
Отделение |
password_hash |
VARCHAR |
bcrypt hash |
patients
| Поле |
Тип |
Описание |
| id |
INTEGER PK |
|
| tenant_id |
FK |
|
| department_id |
FK |
|
| full_name |
VARCHAR |
Шифруется при необходимости |
| date_of_birth |
DATE |
|
| attending_doctor_id |
FK nullable |
|
documents
| Поле |
Тип |
Описание |
| id |
INTEGER PK |
|
| patient_id |
FK |
|
| file_path |
VARCHAR |
Зашифрованный путь |
| status |
ENUM |
uploaded/processing/parsed/failed |
| document_type |
VARCHAR |
|
dicom_studies / dicom_series / dicom_frames
Иерархия DICOM: Study → Series → Frame (PNG preview).
predictions
| Поле |
Тип |
Описание |
| readmission_risk |
FLOAT |
0–1 |
| complication_risk |
FLOAT |
0–1 |
| risk_level |
VARCHAR |
low/medium/high |
| gpt_explanation |
TEXT |
|
Обучение
chat_sessions (ChatSession)
| Поле |
Тип |
Описание |
| id |
INTEGER PK |
|
| public_id |
UUID |
Публичный идентификатор |
| user_id |
FK → users |
Владелец сессии |
| title |
VARCHAR nullable |
Заголовок чата |
| language |
VARCHAR |
Язык (en / ru, …) |
| created_at / updated_at |
DATETIME |
|
chat_messages (ChatMessage)
| Поле |
Тип |
Описание |
| id |
INTEGER PK |
|
| public_id |
UUID |
|
| session_id |
FK → chat_sessions |
Каскадное удаление |
| role |
VARCHAR |
user / assistant / system |
| content |
TEXT |
Текст сообщения |
| sources |
JSON nullable |
Источники RAG |
| created_at |
DATETIME |
|
clinical_cases (ClinicalCase)
| Поле |
Тип |
Описание |
| id |
INTEGER PK |
|
| public_id |
UUID |
|
| title |
VARCHAR |
Название кейса |
| description |
TEXT |
Описание |
| specialty |
VARCHAR nullable |
Специальность |
| difficulty |
VARCHAR nullable |
Сложность |
| steps |
JSON nullable |
Пошаговый сценарий |
| created_at |
DATETIME |
|
tests (Test)
| Поле |
Тип |
Описание |
| id |
INTEGER PK |
|
| public_id |
UUID |
|
| title |
VARCHAR |
Название экзамена/квиза |
| description |
TEXT nullable |
|
| category |
VARCHAR nullable |
Категория |
| difficulty |
VARCHAR nullable |
|
| questions |
JSON nullable |
Вопросы и варианты |
| created_at |
DATETIME |
|
progress (Progress)
| Поле |
Тип |
Описание |
| id |
INTEGER PK |
|
| public_id |
UUID |
|
| user_id |
FK → users |
|
| module |
VARCHAR |
tutor / cases / exam (и др.) |
| score |
FLOAT nullable |
Балл |
| time_spent |
INTEGER nullable |
Секунды |
| completed_at |
DATETIME |
|
| extra_data |
JSON nullable |
Доп. метаданные |
Миграции
Legacy: SQL/Python-файлы в app/db/migrations/ (001–031) — заморожены; применяются через run_migrations() после create_all при ALEMBIC_ENABLED=false.
Alembic (рекомендуется для prod): каталог alembic/, baseline 001_baseline. Включите ALEMBIC_ENABLED=true — тогда deploy.sh выполняет alembic upgrade head (с pg_advisory_lock на PostgreSQL) вместо create_all.
# Локально / в контейнере
docker compose exec app alembic upgrade head
# Или через deploy helper
python scripts/run_alembic_migrate.py
Генерация схемы
Просмотр моделей (пакет app/models/):
grep "^class " app/models/*.py
Индексы
patients(tenant_id, department_id)
documents(patient_id, status)
dicom_studies(patient_id, study_uid)
chat_sessions(user_id), chat_messages(session_id)
progress(user_id, module)
Анонимизация (researcher)
В access.py поля full_name, phone, email заменяются на P-{id} ANON при сериализации.