talk / backend /sql /046_gift_products.sql
user
Deploy StyleVoiceChat backend
aa9892b
Raw History Blame Contribute Delete
2.98 kB
-- ์นดํŽ˜ ์Œ์„ฑ ์„ ๋ฌผ์ฟ ํฐ MVP โ€” gift_products (2026-05-28, P1a Phase A)
--
-- ์นดํŽ˜๋ณ„ ์ฟ ํฐ ์ƒํ’ˆ (์•„๋ฉ”๋ฆฌ์นด๋…ธ 1์ž”, ์ผ€์ดํฌ 1์กฐ๊ฐ ๋“ฑ).
-- ์š”์ฒญ์„œ: doc/runbook/req_cafe_gift_mvp.md ยง1
-- ์„ค๊ณ„: doc/runbook/cafe_gift_p1a.md ยง2 sql/046
--
-- ํ•ต์‹ฌ:
-- - cafe_id FK + CASCADE (์นดํŽ˜ ์‚ญ์ œ ์‹œ ์ƒํ’ˆ๋„ ์ •๋ฆฌ)
-- - image_path โ†’ Supabase Storage 'cafe-products' ๋ฒ„ํ‚ท (12h signed URL)
-- - active=false ๋ฉด ๋น„๋กœ๊ทธ์ธ ๊ตฌ๋งค ํŽ˜์ด์ง€์— ์•ˆ ๋ณด์ž„ (RLS + ๋ฐฑ์—”๋“œ ์ด์ค‘)
-- - sort_order ์‚ฌ์žฅ์ด ์ง์ ‘ ์ˆœ์„œ ๋ณ€๊ฒฝ
--
-- โ›” ํšŒ๊ท€ ๊ฐ€๋“œ: ์‹ ๊ทœ ํ…Œ์ด๋ธ”, ๊ธฐ์กด CHECK ์˜ํ–ฅ 0.
CREATE TABLE IF NOT EXISTS public.gift_products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cafe_id UUID NOT NULL REFERENCES public.cafe_merchants(id) ON DELETE CASCADE,
name TEXT NOT NULL, -- '์•„๋ฉ”๋ฆฌ์นด๋…ธ 1์ž”'
description TEXT, -- ๋ถ€๊ฐ€ ์„ค๋ช… (์˜ต์…˜)
price_krw INT NOT NULL CHECK (price_krw > 0), -- ์› ๋‹จ์œ„ (KRW ์ •์ˆ˜)
image_path TEXT, -- Storage 'cafe-products' ๋ฒ„ํ‚ท path
active BOOLEAN NOT NULL DEFAULT TRUE,
sort_order INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_gift_products_cafe_active
ON public.gift_products (cafe_id, active, sort_order);
ALTER TABLE public.gift_products ENABLE ROW LEVEL SECURITY;
-- ์‚ฌ์žฅ: ๋ณธ์ธ ์นดํŽ˜ ์ƒํ’ˆ ALL (cafe_merchants owner ๊ฒ€์ฆ)
DROP POLICY IF EXISTS gift_products_owner ON public.gift_products;
CREATE POLICY gift_products_owner ON public.gift_products
FOR ALL
USING (cafe_id IN (
SELECT id FROM public.cafe_merchants WHERE owner_user_id = auth.uid()
))
WITH CHECK (cafe_id IN (
SELECT id FROM public.cafe_merchants WHERE owner_user_id = auth.uid()
));
-- ๊ณต๊ฐœ: active=true ๋งŒ SELECT (anon ๊ฐ€๋Šฅ, ๊ตฌ๋งค ํŽ˜์ด์ง€์šฉ)
DROP POLICY IF EXISTS gift_products_public_read ON public.gift_products;
CREATE POLICY gift_products_public_read ON public.gift_products
FOR SELECT
USING (active = TRUE);
CREATE OR REPLACE FUNCTION public._gift_products_touch_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS gift_products_touch_updated_at ON public.gift_products;
CREATE TRIGGER gift_products_touch_updated_at
BEFORE UPDATE ON public.gift_products
FOR EACH ROW EXECUTE FUNCTION public._gift_products_touch_updated_at();
COMMENT ON TABLE public.gift_products IS
'์นดํŽ˜ ์„ ๋ฌผ ์ƒํ’ˆ ์นดํƒˆ๋กœ๊ทธ. active=false ๋น„๊ณต๊ฐœ. ์ด๋ฏธ์ง€๋Š” Storage cafe-products ๋ฒ„ํ‚ท.';
COMMENT ON COLUMN public.gift_products.price_krw IS
'KRW ์ •์ˆ˜. ๋ฐฑ์—”๋“œ์—์„œ gift_orders.amount_krw ๋กœ ๋ณต์‚ฌ (๊ฐ€๊ฒฉ ๋ณ€๊ฒฝ ํ›„์† ์ฃผ๋ฌธ ์˜ํ–ฅ 0).';