-- 찜관리 기능을 위한 데이터베이스 스키마 -- 1. 찜 기록 테이블 (public.jjim) CREATE TABLE IF NOT EXISTS public.jjim ( id BIGSERIAL PRIMARY KEY, user_id UUID NOT NULL, market_url TEXT NOT NULL, market_name TEXT, market_nickname TEXT, zzim_count INTEGER DEFAULT 0, zzim_type VARCHAR(20) NOT NULL CHECK (zzim_type IN ('my_market', 'mutual')), mileage_earned INTEGER DEFAULT 0, target_user_id UUID, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), CONSTRAINT fk_jjim_user_id FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE, CONSTRAINT fk_jjim_target_user_id FOREIGN KEY (target_user_id) REFERENCES auth.users(id) ON DELETE SET NULL ); -- 2. 사용자 마켓 통합 테이블 (public.user_markets) - 찜 관련 필드 추가 CREATE TABLE IF NOT EXISTS public.user_markets ( id BIGSERIAL PRIMARY KEY, user_id UUID NOT NULL, -- 마켓 목록 (JSONB 배열) my_markets JSONB DEFAULT '[]'::jsonb, -- 찜 통계 필드들 (users 테이블에서 이관) my_zzim INTEGER DEFAULT 0, -- 받은 찜 총 개수 zzim_mile INTEGER DEFAULT 0, -- 총 마일리지 available_zzim_mile INTEGER DEFAULT 0, -- 사용 가능한 마일리지 today_zzim_count INTEGER DEFAULT 0, -- 오늘 찜한 개수 today_zzim_date DATE DEFAULT CURRENT_DATE, -- 마지막 찜한 날짜 -- 회원등급 (users 테이블과 동기화) membership_level VARCHAR(20) DEFAULT 'basic', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), CONSTRAINT fk_user_markets_user_id FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE, CONSTRAINT unique_user_markets_user_id UNIQUE (user_id) ); -- 3. 회원등급별 찜 제한 테이블 (public.membership_zzim_limits) - 개선 CREATE TABLE IF NOT EXISTS public.membership_zzim_limits ( id BIGSERIAL PRIMARY KEY, membership_level VARCHAR(20) NOT NULL UNIQUE, -- 찜 제한 설정 daily_zzim_limit INTEGER DEFAULT 50, -- 일일 찜 제한 max_zzim_mileage INTEGER DEFAULT 500, -- 최대 마일리지 보유량 mileage_per_zzim INTEGER DEFAULT 1, -- 찜당 마일리지 -- 추가 제한 설정 max_markets INTEGER DEFAULT 5, -- 최대 등록 가능한 마켓 수 mutual_zzim_enabled BOOLEAN DEFAULT TRUE, -- 품앗이 기능 사용 가능 여부 background_zzim_enabled BOOLEAN DEFAULT FALSE, -- 백그라운드 찜 기능 사용 가능 여부 created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- 4. 기본 회원등급 데이터 삽입 INSERT INTO public.membership_zzim_limits (membership_level, daily_zzim_limit, max_zzim_mileage, mileage_per_zzim, max_markets, mutual_zzim_enabled, background_zzim_enabled) VALUES ('basic', 50, 500, 1, 3, TRUE, FALSE), ('premium', 100, 1000, 1, 10, TRUE, TRUE), ('vip', 200, 2000, 1, 20, TRUE, TRUE) ON CONFLICT (membership_level) DO UPDATE SET daily_zzim_limit = EXCLUDED.daily_zzim_limit, max_zzim_mileage = EXCLUDED.max_zzim_mileage, mileage_per_zzim = EXCLUDED.mileage_per_zzim, max_markets = EXCLUDED.max_markets, mutual_zzim_enabled = EXCLUDED.mutual_zzim_enabled, background_zzim_enabled = EXCLUDED.background_zzim_enabled, updated_at = NOW(); -- 5. 마켓 데이터 구조 예시 (my_markets JSONB 필드 내용) /* my_markets JSONB 예시: [ { "market_url": "https://smartstore.naver.com/example", "market_name": "예시 마켓", "market_nickname": "내 마켓", "is_visible": true, -- 다른 사람에게 노출 여부 "for_zzim": true, -- 내 마켓 찜하기 대상 여부 "for_mutual_zzim": true, -- 품앗이 대상 여부 (새로 추가) "zzim_received_count": 0, -- 받은 찜 개수 "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" } ] */ -- 6. 인덱스 생성 CREATE INDEX IF NOT EXISTS idx_jjim_user_id ON public.jjim(user_id); CREATE INDEX IF NOT EXISTS idx_jjim_target_user_id ON public.jjim(target_user_id); CREATE INDEX IF NOT EXISTS idx_jjim_created_at ON public.jjim(created_at); CREATE INDEX IF NOT EXISTS idx_jjim_zzim_type ON public.jjim(zzim_type); CREATE INDEX IF NOT EXISTS idx_user_markets_user_id ON public.user_markets(user_id); CREATE INDEX IF NOT EXISTS idx_user_markets_membership_level ON public.user_markets(membership_level); CREATE INDEX IF NOT EXISTS idx_user_markets_today_zzim_date ON public.user_markets(today_zzim_date); -- 7. RLS (Row Level Security) 정책 설정 -- user_markets 테이블: 품앗이를 위해 읽기는 모든 사용자에게 허용, 쓰기는 본인만 ALTER TABLE public.user_markets ENABLE ROW LEVEL SECURITY; -- 본인 데이터 읽기/쓰기 허용 CREATE POLICY "Users can view and edit their own user_markets data" ON public.user_markets FOR ALL USING (auth.uid() = user_id); -- 품앗이를 위한 다른 사용자 데이터 읽기 허용 (민감하지 않은 정보만) CREATE POLICY "Users can view others user_markets for mutual zzim" ON public.user_markets FOR SELECT USING (true); -- jjim 테이블: 본인이 한 찜 기록만 조회/수정 가능 ALTER TABLE public.jjim ENABLE ROW LEVEL SECURITY; CREATE POLICY "Users can view and edit their own jjim records" ON public.jjim FOR ALL USING (auth.uid() = user_id); -- membership_zzim_limits 테이블: 모든 사용자가 읽기 가능 ALTER TABLE public.membership_zzim_limits ENABLE ROW LEVEL SECURITY; CREATE POLICY "All users can view membership limits" ON public.membership_zzim_limits FOR SELECT USING (true); -- 8. 데이터 마이그레이션 함수 (users 테이블에서 user_markets로 찜 데이터 이관) CREATE OR REPLACE FUNCTION migrate_zzim_data_to_user_markets() RETURNS void AS $$ BEGIN -- users 테이블의 찜 관련 데이터를 user_markets로 이관 INSERT INTO public.user_markets ( user_id, my_zzim, zzim_mile, available_zzim_mile, today_zzim_count, today_zzim_date, membership_level ) SELECT id, COALESCE(my_zzim, 0), COALESCE(zzim_mile, 0), COALESCE(available_zzim_mile, COALESCE(zzim_mile, 0)), COALESCE(today_zzim_count, 0), COALESCE(today_zzim_date, CURRENT_DATE), COALESCE(membership_level, 'basic') FROM auth.users WHERE id NOT IN (SELECT user_id FROM public.user_markets) ON CONFLICT (user_id) DO UPDATE SET my_zzim = EXCLUDED.my_zzim, zzim_mile = EXCLUDED.zzim_mile, available_zzim_mile = EXCLUDED.available_zzim_mile, today_zzim_count = EXCLUDED.today_zzim_count, today_zzim_date = EXCLUDED.today_zzim_date, membership_level = EXCLUDED.membership_level, updated_at = NOW(); RAISE NOTICE 'Zzim data migration completed'; END; $$ LANGUAGE plpgsql; -- 9. 트리거 함수: user_markets와 users 테이블 동기화 CREATE OR REPLACE FUNCTION sync_user_markets_to_users() RETURNS TRIGGER AS $$ BEGIN -- user_markets 테이블의 변경사항을 users 테이블에 반영 UPDATE auth.users SET my_zzim = NEW.my_zzim, zzim_mile = NEW.zzim_mile, available_zzim_mile = NEW.available_zzim_mile, today_zzim_count = NEW.today_zzim_count, today_zzim_date = NEW.today_zzim_date, membership_level = NEW.membership_level WHERE id = NEW.user_id; RETURN NEW; END; $$ LANGUAGE plpgsql; -- 트리거 생성 CREATE TRIGGER sync_user_markets_to_users_trigger AFTER INSERT OR UPDATE ON public.user_markets FOR EACH ROW EXECUTE FUNCTION sync_user_markets_to_users(); -- 10. 마이그레이션 실행 (주석 해제하여 실행) -- SELECT migrate_zzim_data_to_user_markets();