Spaces:
Sleeping
Sleeping
File size: 4,543 Bytes
aa9892b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | -- ์นดํ ์์ฑ ์ ๋ฌผ์ฟ ํฐ MVP โ gift_orders (2026-05-28, P1a Phase B)
--
-- ์ฃผ๋ฌธ = ์นดํยท์ํ + ์์ฑํธ์ง + ๋ฐ๋์ด ์ด๋ฆ + ๊ตฌ๋งค์ ์๋ณ.
-- ์์ฒญ์: doc/runbook/req_cafe_gift_mvp.md ยง1
-- ์ค๊ณ: doc/runbook/cafe_gift_p1a.md ยง2 sql/048
--
-- Stateless ๊ตฌ๋งค์ (์ฌ์ฉ์ ๊ฒฐ์ #1):
-- - buyer_user_id ๋ NULL (Supabase anon ๋ฏธ์ฌ์ฉ)
-- - ์์์ฆ/์ฌ์ ๊ทผ = reveal_token + buyer_email
--
-- ๊ฒฐ์ mock (P1a):
-- - status 'mock_paid' ๋ง coupon ๋ฐ๊ธ. P1b ์์ 'paid' enum ์ถ๊ฐ.
-- - mock-pay endpoint ๊ฐ ์ค PG ์ฝ๋ฐฑ์ ๊ฐ์ฅ (์ํฐ๋งํฌ๋ก UI ๋
ธ์ถ)
--
-- ์ ํจ๊ธฐ๊ฐ 5๋
(๊ณต์ ์ ํ์ค์ฝ๊ด):
-- - ๋ฐฑ์๋๊ฐ ๋ช
์ set (DB default X) โ ์ ์ฑ
๋ณ๊ฒฝ ์ถ์ ๊ฐ๋ฅ
-- - gift_coupons.expires_at ๋ ์ด ๊ฐ์ ๋ณต์ฌ
--
-- โ ํ๊ท ๊ฐ๋: ์ ๊ท ํ
์ด๋ธ, CHECK ๋ชจ๋ ์ ๊ท ์ปฌ๋ผ๋ง. ๊ฒฐ์ mock ๋ช
์ ๋ถ๋ฆฌ ('mock_paid' vs 'paid').
CREATE TABLE IF NOT EXISTS public.gift_orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cafe_id UUID NOT NULL REFERENCES public.cafe_merchants(id) ON DELETE RESTRICT,
product_id UUID NOT NULL REFERENCES public.gift_products(id) ON DELETE RESTRICT,
voice_letter_id UUID REFERENCES public.voice_letters(id) ON DELETE SET NULL,
-- Stateless ๊ตฌ๋งค์ ์๋ณ (์ฌ์ฉ์ ๊ฒฐ์ #1)
buyer_user_id UUID REFERENCES auth.users(id) ON DELETE SET NULL, -- P1a ๋ ํญ์ NULL
buyer_name TEXT NOT NULL DEFAULT '',
buyer_phone_e164 TEXT, -- ์์์ฆ/ํ๋ถ์ฉ (์ ํ)
buyer_email TEXT, -- ์์์ฆ ๋ฐ์ก (์ ํ)
recipient_name TEXT NOT NULL DEFAULT '',
amount_krw INT NOT NULL CHECK (amount_krw > 0),
-- P1a ๊ฒฐ์ mock โ 'mock_paid' ๋ง coupon ๋ฐ๊ธ. P1b ์์ 'paid' enum ์ ์ํ.
status TEXT NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending','letter_pending','payable','mock_paid','paid','refunded','canceled')),
pg_tx_id TEXT, -- P1b ์์ ์ค PG ๊ฑฐ๋ ID
-- ์ ํจ๊ธฐ๊ฐ 5๋
(๋ฐฑ์๋๊ฐ now + 5y ๋ช
์ ์ธํ
, DB default X)
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_gift_orders_cafe_status
ON public.gift_orders (cafe_id, status, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_gift_orders_buyer_user
ON public.gift_orders (buyer_user_id)
WHERE buyer_user_id IS NOT NULL;
-- voice_letters โ orders FK ์๋ฐฉํฅ ๋ณด๊ฐ (sql/047 ์์๋ column ๋ง ๋ง๋ค๊ณ FK ๋ ์ฌ๊ธฐ)
ALTER TABLE public.voice_letters
DROP CONSTRAINT IF EXISTS voice_letters_order_id_fk;
ALTER TABLE public.voice_letters
ADD CONSTRAINT voice_letters_order_id_fk
FOREIGN KEY (order_id) REFERENCES public.gift_orders(id) ON DELETE SET NULL;
ALTER TABLE public.gift_orders ENABLE ROW LEVEL SECURITY;
-- ์ฌ์ฅ: ๋ณธ์ธ ์นดํ ์ฃผ๋ฌธ SELECT (๋์๋ณด๋์ฉ, Phase E)
DROP POLICY IF EXISTS gift_orders_cafe_read ON public.gift_orders;
CREATE POLICY gift_orders_cafe_read ON public.gift_orders FOR SELECT
USING (cafe_id IN (
SELECT id FROM public.cafe_merchants WHERE owner_user_id = auth.uid()
));
-- ๊ตฌ๋งค์ ๋ณธ์ธ (๋ก๊ทธ์ธ ์ผ์ด์ค โ P1a ๋ NULL ์ด๋ผ ๋นํ์ฑ, P1b ํธํ)
DROP POLICY IF EXISTS gift_orders_buyer_read ON public.gift_orders;
CREATE POLICY gift_orders_buyer_read ON public.gift_orders FOR SELECT
USING (buyer_user_id = auth.uid());
-- INSERT/UPDATE ๋ ๋ฐฑ์๋ service-role ๋ง (๋น๋ก๊ทธ์ธ ์๋ ํ๋ฆ)
CREATE OR REPLACE FUNCTION public._gift_orders_touch_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS gift_orders_touch_updated_at ON public.gift_orders;
CREATE TRIGGER gift_orders_touch_updated_at
BEFORE UPDATE ON public.gift_orders
FOR EACH ROW EXECUTE FUNCTION public._gift_orders_touch_updated_at();
COMMENT ON TABLE public.gift_orders IS
'์นดํ ์ ๋ฌผ ์ฃผ๋ฌธ. P1a stateless (buyer_user_id NULL), mock_paid ๋ง coupon ๋ฐ๊ธ. 5๋
๋ง๋ฃ.';
COMMENT ON COLUMN public.gift_orders.status IS
'pending โ letter_pending โ payable โ mock_paid (P1a) | paid (P1b) โ refunded/canceled.';
COMMENT ON COLUMN public.gift_orders.expires_at IS
'๊ตฌ๋งค์ผ + 5๋
(๊ณต์ ์ ํ์ค์ฝ๊ด). ๋ฐฑ์๋๊ฐ ๋ช
์ ์ธํ
(DB default X).';
|