o2o-infinith-demo/supabase/migrations/20260406_clinic_registry.sql

62 lines
2.7 KiB
SQL

-- ═══════════════════════════════════════════════════════════════
-- Clinic Registry: Pre-verified channel database
-- ═══════════════════════════════════════════════════════════════
-- 사전 검증된 병원 채널 DB. discover-channels에서 API 검색 전에
-- domain으로 조회하여 검증된 채널을 즉시 반환.
-- 미등록 도메인은 기존 API 기반 discovery fallback 사용.
CREATE TABLE IF NOT EXISTS clinic_registry (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
-- 병원 식별
name TEXT NOT NULL, -- 한국어 병원명 (ex: "아이디병원")
name_aliases TEXT[] DEFAULT '{}', -- 별칭 (ex: {"아이디성형외과", "ID Hospital"})
domain TEXT UNIQUE NOT NULL, -- 도메인 (www 제외, lookup key)
website_url TEXT NOT NULL, -- 전체 URL
-- 기본 정보
brand_group TEXT, -- 그룹/카테고리 (ex: "프리미엄/하이타깃 후보")
district TEXT, -- 지역구 (ex: "강남", "서초")
branches TEXT, -- 분점 정보
founded_year INT, -- 개원 연도
-- 영문 사이트
website_en TEXT,
-- 소셜 채널 (사전 검증 완료)
youtube_url TEXT,
instagram_url TEXT,
instagram_en_url TEXT,
facebook_url TEXT,
tiktok_url TEXT,
naver_blog_url TEXT,
naver_place_url TEXT,
gangnam_unni_url TEXT,
google_maps_url TEXT,
-- 메타
verified_by TEXT DEFAULT 'scrape', -- 'manual' | 'scrape' | 'llm'
verified_at TIMESTAMPTZ DEFAULT now(),
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
-- 인덱스: domain lookup (primary query path)
CREATE INDEX IF NOT EXISTS idx_clinic_registry_domain ON clinic_registry (domain);
-- GIN 인덱스: 별칭 검색
CREATE INDEX IF NOT EXISTS idx_clinic_registry_aliases ON clinic_registry USING gin (name_aliases);
-- 지역 필터
CREATE INDEX IF NOT EXISTS idx_clinic_registry_district ON clinic_registry (district);
-- RLS (서비스 키로만 접근, 프론트엔드에서는 Edge Function 통해서만)
ALTER TABLE clinic_registry ENABLE ROW LEVEL SECURITY;
-- 서비스 역할만 CRUD 가능
CREATE POLICY "service_role_full_access" ON clinic_registry
FOR ALL USING (auth.role() = 'service_role');
-- anon/authenticated는 읽기만
CREATE POLICY "public_read_registry" ON clinic_registry
FOR SELECT USING (true);