feat: V2-7 Admin 콘솔 리디자인 + 3단계 권한 + SaaS 전환 + 코드 정리
- Admin CRM: D3RO Console 스타일 전체 적용 (panelSx/tableSx/filterBtnSx) - 3단계 권한: manager/admin/super_admin (DB + Edge Functions + Frontend) - 랜딩 페이지: 1회 결제 → 월간/연간 구독 SaaS 모델 (10개 언어) - SSE 스트리밍: VoiceConversation Premium LLM 라우팅 + fallback - Supabase 클라이언트: packages/api-client 공통 추출 (browser+server) - RPC 함수 타입: 9개 정의 (admin_usage_by_feature 등) - callAdminApi 401 버그 수정 (getUser() 선행 토큰 갱신)
This commit is contained in:
parent
d0e854c255
commit
8af75a0a1e
50 changed files with 2185 additions and 950 deletions
|
|
@ -1,9 +1,9 @@
|
|||
// server/supabase/functions/admin-subscriptions/index.ts
|
||||
// 구독 CRUD — admin: 조회 / super_admin: 생성/수정/삭제
|
||||
// 구독 CRUD — manager: 조회+수정 / admin+: 생성/수정/삭제
|
||||
|
||||
import { corsHeaders, handleCorsPreflightRequest } from '../_shared/cors.ts'
|
||||
import { authErrorResponse, type AuthError } from '../_shared/auth.ts'
|
||||
import { requireAdmin, requireSuperAdmin } from '../_shared/admin-auth.ts'
|
||||
import { requireManager, requireAdmin } from '../_shared/admin-auth.ts'
|
||||
import { createServiceRoleClient } from '../_shared/quota.ts'
|
||||
import { writeAuditLog } from '../_shared/audit.ts'
|
||||
|
||||
|
|
@ -45,9 +45,9 @@ Deno.serve(async (req: Request) => {
|
|||
const url = new URL(req.url)
|
||||
const serviceClient = createServiceRoleClient()
|
||||
|
||||
// ── GET: 목록/상세 ──
|
||||
// ── GET: 목록/상세 (manager 이상) ──
|
||||
if (req.method === 'GET') {
|
||||
await requireAdmin(req)
|
||||
await requireManager(req)
|
||||
|
||||
const userId = url.searchParams.get('userId')
|
||||
|
||||
|
|
@ -95,9 +95,9 @@ Deno.serve(async (req: Request) => {
|
|||
return jsonResponse({ subscriptions: data ?? [], total: count ?? 0, page, limit })
|
||||
}
|
||||
|
||||
// ── POST: 생성 (super_admin) ──
|
||||
// ── POST: 생성 (admin 이상) ──
|
||||
if (req.method === 'POST') {
|
||||
const admin = await requireSuperAdmin(req)
|
||||
const admin = await requireAdmin(req)
|
||||
const body = (await req.json()) as CreateBody
|
||||
|
||||
if (!body.userId || !body.tier || !body.memo) {
|
||||
|
|
@ -155,9 +155,9 @@ Deno.serve(async (req: Request) => {
|
|||
return jsonResponse({ success: true, subscription: created as unknown as Record<string, unknown> }, 201)
|
||||
}
|
||||
|
||||
// ── PATCH: 수정 (super_admin) ──
|
||||
// ── PATCH: 수정 (manager 이상) ──
|
||||
if (req.method === 'PATCH') {
|
||||
const admin = await requireSuperAdmin(req)
|
||||
const admin = await requireManager(req)
|
||||
const userId = url.searchParams.get('userId')
|
||||
if (!userId) return jsonResponse({ error: 'userId query param required' }, 400)
|
||||
|
||||
|
|
@ -211,9 +211,9 @@ Deno.serve(async (req: Request) => {
|
|||
return jsonResponse({ success: true, subscription: after as unknown as Record<string, unknown> })
|
||||
}
|
||||
|
||||
// ── DELETE: 소프트 삭제 (super_admin) ──
|
||||
// ── DELETE: 소프트 삭제 (admin 이상) ──
|
||||
if (req.method === 'DELETE') {
|
||||
const admin = await requireSuperAdmin(req)
|
||||
const admin = await requireAdmin(req)
|
||||
const userId = url.searchParams.get('userId')
|
||||
if (!userId) return jsonResponse({ error: 'userId query param required' }, 400)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue