File size: 3,704 Bytes
10795db | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | """Platform tables: user-facing notifications, audit log of clinical
mutations, per-user preferences for the dashboard / Jarvis. Used by
the corresponding router modules.
All three tables are tiny (no FK cascades, no joins) so they don't
slow patient queries; the audit_log is append-only and we trim it via
the cleanup task on startup if it ever grows past 20k rows.
"""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import JSON, Boolean, DateTime, ForeignKey, Integer, String, Text, func
from sqlalchemy.orm import Mapped, mapped_column
from core.database import Base
class Notification(Base):
"""Lightweight notification feed for the bell dropdown."""
__tablename__ = "notifications"
id: Mapped[int] = mapped_column(primary_key=True)
user_id: Mapped[int | None] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), index=True, nullable=True
)
kind: Mapped[str] = mapped_column(String(32), nullable=False)
severity: Mapped[str] = mapped_column(String(16), default="info", nullable=False)
title: Mapped[str] = mapped_column(String(255), nullable=False)
body: Mapped[str | None] = mapped_column(Text, nullable=True)
link: Mapped[str | None] = mapped_column(String(255), nullable=True)
patient_id: Mapped[int | None] = mapped_column(Integer, nullable=True)
read_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), nullable=False, index=True
)
class AuditLogEntry(Base):
"""Append-only record of clinical mutations.
Captured automatically by the helper in core.audit. Read-only from
the API; only an admin can fetch the list.
"""
__tablename__ = "audit_log"
id: Mapped[int] = mapped_column(primary_key=True)
actor_id: Mapped[int | None] = mapped_column(
ForeignKey("users.id", ondelete="SET NULL"), index=True, nullable=True
)
actor_email: Mapped[str | None] = mapped_column(String(255), nullable=True)
action: Mapped[str] = mapped_column(String(64), nullable=False)
target_kind: Mapped[str] = mapped_column(String(32), nullable=False)
target_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
summary: Mapped[str | None] = mapped_column(Text, nullable=True)
payload: Mapped[dict | None] = mapped_column(JSON, nullable=True)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), nullable=False, index=True
)
class UserPreference(Base):
"""Per-user dashboard + Jarvis preferences (theme, lang, voice…)."""
__tablename__ = "user_preferences"
user_id: Mapped[int] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), primary_key=True
)
locale: Mapped[str] = mapped_column(String(8), default="en", nullable=False)
theme: Mapped[str] = mapped_column(String(16), default="dark", nullable=False)
voice_greetings: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
voice_alerts: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
auto_select_critical: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
compact_density: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
shortcuts_enabled: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
extras: Mapped[dict | None] = mapped_column(JSON, nullable=True)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False
)
|