"""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 ###