feat(phase3a): ai-usage에 music 추가 + music_tracks·CHECK 마이그레이션

- lib/ai-usage.ts: MUSIC_DAILY_LIMIT=1 추가, AiService 타입에 'music' 포함
- lib/__tests__/ai-usage.test.ts: MUSIC_DAILY_LIMIT 상수 검증 테스트 추가
- supabase/migrations/2026-07-03-phase3a-music.sql: music_tracks 테이블, CHECK 확장, service_settings 정리

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAtcmKKtqDUe4NyVgy1aLQ
This commit is contained in:
2026-07-03 12:48:42 +09:00
parent da33254076
commit 7100842179
3 changed files with 29 additions and 2 deletions

View File

@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest'; import { describe, it, expect } from 'vitest';
import { kstDayStartISO, SAJU_DAILY_LIMIT, TAROT_DAILY_LIMIT } from '../ai-usage'; import { kstDayStartISO, SAJU_DAILY_LIMIT, TAROT_DAILY_LIMIT, MUSIC_DAILY_LIMIT } from '../ai-usage';
describe('kstDayStartISO', () => { describe('kstDayStartISO', () => {
it('KST 자정을 UTC로 환산한다 (KST 15:00 UTC = 당일 00:00 KST)', () => { it('KST 자정을 UTC로 환산한다 (KST 15:00 UTC = 당일 00:00 KST)', () => {
@@ -14,4 +14,7 @@ describe('kstDayStartISO', () => {
expect(SAJU_DAILY_LIMIT).toBe(1); expect(SAJU_DAILY_LIMIT).toBe(1);
expect(TAROT_DAILY_LIMIT).toBe(3); expect(TAROT_DAILY_LIMIT).toBe(3);
}); });
it('음악 일일 제한 상수', () => {
expect(MUSIC_DAILY_LIMIT).toBe(1);
});
}); });

View File

@@ -2,7 +2,8 @@ import type { SupabaseClient } from '@supabase/supabase-js';
export const SAJU_DAILY_LIMIT = 1; export const SAJU_DAILY_LIMIT = 1;
export const TAROT_DAILY_LIMIT = 3; export const TAROT_DAILY_LIMIT = 3;
export type AiService = 'saju' | 'tarot'; export const MUSIC_DAILY_LIMIT = 1;
export type AiService = 'saju' | 'tarot' | 'music';
/** KST(UTC+9) 자정을 UTC ISO로. 오늘 사용량 집계 하한. */ /** KST(UTC+9) 자정을 UTC ISO로. 오늘 사용량 집계 하한. */
export function kstDayStartISO(now: Date): string { export function kstDayStartISO(now: Date): string {

View File

@@ -0,0 +1,23 @@
-- Phase 3a (2026-07-03): 음악 회원 저장 + 사용량 로그 확장 + 음악 숨김 해제
-- 의존성: 2026-07-02-phase2-saju-tarot.sql(ai_usage_log 생성) 적용 후 실행
-- 적용: 클라우드 Supabase + NAS self-host 양쪽
CREATE TABLE IF NOT EXISTS music_tracks (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
title text,
story text,
lyrics text,
style text,
audio_url text,
task_id text,
created_at timestamptz NOT NULL DEFAULT now()
);
ALTER TABLE music_tracks ENABLE ROW LEVEL SECURITY;
CREATE POLICY music_select_own ON music_tracks FOR SELECT USING (auth.uid() = user_id);
-- ai_usage_log CHECK에 'music' 추가 (phase2의 인라인 CHECK auto-name 제거 후 재정의)
ALTER TABLE ai_usage_log DROP CONSTRAINT IF EXISTS ai_usage_log_service_check;
ALTER TABLE ai_usage_log ADD CONSTRAINT ai_usage_log_service_check CHECK (service IN ('saju','tarot','music'));
DELETE FROM service_settings WHERE id = 'music';