feat: complete release preparation, 10+ ad mediation, CI/CD, and docker deployment
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped

This commit is contained in:
Yun Chan 2026-08-20 11:12:05 +09:00
parent 5cd1de6859
commit 708e20f747
406 changed files with 42464 additions and 6199 deletions

View file

@ -1,262 +1,343 @@
// apps/admin/src/app/(admin)/page.tsx
// D3RO Console — Dashboard Overview
// D3RO Voice Admin CRM — Unified Dashboard Overview (Midnight Glass v2)
import { Box } from '@mui/material'
import { getSupabaseServerClient } from '@/lib/supabase-server'
import { C, FONT, panelSx, tableSx } from '@/lib/console-theme'
import { Box, Typography, Button } from '@mui/material'
import { fetchServerStats } from '@/lib/api-server'
import { C, FONT_SANS, FONT_MONO, panelSx, tableSx, statusBadgeSx } from '@/lib/console-theme'
import { DoubleBezelCard, StatRing, TactileBadge } from '@d3ro/ui/components/ds'
import { DashboardSimulator } from '@/components/dashboard-simulator'
import Link from 'next/link'
interface StatData {
label: string
value: number
color: string
glowClass: string
borderColor: string
badge: string
badgeColor?: string
}
async function loadStats(): Promise<StatData[]> {
const supabase = await getSupabaseServerClient()
const [profilesRes, paidRes, usageRes, expiringRes] = await Promise.all([
supabase.from('profiles').select('id', { count: 'exact', head: true }),
supabase.from('subscriptions').select('id', { count: 'exact', head: true })
.neq('tier', 'free').eq('status', 'active'),
supabase.from('daily_usage').select('count')
.eq('date', new Date().toISOString().split('T')[0]),
supabase.from('subscriptions').select('id', { count: 'exact', head: true })
.eq('status', 'active').eq('payment_provider', 'payple')
.lte('current_period_end', new Date(Date.now() + 7 * 86400000).toISOString()),
])
const todayUsage = (usageRes.data as Array<{ count: number }> | null)
?.reduce((sum, r) => sum + (r.count ?? 0), 0) ?? 0
return [
{ label: 'Total Users', value: profilesRes.count ?? 0, color: C.bright, glowClass: 'glow-white', borderColor: C.bright, badge: 'ALL TIME' },
{ label: 'Paid Subscribers', value: paidRes.count ?? 0, color: C.green400, glowClass: 'glow-green', borderColor: C.green, badge: 'ACTIVE' },
{ label: 'Today API Calls', value: todayUsage, color: C.orange, glowClass: 'glow-orange', borderColor: C.orange, badge: '24H VOL', badgeColor: C.orange400 },
{ label: 'Expiring (7D)', value: expiringRes.count ?? 0, color: C.red, glowClass: 'glow-red', borderColor: C.red, badge: 'WARNING' },
]
}
async function loadRecentAuditLogs(): Promise<Array<Record<string, unknown>>> {
const supabase = await getSupabaseServerClient()
const { data } = await supabase
.from('audit_log')
.select('*')
.order('created_at', { ascending: false })
.limit(10)
return (data ?? []) as Array<Record<string, unknown>>
}
function MiniBarChart({ value, maxVal, color }: { value: number; maxVal: number; color: string }): React.ReactElement {
const heights = [25, 50, 33, 75, maxVal > 0 ? Math.max(10, (value / Math.max(maxVal, 1)) * 100) : 5]
return (
<Box sx={{ display: 'flex', gap: '3px', alignItems: 'flex-end', height: 32 }}>
{heights.map((h, i) => (
<Box key={i} sx={{
width: 6,
height: `${h}%`,
bgcolor: i === 4 ? color : C.borderHl,
...(i === 4 ? { boxShadow: `0 0 8px ${color}80` } : {}),
}} />
))}
</Box>
)
}
export default async function AdminOverviewPage(): Promise<React.ReactElement> {
const stats = await loadStats()
const logs = await loadRecentAuditLogs()
const maxStatVal = Math.max(...stats.map((s) => s.value), 1)
const stats = await fetchServerStats()
const bentoCards = [
{
title: 'Annual Recurring Revenue (ARR)',
value: `$${stats.arrUsd.toLocaleString()}`,
subtext: `MRR: $${stats.mrrUsd.toLocaleString()} • +18.4% MoM Growth`,
color: 'purple' as const,
badge: 'REVENUE',
badgeColor: 'purple' as const,
icon: (
<svg width="22" height="22" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
),
},
{
title: 'Active Voice & Meeting Sessions',
value: `${stats.activeUsersToday.toLocaleString()} Active`,
subtext: `${stats.totalUsers.toLocaleString()} Total Users • 18 Realtime Streams`,
color: 'blue' as const,
badge: 'VOICE STREAMS',
badgeColor: 'blue' as const,
icon: (
<svg width="22" height="22" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 100-6 3 3 0 000 6z" />
</svg>
),
},
{
title: 'Total API Requests & Compute',
value: `${stats.totalRequests.toLocaleString()}`,
subtext: `Total Compute Cost: $${stats.totalCost.toFixed(4)}`,
color: 'green' as const,
badge: 'TELEMETRY',
badgeColor: 'green' as const,
icon: (
<svg width="22" height="22" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
),
},
{
title: 'Speaker Diarization Accuracy',
value: `${stats.pipelines.meetingIntelligence.speakerAccuracyPercent}%`,
subtext: `${stats.pipelines.meetingIntelligence.templatesGeneratedToday} Meeting Docs • 42 Mindmaps`,
color: 'orange' as const,
badge: 'PHASE 15.5',
badgeColor: 'orange' as const,
icon: (
<svg width="22" height="22" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
),
},
]
return (
<>
{/* Header bar */}
<Box sx={{
...panelSx,
height: 88, flexShrink: 0,
display: 'flex', alignItems: 'center',
px: 4, justifyContent: 'space-between',
}}>
<Box className="bg-grid" sx={{ position: 'absolute', inset: 0, opacity: 0.03, pointerEvents: 'none' }} />
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, position: 'relative', zIndex: 1 }}>
<Box sx={{ width: 4, height: 32, bgcolor: C.accent, borderRadius: 4 }} />
<Box
sx={{
...panelSx,
minHeight: 84,
px: { xs: 2.5, md: 4 },
py: 2,
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
justifyContent: 'space-between',
gap: 2,
}}
>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Box
sx={{
width: 4,
height: 32,
borderRadius: '999px',
background: 'linear-gradient(180deg, #06b6d4 0%, #3b82f6 50%, #8b5cf6 100%)',
}}
/>
<Box>
<Box component="h2" sx={{
fontFamily: FONT, fontSize: '20px', fontWeight: 300,
letterSpacing: '0.15em', textTransform: 'uppercase',
color: C.bright, m: 0,
}}>
Dashboard Overview
</Box>
<Box component="p" sx={{
fontFamily: FONT, fontSize: '12px',
letterSpacing: '0.15em', color: C.dim, mt: 0.5, m: 0,
}}>
REAL-TIME TELEMETRY
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
<Typography
component="h1"
sx={{
fontFamily: FONT_SANS,
fontSize: '20px',
fontWeight: 700,
color: C.bright,
letterSpacing: '-0.02em',
m: 0,
}}
>
Unified Dashboard Overview
</Typography>
<TactileBadge ledColor="green" ledPulse tone="success" mono>
ONLINE v0.2.1-alpha
</TactileBadge>
</Box>
<Typography
sx={{
fontFamily: FONT_MONO,
fontSize: '11px',
color: C.dim,
letterSpacing: '0.04em',
mt: 0.25,
}}
>
REALTIME AI TELEMETRY ARR & SUBSCRIPTION METRICS PIPELINE HEALTH
</Typography>
</Box>
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 3, position: 'relative', zIndex: 1 }}>
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
<Box component="span" sx={{ fontFamily: FONT, fontSize: '9px', letterSpacing: '0.2em', textTransform: 'uppercase', color: C.dim, mb: 0.5 }}>
Server Status
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Box component="span" sx={{ fontFamily: FONT, fontSize: '12px', fontWeight: 500, letterSpacing: '0.1em', color: C.green400 }}>
NOMINAL
</Box>
<svg width="12" height="12" fill="none" viewBox="0 0 24 24" stroke={C.green400}><path strokeLinecap="square" strokeWidth="2" d="M5 13l4 4L19 7" /></svg>
</Box>
</Box>
<Box sx={{ height: 32, width: '1px', bgcolor: C.borderHl }} />
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
<Box component="span" sx={{ fontFamily: FONT, fontSize: '9px', letterSpacing: '0.2em', textTransform: 'uppercase', color: C.dim, mb: 0.5 }}>
Region
</Box>
<Box component="span" sx={{ fontFamily: FONT, fontSize: '12px', fontWeight: 500, letterSpacing: '0.1em', color: C.bright }}>
AP-SEOUL
</Box>
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
<Link href="/pipelines" style={{ textDecoration: 'none' }}>
<Button
variant="outlined"
size="small"
sx={{
fontFamily: FONT_SANS,
fontSize: '12px',
color: C.bright,
borderColor: C.borderHl,
bgcolor: 'rgba(17, 26, 48, 0.6)',
borderRadius: '10px',
textTransform: 'none',
px: 2,
'&:hover': { borderColor: C.accentLight, bgcolor: 'rgba(26, 38, 68, 0.8)' },
}}
>
View Pipelines Console
</Button>
</Link>
</Box>
</Box>
{/* Main content */}
<Box sx={{ flex: 1, display: 'flex', gap: 2, overflow: 'hidden' }}>
{/* Left: Stats cards */}
<Box sx={{ width: 400, flexShrink: 0, display: 'flex', flexDirection: 'column', gap: 2, overflowY: 'auto', pr: 0.5 }}>
{stats.map((stat) => (
<Box key={stat.label} sx={panelSx}>
<Box sx={{ p: 3, position: 'relative', zIndex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'space-between', minHeight: 140 }}>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<Box component="h3" sx={{
fontFamily: FONT, fontSize: '10px', fontWeight: 400,
letterSpacing: '0.25em', textTransform: 'uppercase',
color: C.text, m: 0,
borderLeft: `2px solid ${stat.borderColor}`,
pl: 1,
}}>
{stat.label}
</Box>
<Box component="span" sx={{
fontFamily: FONT, fontSize: '10px',
color: stat.badgeColor ?? C.dim,
bgcolor: C.border,
px: 1, py: 0.5, borderRadius: '4px',
}}>
{stat.badge}
</Box>
</Box>
<Box sx={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', mt: 2 }}>
<MiniBarChart value={stat.value} maxVal={maxStatVal} color={stat.color} />
<Box
className={stat.glowClass}
component="span"
sx={{
fontFamily: FONT,
fontSize: '3.75rem',
fontWeight: 300,
lineHeight: 1,
color: stat.color,
letterSpacing: '-0.05em',
fontVariantNumeric: 'tabular-nums',
}}
>
{stat.value}
</Box>
{/* Main Content Area */}
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3.5 }}>
{/* Executive Bento Grid */}
<Box
sx={{
display: 'grid',
gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr', lg: 'repeat(4, 1fr)' },
gap: 2.5,
}}
>
{bentoCards.map((card) => (
<DoubleBezelCard
key={card.title}
interactive
bezelPadding="5px"
innerPadding="20px"
sx={{ height: '100%' }}
>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', mb: 2 }}>
<StatRing color={card.color} size={46}>
{card.icon}
</StatRing>
<Box component="span" sx={statusBadgeSx(card.badgeColor)}>
{card.badge}
</Box>
</Box>
</Box>
<Typography
sx={{
fontFamily: FONT_SANS,
fontSize: '11px',
fontWeight: 600,
color: C.dim,
textTransform: 'uppercase',
letterSpacing: '0.06em',
}}
>
{card.title}
</Typography>
<Typography
sx={{
fontFamily: FONT_MONO,
fontSize: '26px',
fontWeight: 700,
color: C.bright,
my: 0.75,
}}
>
{card.value}
</Typography>
<Typography
sx={{
fontFamily: FONT_SANS,
fontSize: '11px',
color: C.text,
}}
>
{card.subtext}
</Typography>
</DoubleBezelCard>
))}
</Box>
{/* Right: Activity Log */}
<Box sx={{ ...panelSx, flex: 1, display: 'flex', flexDirection: 'column', minHeight: 400 }}>
<Box className="bg-grid" sx={{ position: 'absolute', inset: 0, opacity: 0.02, pointerEvents: 'none' }} />
{/* Live System Nodes Grid */}
<DoubleBezelCard bezelPadding="6px" innerPadding="24px">
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2.5 }}>
<Box>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '16px', fontWeight: 700, color: C.bright }}>
System Nodes & Pipeline Topology
</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '11px', color: C.dim }}>
6 NODES HEALTHY ZERO SERVICE DEGRADATION DETECTED
</Typography>
</Box>
<TactileBadge tone="success" mono>
ALL OPERATIONAL
</TactileBadge>
</Box>
{/* Log header */}
<Box sx={{
px: 3, py: 2,
borderBottom: `1px solid ${C.border}`,
bgcolor: `${C.base}4D`,
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
position: 'relative', zIndex: 1,
}}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke={C.dim}><path strokeLinecap="square" strokeWidth="2" d="M4 6h16M4 12h16M4 18h7" /></svg>
<Box component="span" sx={{
fontFamily: FONT, fontSize: '12px', fontWeight: 500,
letterSpacing: '0.2em', textTransform: 'uppercase', color: C.bright,
}}>
System Activity Log
<Box
sx={{
display: 'grid',
gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, 1fr)', lg: 'repeat(3, 1fr)' },
gap: 2,
}}
>
{stats.nodes.map((node) => (
<Box
key={node.id}
sx={{
p: 2,
borderRadius: '14px',
bgcolor: 'rgba(10, 17, 31, 0.65)',
border: `1px solid ${C.border}`,
transition: 'all 0.2s ease',
'&:hover': {
borderColor: C.accentLight,
bgcolor: 'rgba(17, 26, 48, 0.8)',
transform: 'translateY(-2px)',
},
}}
>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', mb: 1 }}>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '13px', fontWeight: 700, color: C.bright }}>
{node.name}
</Typography>
<Box
sx={{
width: 8,
height: 8,
borderRadius: '50%',
bgcolor: '#10b981',
boxShadow: '0 0 8px #10b981',
}}
/>
</Box>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '11px', color: C.cyanLight, mb: 1.5 }}>
{node.versionOrModel}
</Typography>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', pt: 1, borderTop: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>
Latency: <strong style={{ color: C.bright }}>{node.latencyMs}ms</strong>
</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.green400 }}>
{node.uptimePercent}% Up
</Typography>
</Box>
</Box>
))}
</Box>
</DoubleBezelCard>
{/* Live Audio & Voice Intelligence Simulator Widget */}
<DashboardSimulator />
{/* Server Operational Telemetry Logs */}
<DoubleBezelCard bezelPadding="6px" innerPadding="24px">
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '15px', fontWeight: 700, color: C.bright }}>
Operational Telemetry & Server Logs
</Typography>
<TactileBadge tone="mono" mono>
AUTO REFRESH (30s)
</TactileBadge>
</Box>
<Box sx={{ overflowX: 'auto' }}>
<Box component="table" sx={tableSx}>
<Box component="thead">
<Box component="tr">
<Box component="th">ID</Box>
<Box component="th">STATUS</Box>
<Box component="th">MESSAGE</Box>
<Box component="th">ENDPOINT</Box>
<Box component="th">TIMESTAMP</Box>
</Box>
</Box>
<Box component="tbody">
{stats.recentErrors.length === 0 ? (
<Box component="tr">
<Box component="td" colSpan={5} sx={{ textAlign: 'center', color: C.green400, py: 3 }}>
NO OPERATIONAL ERRORS ALL C# .NET API NODES HEALTHY (100% SUCCESS RATE)
</Box>
</Box>
) : (
stats.recentErrors.map((err) => (
<Box component="tr" key={err.id}>
<Box component="td">#{err.id}</Box>
<Box component="td">
<Box component="span" sx={statusBadgeSx('red')}>
{err.errorType}
</Box>
</Box>
<Box component="td">{err.message}</Box>
<Box component="td" sx={{ fontFamily: FONT_MONO, fontSize: '11px' }}>
{err.endpoint || '-'}
</Box>
<Box component="td" sx={{ color: C.dim }}>
{new Date(err.createdAt).toLocaleString()}
</Box>
</Box>
))
)}
</Box>
</Box>
<Box sx={{ display: 'flex', gap: 1 }}>
<Link href="/audit-log" style={{ textDecoration: 'none' }}>
<Box component="span" sx={{
fontFamily: FONT, fontSize: '10px', fontWeight: 500,
letterSpacing: '0.1em', textTransform: 'uppercase',
px: 1.5, py: 0.5, borderRadius: '4px',
bgcolor: C.borderHl, color: C.bright,
cursor: 'pointer',
'&:hover': { bgcolor: C.dim },
transition: 'background 0.15s',
}}>
View All
</Box>
</Link>
</Box>
</Box>
{/* Log table */}
<Box sx={{ flex: 1, overflow: 'auto', p: 3, position: 'relative', zIndex: 1 }}>
<Box component="table" sx={tableSx}>
<thead>
<tr>
<th style={{ width: 140 }}>Timestamp</th>
<th style={{ width: 120 }}>Action</th>
<th style={{ width: 100 }}>Target</th>
<th>Memo</th>
</tr>
</thead>
<tbody>
{logs.length === 0 ? (
<tr>
<td colSpan={4} style={{ textAlign: 'center', color: C.dim, padding: '32px 0' }}>
No activity records yet
</td>
</tr>
) : (
logs.map((log) => {
const action = log.action as string
const actionColor = action.includes('delete') ? C.red400
: action.includes('create') ? C.green400
: action.includes('role') ? C.purple400
: C.orange400
return (
<tr key={log.id as number}>
<td style={{ color: C.dim, whiteSpace: 'nowrap' }}>
{new Date(log.created_at as string).toLocaleTimeString()}
</td>
<td style={{ color: actionColor }}>
{action.toUpperCase().replace('.', '_')}
</td>
<td>{(log.target_type as string).toUpperCase()}</td>
<td style={{ color: C.dim }}>
{((log.memo as string) ?? '').substring(0, 60)}
</td>
</tr>
)
})
)}
</tbody>
</Box>
</Box>
</Box>
</DoubleBezelCard>
</Box>
</>
)