from sqlalchemy import Column, Integer, String, Float, Boolean, DateTime, Text, ARRAY from sqlalchemy.dialects.postgresql import UUID, JSONB from sqlalchemy.sql import func import uuid from database import Base class Case(Base): Unified case model - combines search case and result __tablename__ = "cases" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) created_at = Column(DateTime, server_default=func.now()) status = Column(String(20), default="active") # active/closed/archived # Ребёнок (Шаг 1) child_name = Column(String(255)) age_years = Column(Integer, nullable=False) gender = Column(String(1)) # М / Ж height_build = Column(Text) # Рост / телосложение clothes_upper = Column(Text) # Одежда: верх (цвет, тип) clothes_lower = Column(Text) # Одежда: низ (цвет, тип) shoes = Column(Text) # Обувь (тип, цвет) clothes_description = Column(Text) # Общее описание одежды (legacy) special_marks = Column(Text) # Особые приметы phone_status = Column(String(20)) # answers/silent/none # Здоровье (Шаг 2) has_diagnosis = Column(Boolean, default=False) diagnosis_type = Column(ARRAY(String)) # РАС, эпилепсия, СДВГ, ЗПР, слабое зрение, слабый слух... fitness_level = Column(String(20)) # low/medium/high has_transport = Column(String(20), default="none") # none/bike/scooter/other cant_swim = Column(Boolean, default=False) # Психотип (Шаг 2б) psychotype = Column(String(50)) # dominant/harmonic/anxious/introvert_passive/introvert_active psychotype_answers = Column(JSONB) # сырые ответы на 4 вопроса # Обстоятельства (Шаг 3) loss_reason = Column(String(100)) # потерялся в лесу/ушёл из дома/в городе/не вернулся с прогулки/на мероприятии/другое loss_time = Column(DateTime) elapsed_hours = Column(Float) last_seen_direction = Column(String(10)) # С/СВ/В/ЮВ/Ю/ЮЗ/З/СЗ/неизвестно last_seen_reliability = Column(String(20)) # exact/approx/unknown last_seen_description = Column(Text) behavior_description = Column(Text) # Поведение при стрессе familiar_places = Column(Text) # Знакомые места lost_before = Column(String(20)) # yes/no/unknown # Среда (Шаг 4) season = Column(String(20)) # зима/весна/лето/осень temperature_c = Column(Float) precipitation = Column(String(20)) # нет/морось/дождь/ливень/снег/гроза/туман visibility = Column(String(20)) # хорошая/ограниченная/плохая wind = Column(String(20)) # штиль/слабый/умеренный/сильный terrain = Column(ARRAY(String)) # густой лес, редкий лес, лесная дорога, поле, болото, водоём, город... # GPS (Шаг 4) tnp_lat = Column(Float) tnp_lon = Column(Float) tnp_address = Column(Text) # Ресурсы (Шаг 5) teams_count = Column(Integer) team_size = Column(Integer) has_dog = Column(Boolean, default=False) extra_resources = Column(ARRAY(String)) # drone/helicopter/boat/thermal/quadbike # Исход (заполняется после завершения) found_alive = Column(Boolean) found_distance_km = Column(Float) found_direction = Column(String(10)) found_location_type = Column(String(50)) # forest/road/building/water/field found_lat = Column(Float) found_lon = Column(Float) search_duration_hours = Column(Float) who_found = Column(String(50)) # mchs/mvd/volunteers/self # Мета confidence_avg = Column(Float) raw_text = Column(Text) analysis_log = Column(JSONB) class RawDocument(Base): """Raw document storage for parsed reports""" __tablename__ = "raw_documents" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) filename = Column(String(255), nullable=False) raw_text = Column(Text) extracted_json = Column(JSONB) created_at = Column(DateTime, server_default=func.now())