-- 1. 유저 프로필 테이블 (auth.users와 연동) create table public.profiles ( id uuid references auth.users(id) on delete cascade not null primary key, email text, full_name text, avatar_url text, credits integer default 0, -- 사주 보기용 머니/크레딧 created_at timestamp with time zone default timezone('utc'::text, now()) not null ); -- RLS (Row Level Security) 설정 alter table public.profiles enable row level security; create policy "공개 프로필은 누구나 볼 수 있음" on public.profiles for select using ( true ); create policy "사용자는 자신의 프로필을 생성 가능" on public.profiles for insert with check ( auth.uid() = id ); create policy "사용자는 자신의 프로필만 수정 가능" on public.profiles for update using ( auth.uid() = id ); -- 새 유저 가입 시 자동으로 profile 생성하는 트리거 create function public.handle_new_user() returns trigger as $$ begin insert into public.profiles (id, email, full_name, avatar_url) values (new.id, new.email, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url'); return new; end; $$ language plpgsql security definer; create trigger on_auth_user_created after insert on auth.users for each row execute procedure public.handle_new_user(); -- 2. 사주 기록 테이블 (저장된 결과) create table public.saju_records ( id bigint generated by default as identity primary key, user_id uuid references public.profiles(id) not null, saju_data jsonb not null, -- 사주 원국 데이터 (JSON) interpretation text, -- AI 해석 결과 (Markdown 텍스트) created_at timestamp with time zone default timezone('utc'::text, now()) not null ); alter table public.saju_records enable row level security; create policy "사용자는 자신의 기록만 볼 수 있음" on public.saju_records for select using ( auth.uid() = user_id ); create policy "사용자는 자신의 기록만 생성 가능" on public.saju_records for insert with check ( auth.uid() = user_id ); -- 3. 결제 내역 테이블 (PortOne 연동) create table public.payments ( id uuid default gen_random_uuid() primary key, user_id uuid references public.profiles(id) not null, merchant_uid text not null unique, -- 주문 번호 imp_uid text, -- 포트원 고유 번호 amount integer not null, token_amount integer default 0, -- 충전된 토큰 수 status text not null default 'pending', -- pending, paid, failed, cancelled created_at timestamp with time zone default timezone('utc'::text, now()) not null ); alter table public.payments enable row level security; create policy "사용자는 자신의 결제 내역만 볼 수 있음" on public.payments for select using ( auth.uid() = user_id ); create policy "사용자는 자신의 결제 내역 생성 가능" on public.payments for insert with check ( auth.uid() = user_id ); create policy "사용자는 자신의 결제 내역 수정 가능" on public.payments for update using ( auth.uid() = user_id ); -- 토큰(크레딧) 충전을 위한 RPC 함수 (atomic increment, RLS 우회) create or replace function public.add_credits(user_id_input uuid, amount_input integer) returns integer as $$ declare new_credits integer; begin update public.profiles set credits = credits + amount_input where id = user_id_input returning credits into new_credits; return new_credits; end; $$ language plpgsql security definer;