innercontext/backend/innercontext/models/health.py
Piotr Oleszczyk 8f7d893a63 Initial commit: backend API, data models, and test suite
FastAPI backend for personal health and skincare data with MCP export.
Includes SQLModel models for products, inventory, medications, lab results,
routines, and skin condition snapshots. Pytest suite with 111 tests running
on SQLite in-memory (no PostgreSQL required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 15:10:24 +01:00

113 lines
3.7 KiB
Python

from datetime import datetime
from typing import ClassVar
from uuid import UUID, uuid4
from sqlalchemy import Column, DateTime
from sqlmodel import Field, Relationship, SQLModel
from .base import utc_now
from .domain import Domain
from .enums import MedicationKind, ResultFlag
class MedicationEntry(SQLModel, table=True):
__tablename__ = "medication_entries"
__domains__: ClassVar[frozenset[Domain]] = frozenset({Domain.HEALTH})
record_id: UUID = Field(default_factory=uuid4, primary_key=True)
kind: MedicationKind = Field(index=True)
product_name: str = Field(index=True)
active_substance: str | None = Field(default=None, index=True)
formulation: str | None = Field(default=None)
route: str | None = Field(default=None)
source_file: str | None = Field(default=None)
notes: str | None = Field(default=None)
created_at: datetime = Field(default_factory=utc_now, nullable=False)
updated_at: datetime = Field(
default_factory=utc_now,
sa_column=Column(
DateTime(timezone=True),
default=utc_now,
onupdate=utc_now,
nullable=False,
),
)
usage_history: list["MedicationUsage"] = Relationship(back_populates="medication")
class MedicationUsage(SQLModel, table=True):
__tablename__ = "medication_usages"
__domains__: ClassVar[frozenset[Domain]] = frozenset({Domain.HEALTH})
record_id: UUID = Field(default_factory=uuid4, primary_key=True)
medication_record_id: UUID = Field(
foreign_key="medication_entries.record_id", index=True
)
dose_value: float | None = Field(default=None, ge=0)
dose_unit: str | None = Field(default=None)
frequency: str | None = Field(default=None)
schedule_text: str | None = Field(default=None)
as_needed: bool = Field(default=False, index=True)
valid_from: datetime = Field(index=True)
valid_to: datetime | None = Field(default=None, index=True)
source_file: str | None = Field(default=None)
notes: str | None = Field(default=None)
created_at: datetime = Field(default_factory=utc_now, nullable=False)
updated_at: datetime = Field(
default_factory=utc_now,
sa_column=Column(
DateTime(timezone=True),
default=utc_now,
onupdate=utc_now,
nullable=False,
),
)
medication: MedicationEntry = Relationship(back_populates="usage_history")
class LabResult(SQLModel, table=True):
__tablename__ = "lab_results"
__domains__: ClassVar[frozenset[Domain]] = frozenset({Domain.HEALTH})
record_id: UUID = Field(default_factory=uuid4, primary_key=True)
collected_at: datetime = Field(index=True)
test_code: str = Field(index=True, regex=r"^\d+-\d$")
test_name_original: str | None = Field(default=None)
test_name_loinc: str | None = Field(default=None)
value_num: float | None = Field(default=None)
value_text: str | None = Field(default=None)
value_bool: bool | None = Field(default=None)
unit_original: str | None = Field(default=None)
unit_ucum: str | None = Field(default=None)
ref_low: float | None = Field(default=None)
ref_high: float | None = Field(default=None)
ref_text: str | None = Field(default=None)
flag: ResultFlag | None = Field(default=None, index=True)
lab: str | None = Field(default=None, index=True)
source_file: str | None = Field(default=None)
notes: str | None = Field(default=None)
created_at: datetime = Field(default_factory=utc_now, nullable=False)
updated_at: datetime = Field(
default_factory=utc_now,
sa_column=Column(
DateTime(timezone=True),
default=utc_now,
onupdate=utc_now,
nullable=False,
),
)