File size: 3,380 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
-- 카페 BGM μ—°μ†μž¬μƒ νƒ€μž„λΌμΈ (2026-05-20, BGM Phase 2).
--
-- 점주가 [μ›°μ»΄ 멘트 TTS] β†’ [BGM] β†’ [신메뉴 멘트 TTS] β†’ [BGM] ... λ₯Ό μˆœμ„œλŒ€λ‘œ μ‘°ν•©.
-- κΈ°μ‘΄ playlists(sql/013, μ˜ˆμ•½λ°©μ†‘ μ „μš©)와 λ³„κ°œ β€” BGM μ „μš© μ‹ κ·œ ν…Œμ΄λΈ”.
--
-- 핡심 원칙(μž¬μƒ 경둜 GPU 0):
--   - bgm 슬둯   = music_themes(κΈ€λ‘œλ²Œ) λ˜λŠ” user_music(Phase 4) μ°Έμ‘° β†’ Storage 파일.
--   - tts_ment 슬둯 = 멘트 ν…μŠ€νŠΈλ₯Ό **사전 생성**(νƒ€μž„λΌμΈ μ €μž₯/νŽΈμ§‘ μ‹œ TTS 1회) β†’
--     ment_audio_path 에 μ €μž₯. μž¬μƒ μ‹œμ—” 이 파일만 μ„œλΉ™ (μ‹€μ‹œκ°„ TTS μ•„λ‹˜).
--   ment_status: pending(생성 λŒ€κΈ°) β†’ ready(파일 있음) β†’ failed(μž¬μ‹œλ„ λŒ€μƒ).
--
-- νšŒκ·€ 0: μ‹ κ·œ ν…Œμ΄λΈ” β€” κΈ°μ‘΄ TTS/voice/playlist/care/music_themes 영ν–₯ μ—†μŒ.
-- RLS: μ†Œμœ μžλ§Œ read/write (λ°©μ–΄). λ°±μ—”λ“œλŠ” service_role + user_id ν•„ν„° 병행.

CREATE TABLE IF NOT EXISTS public.music_timelines (
    id          uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id     uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
    name        text NOT NULL DEFAULT 'λ‚΄ 카페 BGM',
    is_active   boolean NOT NULL DEFAULT true,
    created_at  timestamptz NOT NULL DEFAULT now(),
    updated_at  timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS public.timeline_items (
    id              uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    timeline_id     uuid NOT NULL REFERENCES public.music_timelines(id) ON DELETE CASCADE,
    position        integer NOT NULL,            -- μž¬μƒ μˆœμ„œ (0-based)
    item_type       text NOT NULL CHECK (item_type IN ('bgm', 'tts_ment')),

    -- bgm 슬둯
    music_theme_id  uuid REFERENCES public.music_themes(id) ON DELETE SET NULL,

    -- tts_ment 슬둯 (사전 생성 β†’ 파일 μž¬μƒ)
    ment_text       text,
    ment_voice      text,                        -- μŒμƒ‰/μŠ€ν”Όμ»€ ν‚€
    ment_audio_path text,                        -- μƒμ„±λœ 멘트 μ˜€λ””μ˜€ ('music' 버킷 μƒλŒ€ 경둜)
    ment_status     text NOT NULL DEFAULT 'pending'
                        CHECK (ment_status IN ('pending', 'ready', 'failed')),

    settings        jsonb NOT NULL DEFAULT '{}', -- loop/gap/volume λ“± μŠ¬λ‘―λ³„ μ˜΅μ…˜
    created_at      timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS timeline_items_timeline_pos_idx
    ON public.timeline_items (timeline_id, position);
CREATE INDEX IF NOT EXISTS music_timelines_user_idx
    ON public.music_timelines (user_id, updated_at DESC);

ALTER TABLE public.music_timelines ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.timeline_items  ENABLE ROW LEVEL SECURITY;

-- μ†Œμœ μžλ§Œ μ ‘κ·Ό (λ°±μ—”λ“œ service_role 은 RLS bypass β€” μΆ”κ°€ λ°©μ–΄μ„ ).
DROP POLICY IF EXISTS music_timelines_owner ON public.music_timelines;
CREATE POLICY music_timelines_owner ON public.music_timelines
    FOR ALL USING (user_id = auth.uid()) WITH CHECK (user_id = auth.uid());

DROP POLICY IF EXISTS timeline_items_owner ON public.timeline_items;
CREATE POLICY timeline_items_owner ON public.timeline_items
    FOR ALL USING (
        EXISTS (SELECT 1 FROM public.music_timelines t
                WHERE t.id = timeline_items.timeline_id AND t.user_id = auth.uid())
    );

COMMENT ON TABLE public.music_timelines IS
    '카페 BGM μ—°μ†μž¬μƒ νƒ€μž„λΌμΈ (멘트 TTS + BGM). μž¬μƒ=Storage 파일 μ„œλΉ™.';