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:
윤찬 2026-04-13 01:28:10 +09:00
parent d0e854c255
commit 8af75a0a1e
50 changed files with 2185 additions and 950 deletions

View file

@ -0,0 +1,114 @@
// apps/admin/src/lib/console-theme.ts
// D3RO Console 디자인 토큰 — 터미널/콘솔 스타일
export const C = {
// backgrounds
base: '#000000',
panel: '#09090b',
panelHover: '#121214',
// borders
border: '#1f1f22',
borderHl: '#27272a',
// text
dim: '#71717a',
text: '#a1a1aa',
bright: '#ffffff',
// accent
accent: '#ff5c28',
// semantic
green: '#22c55e',
green400: '#4ade80',
orange: '#f97316',
orange400: '#fb923c',
red: '#ef4444',
red400: '#f87171',
blue: '#3b82f6',
blue400: '#60a5fa',
purple: '#a855f7',
purple400: '#c084fc',
} as const
export const FONT = '"JetBrains Mono", ui-monospace, monospace'
/** 공통 패널 스타일 */
export const panelSx = {
bgcolor: C.panel,
border: `1px solid ${C.border}`,
borderRadius: '16px',
position: 'relative' as const,
overflow: 'hidden',
'&:hover': { borderColor: C.borderHl },
transition: 'border-color 0.2s',
}
/** 테이블 공통 스타일 */
export const tableSx = {
width: '100%',
borderCollapse: 'collapse' as const,
fontFamily: FONT,
fontSize: '12px',
'& th': {
pb: 1.5,
fontWeight: 400,
textTransform: 'uppercase' as const,
letterSpacing: '0.1em',
color: C.dim,
textAlign: 'left' as const,
borderBottom: `1px solid ${C.borderHl}`,
},
'& td': {
py: 1.5,
textAlign: 'left' as const,
color: C.text,
borderBottom: `1px solid ${C.border}50`,
},
'& tr:hover td': {
bgcolor: `${C.borderHl}33`,
},
}
/** 필터 버튼 스타일 */
export const filterBtnSx = (active: boolean) => ({
px: 1.5,
py: 0.5,
borderRadius: '4px',
fontFamily: FONT,
fontSize: '10px',
fontWeight: 500,
letterSpacing: '0.1em',
textTransform: 'uppercase' as const,
cursor: 'pointer',
border: `1px solid ${active ? C.borderHl : 'transparent'}`,
bgcolor: active ? C.borderHl : 'transparent',
color: active ? C.bright : C.text,
'&:hover': {
bgcolor: C.panelHover,
borderColor: C.border,
},
transition: 'all 0.15s',
})
/** 상태 뱃지 스타일 */
export function statusBadgeSx(variant: 'green' | 'red' | 'orange' | 'blue' | 'purple') {
const colorMap = {
green: { bg: 'rgba(34, 197, 94, 0.1)', fg: C.green400, border: 'rgba(34, 197, 94, 0.2)' },
red: { bg: 'rgba(239, 68, 68, 0.1)', fg: C.red400, border: 'rgba(239, 68, 68, 0.2)' },
orange: { bg: 'rgba(249, 115, 22, 0.1)', fg: C.orange400, border: 'rgba(249, 115, 22, 0.2)' },
blue: { bg: 'rgba(59, 130, 246, 0.1)', fg: C.blue400, border: 'rgba(59, 130, 246, 0.2)' },
purple: { bg: 'rgba(168, 85, 247, 0.1)', fg: C.purple400, border: 'rgba(168, 85, 247, 0.2)' },
}
const c = colorMap[variant]
return {
display: 'inline-block',
px: 1,
py: 0.25,
borderRadius: '4px',
fontSize: '10px',
fontFamily: FONT,
fontWeight: 500,
letterSpacing: '0.05em',
bgcolor: c.bg,
color: c.fg,
border: `1px solid ${c.border}`,
}
}