-- 90_user_weight_profiles.sql -- User-defined POI weight profiles для site_finder/analyze_parcel. -- Per #114 (Макс feedback): разные веса для разных категорий (садики ≠ Мегамарт). -- -- Apply order: после 89_drop_dead_brin_rosreestr_deals.sql -- Dependencies: нет (standalone table, no FK to other tables) -- -- POI categories compatible with _POI_WEIGHTS in backend/app/api/v1/parcels.py: -- school, kindergarten, pharmacy, hospital, shop_mall, shop_supermarket, -- shop_small, park, bus_stop, metro_stop, tram_stop -- -- Idempotent: safe to run multiple times. BEGIN; CREATE TABLE IF NOT EXISTS user_weight_profiles ( id SERIAL PRIMARY KEY, user_id TEXT NOT NULL, -- пока admin token / простой ID; auth в Sprint 5 profile_name TEXT NOT NULL, weights JSONB NOT NULL DEFAULT '{}'::jsonb, is_default BOOLEAN NOT NULL DEFAULT FALSE, description TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE (user_id, profile_name) ); CREATE INDEX IF NOT EXISTS user_weight_profiles_user_idx ON user_weight_profiles (user_id); -- Partial index для быстрого fetch default profile per user CREATE INDEX IF NOT EXISTS user_weight_profiles_default_idx ON user_weight_profiles (user_id) WHERE is_default = TRUE; -- Trigger function для auto-update updated_at (shared, reusable across tables) CREATE OR REPLACE FUNCTION set_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; -- Drop trigger если ранее существовал (idempotent) DROP TRIGGER IF EXISTS user_weight_profiles_updated_at ON user_weight_profiles; CREATE TRIGGER user_weight_profiles_updated_at BEFORE UPDATE ON user_weight_profiles FOR EACH ROW EXECUTE FUNCTION set_updated_at(); COMMENT ON TABLE user_weight_profiles IS 'POI weight profiles для site_finder. Per #114 (Макс feedback). ' 'weights = {"school": 1.5, "kindergarten": 1.5, "shop_mall": 1.2, ...}'; COMMENT ON COLUMN user_weight_profiles.weights IS 'JSONB map: poi_category → weight (float, typically -1.5..2.5). ' 'Совместимо с _POI_WEIGHTS default в backend/app/api/v1/parcels.py. ' 'Категории: school, kindergarten, pharmacy, hospital, shop_mall, ' 'shop_supermarket, shop_small, park, bus_stop, metro_stop, tram_stop.'; COMMENT ON COLUMN user_weight_profiles.user_id IS 'Простой строковый ID пользователя. Full auth integration — Sprint 5.'; COMMENT ON COLUMN user_weight_profiles.is_default IS 'TRUE = профиль используется по умолчанию для этого user_id. ' 'Partial index user_weight_profiles_default_idx ускоряет lookup.'; COMMIT;