innercontext/backend/alembic/versions/c2d626a2b36c_initial_schema.py
2026-03-01 17:27:07 +01:00

478 lines
18 KiB
Python

"""initial_schema
Revision ID: c2d626a2b36c
Revises:
Create Date: 2026-02-28 20:13:55.499494
"""
from typing import Sequence, Union
import sqlalchemy as sa
import sqlmodel.sql.sqltypes
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "c2d626a2b36c"
down_revision: Union[str, Sequence[str], None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"grooming_schedule",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("day_of_week", sa.Integer(), nullable=False),
sa.Column(
"action",
sa.Enum(
"SHAVING_RAZOR",
"SHAVING_ONEBLADE",
"DERMAROLLING",
name="groomingaction",
),
nullable=False,
),
sa.Column("notes", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_grooming_schedule_day_of_week"),
"grooming_schedule",
["day_of_week"],
unique=False,
)
op.create_table(
"lab_results",
sa.Column("record_id", sa.Uuid(), nullable=False),
sa.Column("collected_at", sa.DateTime(), nullable=False),
sa.Column("test_code", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column(
"test_name_original", sqlmodel.sql.sqltypes.AutoString(), nullable=True
),
sa.Column("test_name_loinc", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("value_num", sa.Float(), nullable=True),
sa.Column("value_text", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("value_bool", sa.Boolean(), nullable=True),
sa.Column("unit_original", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("unit_ucum", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("ref_low", sa.Float(), nullable=True),
sa.Column("ref_high", sa.Float(), nullable=True),
sa.Column("ref_text", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column(
"flag",
sa.Enum(
"NORMAL",
"ABNORMAL",
"POSITIVE",
"NEGATIVE",
"LOW",
"HIGH",
name="resultflag",
),
nullable=True,
),
sa.Column("lab", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("source_file", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("notes", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("record_id"),
)
op.create_index(
op.f("ix_lab_results_collected_at"),
"lab_results",
["collected_at"],
unique=False,
)
op.create_index(op.f("ix_lab_results_flag"), "lab_results", ["flag"], unique=False)
op.create_index(op.f("ix_lab_results_lab"), "lab_results", ["lab"], unique=False)
op.create_index(
op.f("ix_lab_results_test_code"), "lab_results", ["test_code"], unique=False
)
op.create_table(
"medication_entries",
sa.Column("record_id", sa.Uuid(), nullable=False),
sa.Column(
"kind",
sa.Enum(
"PRESCRIPTION",
"OTC",
"SUPPLEMENT",
"HERBAL",
"OTHER",
name="medicationkind",
),
nullable=False,
),
sa.Column("product_name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column(
"active_substance", sqlmodel.sql.sqltypes.AutoString(), nullable=True
),
sa.Column("formulation", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("route", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("source_file", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("notes", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("record_id"),
)
op.create_index(
op.f("ix_medication_entries_active_substance"),
"medication_entries",
["active_substance"],
unique=False,
)
op.create_index(
op.f("ix_medication_entries_kind"), "medication_entries", ["kind"], unique=False
)
op.create_index(
op.f("ix_medication_entries_product_name"),
"medication_entries",
["product_name"],
unique=False,
)
op.create_table(
"products",
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("brand", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column(
"line_name", sqlmodel.sql.sqltypes.AutoString(length=128), nullable=True
),
sa.Column("sku", sqlmodel.sql.sqltypes.AutoString(length=64), nullable=True),
sa.Column("url", sqlmodel.sql.sqltypes.AutoString(length=512), nullable=True),
sa.Column(
"barcode", sqlmodel.sql.sqltypes.AutoString(length=64), nullable=True
),
sa.Column(
"category",
sa.Enum(
"CLEANSER",
"TONER",
"ESSENCE",
"SERUM",
"MOISTURIZER",
"SPF",
"MASK",
"EXFOLIANT",
"HAIR_TREATMENT",
"TOOL",
"SPOT_TREATMENT",
"OIL",
name="productcategory",
),
nullable=False,
),
sa.Column(
"recommended_time",
sa.Enum("AM", "PM", "BOTH", name="daytime"),
nullable=False,
),
sa.Column(
"texture",
sa.Enum(
"WATERY",
"GEL",
"EMULSION",
"CREAM",
"OIL",
"BALM",
"FOAM",
"FLUID",
name="texturetype",
),
nullable=True,
),
sa.Column(
"absorption_speed",
sa.Enum(
"VERY_FAST",
"FAST",
"MODERATE",
"SLOW",
"VERY_SLOW",
name="absorptionspeed",
),
nullable=True,
),
sa.Column("leave_on", sa.Boolean(), nullable=False),
sa.Column("size_ml", sa.Float(), nullable=True),
sa.Column("full_weight_g", sa.Float(), nullable=True),
sa.Column("empty_weight_g", sa.Float(), nullable=True),
sa.Column("pao_months", sa.Integer(), nullable=True),
sa.Column(
"price_tier",
sa.Enum("BUDGET", "MID", "PREMIUM", "LUXURY", name="pricetier"),
nullable=True,
),
sa.Column("inci", sa.JSON(), nullable=False),
sa.Column("actives", sa.JSON(), nullable=True),
sa.Column("recommended_for", sa.JSON(), nullable=False),
sa.Column("targets", sa.JSON(), nullable=False),
sa.Column("contraindications", sa.JSON(), nullable=False),
sa.Column("usage_notes", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("fragrance_free", sa.Boolean(), nullable=True),
sa.Column("essential_oils_free", sa.Boolean(), nullable=True),
sa.Column("alcohol_denat_free", sa.Boolean(), nullable=True),
sa.Column("pregnancy_safe", sa.Boolean(), nullable=True),
sa.Column("product_effect_profile", sa.JSON(), nullable=False),
sa.Column("ph_min", sa.Float(), nullable=True),
sa.Column("ph_max", sa.Float(), nullable=True),
sa.Column("incompatible_with", sa.JSON(), nullable=True),
sa.Column("synergizes_with", sa.JSON(), nullable=True),
sa.Column("context_rules", sa.JSON(), nullable=True),
sa.Column("min_interval_hours", sa.Integer(), nullable=True),
sa.Column("max_frequency_per_week", sa.Integer(), nullable=True),
sa.Column("is_medication", sa.Boolean(), nullable=False),
sa.Column("is_tool", sa.Boolean(), nullable=False),
sa.Column("needle_length_mm", sa.Float(), nullable=True),
sa.Column(
"personal_tolerance_notes",
sqlmodel.sql.sqltypes.AutoString(),
nullable=True,
),
sa.Column("personal_repurchase_intent", sa.Boolean(), nullable=True),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_products_price_tier"), "products", ["price_tier"], unique=False
)
op.create_table(
"routines",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("routine_date", sa.Date(), nullable=False),
sa.Column("part_of_day", sa.Enum("AM", "PM", name="partofday"), nullable=False),
sa.Column("notes", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint(
"routine_date", "part_of_day", name="uq_routine_date_part_of_day"
),
)
op.create_index(
op.f("ix_routines_part_of_day"), "routines", ["part_of_day"], unique=False
)
op.create_index(
op.f("ix_routines_routine_date"), "routines", ["routine_date"], unique=False
)
op.create_table(
"skin_condition_snapshots",
sa.Column("snapshot_date", sa.Date(), nullable=False),
sa.Column(
"overall_state",
sa.Enum("EXCELLENT", "GOOD", "FAIR", "POOR", name="overallskinstate"),
nullable=True,
),
sa.Column(
"skin_type",
sa.Enum(
"DRY",
"OILY",
"COMBINATION",
"SENSITIVE",
"NORMAL",
"ACNE_PRONE",
name="skintype",
),
nullable=True,
),
sa.Column(
"texture",
sa.Enum("SMOOTH", "ROUGH", "FLAKY", "BUMPY", name="skintexture"),
nullable=True,
),
sa.Column("hydration_level", sa.Integer(), nullable=True),
sa.Column("sebum_tzone", sa.Integer(), nullable=True),
sa.Column("sebum_cheeks", sa.Integer(), nullable=True),
sa.Column("sensitivity_level", sa.Integer(), nullable=True),
sa.Column(
"barrier_state",
sa.Enum("INTACT", "MILDLY_COMPROMISED", "COMPROMISED", name="barrierstate"),
nullable=True,
),
sa.Column("active_concerns", sa.JSON(), nullable=False),
sa.Column("risks", sa.JSON(), nullable=False),
sa.Column("priorities", sa.JSON(), nullable=False),
sa.Column("notes", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("snapshot_date", name="uq_skin_snapshot_date"),
)
op.create_index(
op.f("ix_skin_condition_snapshots_snapshot_date"),
"skin_condition_snapshots",
["snapshot_date"],
unique=False,
)
op.create_table(
"medication_usages",
sa.Column("record_id", sa.Uuid(), nullable=False),
sa.Column("medication_record_id", sa.Uuid(), nullable=False),
sa.Column("dose_value", sa.Float(), nullable=True),
sa.Column("dose_unit", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("frequency", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("schedule_text", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("as_needed", sa.Boolean(), nullable=False),
sa.Column("valid_from", sa.DateTime(), nullable=False),
sa.Column("valid_to", sa.DateTime(), nullable=True),
sa.Column("source_file", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("notes", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(
["medication_record_id"],
["medication_entries.record_id"],
),
sa.PrimaryKeyConstraint("record_id"),
)
op.create_index(
op.f("ix_medication_usages_as_needed"),
"medication_usages",
["as_needed"],
unique=False,
)
op.create_index(
op.f("ix_medication_usages_medication_record_id"),
"medication_usages",
["medication_record_id"],
unique=False,
)
op.create_index(
op.f("ix_medication_usages_valid_from"),
"medication_usages",
["valid_from"],
unique=False,
)
op.create_index(
op.f("ix_medication_usages_valid_to"),
"medication_usages",
["valid_to"],
unique=False,
)
op.create_table(
"product_inventory",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("product_id", sa.Uuid(), nullable=False),
sa.Column("is_opened", sa.Boolean(), nullable=False),
sa.Column("opened_at", sa.Date(), nullable=True),
sa.Column("finished_at", sa.Date(), nullable=True),
sa.Column("expiry_date", sa.Date(), nullable=True),
sa.Column("current_weight_g", sa.Float(), nullable=True),
sa.Column("last_weighed_at", sa.Date(), nullable=True),
sa.Column("notes", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(
["product_id"],
["products.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_product_inventory_product_id"),
"product_inventory",
["product_id"],
unique=False,
)
op.create_table(
"routine_steps",
sa.Column("id", sa.Uuid(), nullable=False),
sa.Column("routine_id", sa.Uuid(), nullable=False),
sa.Column("product_id", sa.Uuid(), nullable=True),
sa.Column("order_index", sa.Integer(), nullable=False),
sa.Column(
"action_type",
sa.Enum(
"SHAVING_RAZOR",
"SHAVING_ONEBLADE",
"DERMAROLLING",
name="groomingaction",
),
nullable=True,
),
sa.Column("action_notes", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("dose", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("region", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.ForeignKeyConstraint(
["product_id"],
["products.id"],
),
sa.ForeignKeyConstraint(
["routine_id"],
["routines.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_routine_steps_product_id"),
"routine_steps",
["product_id"],
unique=False,
)
op.create_index(
op.f("ix_routine_steps_routine_id"),
"routine_steps",
["routine_id"],
unique=False,
)
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f("ix_routine_steps_routine_id"), table_name="routine_steps")
op.drop_index(op.f("ix_routine_steps_product_id"), table_name="routine_steps")
op.drop_table("routine_steps")
op.drop_index(
op.f("ix_product_inventory_product_id"), table_name="product_inventory"
)
op.drop_table("product_inventory")
op.drop_index(op.f("ix_medication_usages_valid_to"), table_name="medication_usages")
op.drop_index(
op.f("ix_medication_usages_valid_from"), table_name="medication_usages"
)
op.drop_index(
op.f("ix_medication_usages_medication_record_id"),
table_name="medication_usages",
)
op.drop_index(
op.f("ix_medication_usages_as_needed"), table_name="medication_usages"
)
op.drop_table("medication_usages")
op.drop_index(
op.f("ix_skin_condition_snapshots_snapshot_date"),
table_name="skin_condition_snapshots",
)
op.drop_table("skin_condition_snapshots")
op.drop_index(op.f("ix_routines_routine_date"), table_name="routines")
op.drop_index(op.f("ix_routines_part_of_day"), table_name="routines")
op.drop_table("routines")
op.drop_index(op.f("ix_products_price_tier"), table_name="products")
op.drop_table("products")
op.drop_index(
op.f("ix_medication_entries_product_name"), table_name="medication_entries"
)
op.drop_index(op.f("ix_medication_entries_kind"), table_name="medication_entries")
op.drop_index(
op.f("ix_medication_entries_active_substance"), table_name="medication_entries"
)
op.drop_table("medication_entries")
op.drop_index(op.f("ix_lab_results_test_code"), table_name="lab_results")
op.drop_index(op.f("ix_lab_results_lab"), table_name="lab_results")
op.drop_index(op.f("ix_lab_results_flag"), table_name="lab_results")
op.drop_index(op.f("ix_lab_results_collected_at"), table_name="lab_results")
op.drop_table("lab_results")
op.drop_index(
op.f("ix_grooming_schedule_day_of_week"), table_name="grooming_schedule"
)
op.drop_table("grooming_schedule")
# ### end Alembic commands ###