File size: 3,558 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
-- μ•ˆλΆ€ λ©”μ‹œμ§€ (`/message`) β€” 본인 μŒμƒ‰μœΌλ‘œ κ°€μ‘±/μΉœκ΅¬μ—κ²Œ 보낼 짧은 μŒμ„± λ©”μ‹œμ§€.
--
-- 흐름:
--   1) μ‚¬μš©μžκ°€ μŒμ„±/ν…μŠ€νŠΈλ‘œ "이런 μ•ˆλΆ€ λ³΄λ‚΄μ€˜" μ§€μ‹œ
--   2) LLM 이 1~2λ¬Έμž₯ λ³Έλ¬Έ 생성 + μ‚¬μš©μž μŒμƒ‰ ICL TTS ν•©μ„±
--   3) wav λ₯Ό Supabase Storage (scheduled-audio bucket μž¬μ‚¬μš©) 에 μ—…λ‘œλ“œ
--   4) μ¦‰μ‹œ 곡유: μ‚¬μš©μžκ°€ 카카였 JS SDK 둜 본인 μΉ΄ν†‘μ—μ„œ κ°€μ‘± μ±„νŒ…λ°© 선택 β†’ /listen/<id> 링크 λ°œμ†‘
--   5) μ˜ˆμ•½: μ‹œκ° 도달 μ‹œ μ‚¬μš©μž λ³ΈμΈμ—κ²Œ μ•Œλ¦Όν†‘ ("μ€€λΉ„λμ–΄μš”. κ³΅μœ ν•˜κΈ°") β†’ 클릭 β†’ /listen/<id> νŽ˜μ΄μ§€μ˜
--           [κ³΅μœ ν•˜κΈ°] λ²„νŠΌ β†’ 카톑 곡유
--
-- λ°œμ‹ μ€ 항상 μ‚¬μš©μž 본인 β€” μ•Œλ¦Όν†‘μ€ μ‚¬μš©μž μžμ‹ μ—κ²Œλ§Œ λ°œμ†‘ (μ •μ±… μ•ˆμ „), κ°€μ‘±μ—κ²ŒλŠ” μ‚¬μš©μž μΉ΄ν†‘μœΌλ‘œ 직접.
-- λ°›λŠ” μ‚¬λžŒ 번호 μˆ˜μ§‘ μ—†μŒ (PIPA λΆ€λ‹΄ νšŒν”Ό). recipient_label 은 μ‚¬μš©μžκ°€ 자기만 μ•Œμ•„λ³΄λŠ” λ©”λͺ¨.

CREATE TABLE IF NOT EXISTS public.care_messages (
    id                 UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id            UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,

    -- μž…λ ₯
    recipient_label    TEXT NOT NULL DEFAULT '',  -- "μ–΄λ¨Έλ‹ˆ" / "μ•„λΉ " λ“± μ‚¬μš©μž λ©”λͺ¨
    voice_input_text   TEXT,                       -- STT λ˜λŠ” 직접 μž…λ ₯ν•œ μ§€μ‹œλ¬Έ (이λ ₯)

    -- μƒμ„±λœ κ²°κ³Ό
    generated_text     TEXT NOT NULL DEFAULT '',  -- LLM 이 λ§Œλ“  λ³Έλ¬Έ (μ‹€μ œ μŒμ„± ν…μŠ€νŠΈ)
    audio_file_path    TEXT,                       -- storage 경둜 (μ‚­μ œμš©)
    audio_file_url     TEXT,                       -- 1λ…„ signed URL (λͺ©λ‘ 미리듣기)
    voice_storage_path TEXT,                       -- 합성에 μ‚¬μš©ν•œ μ‚¬μš©μž μŒμƒ‰ (μž¬ν•©μ„± 좔적)

    -- μ˜ˆμ•½ (NULL = μ¦‰μ‹œ 곡유, μ˜ˆμ•½ μ—†μŒ)
    scheduled_at       TIMESTAMPTZ,
    timezone           TEXT NOT NULL DEFAULT 'Asia/Seoul',
    next_fire_at       TIMESTAMPTZ,
    last_fired_at      TIMESTAMPTZ,
    active             BOOLEAN NOT NULL DEFAULT TRUE,

    -- 뢄석
    shared_at          TIMESTAMPTZ,                -- μ‚¬μš©μžκ°€ [κ³΅μœ ν•˜κΈ°] λ²„νŠΌ λˆ„λ₯Έ μ‹œκ°

    created_at         TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at         TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_care_messages_user
    ON public.care_messages (user_id, created_at DESC);

CREATE INDEX IF NOT EXISTS idx_care_messages_due
    ON public.care_messages (active, next_fire_at)
    WHERE next_fire_at IS NOT NULL;

ALTER TABLE public.care_messages ENABLE ROW LEVEL SECURITY;

DROP POLICY IF EXISTS care_messages_owner ON public.care_messages;
CREATE POLICY care_messages_owner ON public.care_messages
    FOR ALL
    USING (user_id = auth.uid())
    WITH CHECK (user_id = auth.uid());

-- updated_at μžλ™ κ°±μ‹ 
CREATE OR REPLACE FUNCTION public._care_messages_touch_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS care_messages_touch_updated_at ON public.care_messages;
CREATE TRIGGER care_messages_touch_updated_at
    BEFORE UPDATE ON public.care_messages
    FOR EACH ROW EXECUTE FUNCTION public._care_messages_touch_updated_at();

-- ───────── Storage μ •μ±… ─────────
-- scheduled-audio bucket μž¬μ‚¬μš© (sql/016 μ—μ„œ 이미 생성). 같은 폴더 (<user_id>/)
-- μ•ˆμ— care λ©”μ‹œμ§€ wav λ₯Ό λ‘λ―€λ‘œ μΆ”κ°€ μ •μ±… λΆˆν•„μš”.
-- care 파일λͺ… μ»¨λ²€μ…˜: <user_id>/care-<message_id>-<timestamp>.wav