/** * 데이터베이스 조회·쓰기. 브라우저는 테이블에 직접 접근하지 않고 서버 함수(api/db.js)의 정해진 작업만 부른다. * 공개 키로 테이블을 읽고 쓰던 구조를 없애기 위한 것이다 (2026-10-07). 반환 형태는 Supabase 클라이언트와 같은 { data, error }. */ export type DbOp = | 'report.byId' | 'report.status' | 'run.clinicId' | 'clinic.byId' | 'plan.active' | 'plan.updateEntry' | 'perf.latest' | 'adjustments.list' | 'builds.latest' | 'builds.queue' | 'inputs.list' | 'inputs.add'; export interface DbResult { data: T | null; error: { message: string; code?: string | null } | null; } export async function db(op: DbOp, params: Record = {}): Promise> { try { const res = await fetch('/api/db', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ op, params }), }); const body = (await res.json().catch(() => null)) as DbResult | null; if (!body) return { data: null, error: { message: `서버 응답 오류 (${res.status})` } }; return body; } catch (e) { console.error(`[db] ${op} 연결 실패`, e); return { data: null, error: { message: '서버에 연결할 수 없습니다' } }; } }