talk / backend /sql /049_gift_coupons.sql
user
Deploy StyleVoiceChat backend
aa9892b
Raw History Blame Contribute Delete
3.25 kB
-- 카페 μŒμ„± 선물쿠폰 MVP β€” gift_coupons (2026-05-28, P1a Phase B)
--
-- λ°œν–‰λœ 쿠폰 = 결제 μ™„λ£Œ β†’ λ°›λŠ”μ΄ 펼침 β†’ λ§€μž₯ μ‚¬μš©μ²˜λ¦¬.
-- μš”μ²­μ„œ: doc/runbook/req_cafe_gift_mvp.md Β§1
-- 섀계: doc/runbook/cafe_gift_p1a.md Β§2 sql/049
--
-- λΆ„λ¦¬λœ 토큰 (Plan κ²°μ • #2, #6):
-- - code: 8자 영숫자 (O/0/I/1 μ œμ™Έ, μ•ŒνŒŒλ²³ 32) β€” λ§€μž₯ 직원 수기 μž…λ ₯용
-- - reveal_token: 32 byte hex (DB default) β€” λ°›λŠ”μ΄ /g/<token> reveal μ§„μž…μš©
-- - λ‘˜ λ‹€ unguessable + 뢄리 = code λ…ΈμΆœ μ‹œ reveal_token μ•ˆμ „, reveal μ‹œ code μ•ˆ λ…ΈμΆœ κ°€λŠ₯
--
-- 만료:
-- - expires_at = gift_orders.expires_at 볡사 (λ°±μ—”λ“œκ°€ set, μ •μ±… λ³€κ²½ 좔적)
-- - status='expired' μžλ™ μ „μ΄λŠ” cron (후속), P1a λŠ” 라이브 쑰회 μ‹œ 만료 검사
--
-- β›” νšŒκ·€ κ°€λ“œ: μ‹ κ·œ ν…Œμ΄λΈ”. RLS cafe owner only (사μž₯ redeem κΆŒν•œ).
CREATE TABLE IF NOT EXISTS public.gift_coupons (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
order_id UUID NOT NULL UNIQUE REFERENCES public.gift_orders(id) ON DELETE CASCADE,
cafe_id UUID NOT NULL REFERENCES public.cafe_merchants(id) ON DELETE RESTRICT,
-- λ§€μž₯ 직원 수기 μž…λ ₯용 (μ‚¬λžŒμ΄ 읽기 μ‰¬μš΄ μ½”λ“œ)
code TEXT NOT NULL UNIQUE,
-- λ°›λŠ”μ΄ 펼침용 (λ°±μ—”λ“œκ°€ 생성, μΆ”μΈ‘ λΆˆκ°€)
reveal_token TEXT NOT NULL UNIQUE
DEFAULT encode(gen_random_bytes(20), 'hex'),
status TEXT NOT NULL DEFAULT 'issued'
CHECK (status IN ('issued','viewed','redeemed','expired','refunded')),
viewed_at TIMESTAMPTZ, -- λ°›λŠ”μ΄κ°€ /g/<token> 첫 μ§„μž… μ‹œκ°
redeemed_at TIMESTAMPTZ,
redeemed_by UUID REFERENCES auth.users(id) ON DELETE SET NULL, -- μ‚¬μš©μ²˜λ¦¬ν•œ λ§€μž₯ 직원
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ NOT NULL -- order.expires_at 볡사 (λ°±μ—”λ“œ μ„ΈνŒ…)
);
CREATE INDEX IF NOT EXISTS idx_gift_coupons_cafe_status
ON public.gift_coupons (cafe_id, status, created_at DESC);
ALTER TABLE public.gift_coupons ENABLE ROW LEVEL SECURITY;
-- 사μž₯: 본인 카페 쿠폰 SELECT + UPDATE (redeem)
DROP POLICY IF EXISTS gift_coupons_cafe_rw ON public.gift_coupons;
CREATE POLICY gift_coupons_cafe_rw ON public.gift_coupons 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()
));
-- INSERT λŠ” λ°±μ—”λ“œ service-role (gift_order_service.mock_pay κ°€ λ°œκΈ‰)
-- reveal_token μ‘°νšŒλŠ” λ°±μ—”λ“œ service-role (gift_reveal λΌμš°ν„° β€” Phase C)
COMMENT ON TABLE public.gift_coupons IS
'λ°œν–‰ 쿠폰. code = λ§€μž₯ 직원 μž…λ ₯용 8자 영숫자. reveal_token = λ°›λŠ”μ΄ 펼침용 hex.';
COMMENT ON COLUMN public.gift_coupons.code IS
'8자 영숫자 μ•ŒνŒŒλ²³ ABCDEFGHJKLMNPQRSTUVWXYZ23456789 (O/0/I/1 μ œμ™Έ, 가독성). λ°±μ—”λ“œ 생성 + UNIQUE 좩돌 μž¬μ‹œλ„.';
COMMENT ON COLUMN public.gift_coupons.reveal_token IS
'32 byte hex. λ°›λŠ”μ΄ /g/<token> μ§„μž…. λ°±μ—”λ“œλ§Œ service-role 둜 쑰회.';