Spaces:
Sleeping
Sleeping
File size: 3,596 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 | -- μΉ΄ν μμ± μ λ¬ΌμΏ ν° MVP β voice_letters (2026-05-28, P1a Phase B)
--
-- μλμ΄ μμ±ν μμ±νΈμ§ (ν
μ€νΈ + 보μ΄μ€ + λͺ¨λλ μ΄μ
+ ν©μ±λ audio path).
-- μμ²μ: doc/runbook/req_cafe_gift_mvp.md Β§1
-- μ€κ³: doc/runbook/cafe_gift_p1a.md Β§2 sql/047
--
-- νλ¦:
-- 1) μλ ν
μ€νΈ μ
λ ₯ (β€400μ, λ°±μλ κ²μ¦)
-- 2) moderation_service β approved/blocked
-- 3) approved λ©΄ TTS ν©μ± β 'voice-letters' Storage μ
λ‘λ β audio_path μΈν
-- 4) gift_orders κ° voice_letter_id FK λ‘ μ°κ²° (1:1)
--
-- λΉλ‘κ·ΈμΈ μλμ΄ λ§λ€ μ μμ΄μΌ νλ―λ‘ λ°±μλ service-role λ§ INSERT.
-- RLS κ³΅κ° SELECT μμ β reveal μ λ³λ token (gift_coupons.reveal_token) μΌλ‘ λ°±μλ λΌμ°ν°κ° service-role μ‘°ν.
--
-- β νκ· κ°λ:
-- - μ κ· ν
μ΄λΈ, κΈ°μ‘΄ CHECK μν₯ 0 (sql/043 μ¬κ³ κ°λ)
-- - voice_clone νΈμΆ 0 (μμ€ν
UID + λ΄μ₯νμλ§, P2 νμ₯)
-- - is_preview=True (chat broadcast leak μ°¨λ¨)
CREATE TABLE IF NOT EXISTS public.voice_letters (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- gift_orders.id μ μλ°©ν₯ 1:1 (FK λ sql/048 μμ 보κ°)
-- νΈμ§ λ¨Όμ β λͺ¨λλ μ΄μ
ν΅κ³Ό β μ£Όλ¬Έ attach κ°λ₯. λλ λμ μμ±.
order_id UUID,
sender_name TEXT NOT NULL DEFAULT '',
-- λ°±μλκ° 400μ cap κ²μ¦ (μ¬μ©μ κ²°μ #3). DB μ hard cap CHECK μ λ β μΆν μ μ±
λ³κ²½ μ λ§μ΄κ·Έλ μ΄μ
μμ΄ κ°λ₯.
text TEXT NOT NULL,
voice_kind TEXT NOT NULL DEFAULT '__default__',
-- '__default__' (Sohee) | '__spk__<code>' (λ΄μ₯νμ 8μ’
)
-- ν©μ± κ²°κ³Ό (λͺ¨λλ μ΄μ
approved μμλ§ μ±μμ§)
audio_path TEXT, -- Storage 'voice-letters' λ²ν· path
audio_duration_sec NUMERIC(6,2),
moderation_status TEXT NOT NULL DEFAULT 'pending'
CHECK (moderation_status IN ('pending','approved','blocked','manual_review')),
moderation_reason TEXT, -- blocked μ μ¬μ©μ λ
ΈμΆμ© μ§§μ μ΄μ
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_voice_letters_status
ON public.voice_letters (moderation_status, created_at DESC);
ALTER TABLE public.voice_letters ENABLE ROW LEVEL SECURITY;
-- κ³΅κ° INSERT/UPDATE μ μ±
μμ. λ°±μλ service-role ν€λ§ μμ
.
-- (λΌμ°ν°κ° λΉλ‘κ·ΈμΈ μλ μ
λ ₯ λ°μ service-role λ‘ INSERT, owner_user_id μ»¬λΌ μμ.)
CREATE OR REPLACE FUNCTION public._voice_letters_touch_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS voice_letters_touch_updated_at ON public.voice_letters;
CREATE TRIGGER voice_letters_touch_updated_at
BEFORE UPDATE ON public.voice_letters
FOR EACH ROW EXECUTE FUNCTION public._voice_letters_touch_updated_at();
COMMENT ON TABLE public.voice_letters IS
'μΉ΄ν μ λ¬ΌμΏ ν° μμ±νΈμ§. β€400μ, λ΄μ₯νμλ§ (P1a). λͺ¨λλ μ΄μ
ν΅κ³Ό ν audio ν©μ±.';
COMMENT ON COLUMN public.voice_letters.voice_kind IS
'__default__ (Sohee) λλ __spk__<code> (λ΄μ₯νμ 8μ’
). voice_clone(β€οΈ) μ P2.';
COMMENT ON COLUMN public.voice_letters.moderation_status IS
'pending: κ²μ¬ μ | approved: ν΅κ³Ό (audio ν©μ± OK) | blocked: μ°¨λ¨ (κ²°μ μ§μ
λΆκ°) | manual_review: μ΄μμ κ²ν (Phase E)';
|