"use client";
import { useRef, useState } from "react";
import { NextIntlClientProvider } from "next-intl";
import {
Bot,
Check,
Copy,
Database,
FileCheck2,
KeyRound,
LockKeyhole,
RefreshCcw,
ShieldCheck,
UserRound,
WalletCards,
Webhook,
} from "lucide-react";
import {
Avatar,
Badge,
Button,
Progress,
ToastProvider,
cn,
} from "@reopt-ai/opt-ui";
import { useExampleAction } from "@/components/examples/use-example-action";
import type { BrandappExampleDemoProps } from "./sign-in-with-reopt-button-demo";
type PanelId = "overview" | "auth" | "eav" | "ai" | "terms" | "webhooks";
type SyncState = "idle" | "syncing" | "complete";
type DoctorState = "idle" | "running" | "passed";
type VerifierState = "idle" | "running" | "passed";
type TermsState = "draft" | "publishing" | "published";
type SecretState = "due" | "rotating" | "rotated";
type DriftState = "pending" | "resolving" | "resolved";
type CreditGuardState = "open" | "locking" | "locked";
type WebhookReplayState = "failed" | "replaying" | "delivered";
interface ControlMetric {
label: string;
value: string;
detail: string;
tone: "info" | "success" | "warning";
icon: React.ReactNode;
}
interface AuditLogItem {
id: string;
label: string;
detail: string;
tone: "info" | "success" | "warning";
}
const AUDIT_TONE_LABEL: Record<AuditLogItem["tone"], string> = {
success: "ok",
warning: "check",
info: "info",
};
const AUDIT_LOG_VISIBLE_LIMIT = 3;
const PANELS: Array<{
id: PanelId;
label: string;
icon: React.ReactNode;
}> = [
{ id: "overview", label: "Overview", icon: <ShieldCheck /> },
{ id: "auth", label: "Auth", icon: <KeyRound /> },
{ id: "eav", label: "EAV", icon: <Database /> },
{ id: "ai", label: "AI", icon: <Bot /> },
{ id: "terms", label: "Terms", icon: <FileCheck2 /> },
{ id: "webhooks", label: "Webhooks", icon: <Webhook /> },
];
const AI_MODEL_ROUTES = [
{ model: "claude-sonnet-4.5", label: "agent" },
{ model: "claude-haiku-4.5", label: "draft" },
{ model: "glm-4.7-flash", label: "fast" },
] as const;
const METRICS: ControlMetric[] = [
{
label: "OAuth sessions",
value: "1,248",
detail: "99.98% success",
tone: "success",
icon: <UserRound className="size-4" aria-hidden />,
},
{
label: "EAV entities",
value: "18",
detail: "3 synced today",
tone: "info",
icon: <Database className="size-4" aria-hidden />,
},
{
label: "AI credits",
value: "8,420",
detail: "of 10,000 left",
tone: "warning",
icon: <WalletCards className="size-4" aria-hidden />,
},
{
label: "Published terms",
value: "3/4",
detail: "refund policy draft",
tone: "warning",
icon: <FileCheck2 className="size-4" aria-hidden />,
},
];
const INITIAL_AUDIT_LOG: AuditLogItem[] = [
{
id: "audit-sync",
label: "SDK sync completed",
detail: "EAV, terms, auth, and AI clients checked 48 seconds ago",
tone: "success",
},
{
id: "audit-drift",
label: "Schema drift detected",
detail: "2 optional EAV attrs need owner review",
tone: "warning",
},
];
const SDK_ROUTE_SNIPPET = `// lib/brandapp-sdk.ts
import { createReoptEavClient } from "@reopt-ai/brandapp-sdk/eav";
import { createReoptTermsClient } from "@reopt-ai/brandapp-sdk/terms";
type BrandappClients = {
eav: ReturnType<typeof createReoptEavClient>;
terms: ReturnType<typeof createReoptTermsClient>;
};
let cachedClients: BrandappClients | undefined;
function readConfig() {
return {
clientId: process.env.BRANDAPP_CLIENT_ID!,
clientSecret: process.env.BRANDAPP_CLIENT_SECRET!,
brandappId: process.env.BRANDAPP_ID!,
baseUrl: process.env.REOPT_BASE_URL,
};
}
export function getBrandappClients() {
if (!cachedClients) {
const config = readConfig();
cachedClients = {
eav: createReoptEavClient(config),
terms: createReoptTermsClient(config),
};
}
return cachedClients;
}`;
function PanelButton({
id,
label,
icon,
active,
onSelect,
}: {
id: PanelId;
label: string;
icon: React.ReactNode;
active: boolean;
onSelect: (panel: PanelId) => void;
}) {
return (
<button
type="button"
aria-pressed={active}
onClick={() => onSelect(id)}
className={cn(
"flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm transition-colors",
active
? "bg-accent text-accent-fg"
: "text-text-secondary hover:bg-bg-subtle hover:text-text-primary",
)}
>
<span className="[&_svg]:size-4">{icon}</span>
{label}
</button>
);
}
function MetricCard({ metric }: { metric: ControlMetric }) {
return (
<div className="border-border bg-surface rounded-lg border p-4">
<div className="flex items-center justify-between">
<span className="text-text-tertiary">{metric.icon}</span>
<Badge variant={metric.tone} size="sm">
live
</Badge>
</div>
<p className="text-text-primary mt-3 text-2xl font-semibold">
{metric.value}
</p>
<p className="text-text-secondary text-sm">{metric.label}</p>
<p className="text-text-tertiary mt-1 text-xs">{metric.detail}</p>
</div>
);
}
function StatusRow({
label,
value,
detail,
tone = "success",
}: {
label: string;
value: string;
detail: string;
tone?: "success" | "info" | "warning";
}) {
return (
<div className="border-border-subtle bg-surface flex items-center justify-between gap-4 rounded-lg border px-3 py-2">
<div className="min-w-0">
<p className="text-text-primary truncate text-sm font-medium">
{label}
</p>
<p className="text-text-tertiary truncate text-xs">{detail}</p>
</div>
<Badge variant={tone} size="sm" dot>
{value}
</Badge>
</div>
);
}
function PanelContent({
activePanel,
metrics,
schemaDriftCount,
driftState,
creditGuardState,
secretState,
termsState,
webhookReplayState,
onResolveSchemaDrift,
onEnableCreditGuard,
onRotateSecret,
onPublishTerms,
onReplayWebhook,
}: {
activePanel: PanelId;
metrics: ControlMetric[];
schemaDriftCount: number;
driftState: DriftState;
creditGuardState: CreditGuardState;
secretState: SecretState;
termsState: TermsState;
webhookReplayState: WebhookReplayState;
onResolveSchemaDrift: () => void;
onEnableCreditGuard: () => void;
onRotateSecret: () => void;
onPublishTerms: () => void;
onReplayWebhook: () => void;
}) {
if (activePanel === "auth") {
return (
<div className="grid gap-4 lg:grid-cols-[1fr_280px]">
<div className="grid gap-3 lg:grid-cols-2">
<StatusRow
label="Better Auth client"
value="ready"
detail="@/lib/auth-client configured"
/>
<StatusRow
label="OAuth callback"
value="ready"
detail="/api/auth/callback/reopt"
/>
<StatusRow
label="Session refresh"
value="healthy"
detail="last refresh 48 seconds ago"
/>
<StatusRow
label="OAuth client secret"
value={
secretState === "rotating"
? "rotating"
: secretState === "rotated"
? "current"
: "due"
}
detail={
secretState === "rotated"
? "rotated just now; old key expires in 24 hours"
: secretState === "rotating"
? "minting replacement server secret"
: "secret expires in 7 days"
}
tone={secretState === "rotated" ? "success" : "warning"}
/>
<StatusRow
label="Secret exposure"
value="server"
detail="clientSecret never leaves route handlers"
tone="info"
/>
</div>
<div className="border-border bg-surface rounded-lg border p-4">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-text-primary text-sm font-semibold">
Credential rotation
</p>
<p className="text-text-tertiary mt-1 text-xs">
Mint a replacement OAuth secret without exposing it to the
client bundle.
</p>
</div>
<Badge
variant={secretState === "rotated" ? "success" : "warning"}
size="sm"
dot
>
{secretState === "rotated" ? "current" : "due"}
</Badge>
</div>
<div className="mt-3 grid gap-2 text-xs">
<div className="border-border-subtle rounded-lg border px-3 py-2">
<p className="text-text-primary font-medium">
BRANDAPP_CLIENT_SECRET
</p>
<p className="text-text-tertiary mt-1">
stored server-side only · masked in diagnostics
</p>
</div>
<div className="border-border-subtle rounded-lg border px-3 py-2">
<p className="text-text-primary font-medium">Rotation window</p>
<p className="text-text-tertiary mt-1">
{secretState === "rotated"
? "new secret active; old secret expires in 24 hours"
: "dual-secret rollout is ready"}
</p>
</div>
</div>
<Button
size="sm"
className="mt-4"
leftIcon={
<KeyRound
className={cn(
"size-4",
secretState === "rotating" && "animate-pulse",
)}
aria-hidden
/>
}
disabled={secretState !== "due"}
onClick={onRotateSecret}
>
{secretState === "rotating"
? "Rotating"
: secretState === "rotated"
? "Rotated"
: "Rotate secret"}
</Button>
</div>
</div>
);
}
if (activePanel === "eav") {
return (
<div className="grid gap-4 lg:grid-cols-[1fr_280px]">
<div className="grid gap-3 lg:grid-cols-2">
<StatusRow
label="customers"
value="synced"
detail="12 attributes · 24,130 records"
/>
<StatusRow
label="campaigns"
value="synced"
detail="9 attributes · 318 records"
/>
<StatusRow
label="notes"
value="mapped"
detail="EditorSpec stored as JSON values"
tone="info"
/>
<StatusRow
label="schema drift"
value={schemaDriftCount > 0 ? "watch" : "clear"}
detail={
schemaDriftCount > 0
? `${schemaDriftCount} optional attrs detected`
: "local file map matches BrandApp console"
}
tone={schemaDriftCount > 0 ? "warning" : "success"}
/>
</div>
<div className="border-border bg-surface rounded-lg border p-4">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-text-primary text-sm font-semibold">
Schema remediation
</p>
<p className="text-text-tertiary mt-1 text-xs">
Map optional EAV attributes into the local file and warm the SDK
cache.
</p>
</div>
<Badge
variant={schemaDriftCount > 0 ? "warning" : "success"}
size="sm"
dot
>
{schemaDriftCount > 0 ? `${schemaDriftCount} attrs` : "clear"}
</Badge>
</div>
<div className="border-border-subtle my-3 rounded-lg border px-3 py-2 text-xs">
<p className="text-text-primary font-medium">Local EAV file</p>
<p className="text-text-tertiary mt-1">
{schemaDriftCount > 0
? "optional loyalty_tier and consent_source attrs pending"
: "local file map matches the BrandApp console"}
</p>
</div>
<Button
size="sm"
leftIcon={
<Database
className={cn(
"size-4",
driftState === "resolving" && "animate-pulse",
)}
aria-hidden
/>
}
disabled={schemaDriftCount === 0 || driftState === "resolving"}
onClick={onResolveSchemaDrift}
>
{driftState === "resolving"
? "Resolving"
: schemaDriftCount === 0
? "Resolved"
: "Resolve drift"}
</Button>
</div>
</div>
);
}
if (activePanel === "ai") {
return (
<div className="grid gap-4 lg:grid-cols-[1fr_300px]">
<div className="border-border bg-surface rounded-lg border p-4">
<div className="flex items-center justify-between">
<p className="text-text-primary text-sm font-semibold">
Model routing
</p>
<Badge variant="success" size="sm">
enabled
</Badge>
</div>
<div className="mt-4 grid gap-3 md:grid-cols-3">
{AI_MODEL_ROUTES.map(({ model, label }) => (
<div
key={model}
className="border-border-subtle rounded-lg border px-3 py-2"
>
<p className="text-text-primary truncate text-sm font-medium">
{model}
</p>
<p className="text-text-tertiary text-xs">{label}</p>
</div>
))}
</div>
</div>
<div className="border-border bg-surface rounded-lg border p-4">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-text-primary text-sm font-semibold">
Credit guard
</p>
<p className="text-text-tertiary mt-1 text-xs">
Require approval before high-cost image or long reasoning runs.
</p>
</div>
<Badge
variant={creditGuardState === "locked" ? "success" : "warning"}
size="sm"
dot
>
{creditGuardState === "locking"
? "locking"
: creditGuardState === "locked"
? "guarded"
: "watch"}
</Badge>
</div>
<Progress
value={84}
label="Credit balance"
showLabel
variant="warning"
className="mt-4"
/>
<p className="text-text-tertiary mt-3 text-xs">
{creditGuardState === "locked"
? "High-cost model routes now require approval above 80% usage."
: creditGuardState === "locking"
? "Writing the guard policy to the BrandApp AI route map."
: "Alerts trigger before agent tools consume high-cost image or reasoning runs."}
</p>
<Button
size="sm"
className="mt-4"
leftIcon={
<WalletCards
className={cn(
"size-4",
creditGuardState === "locking" && "animate-pulse",
)}
aria-hidden
/>
}
disabled={creditGuardState !== "open"}
onClick={onEnableCreditGuard}
>
{creditGuardState === "locking"
? "Locking"
: creditGuardState === "locked"
? "Guard enabled"
: "Enable guard"}
</Button>
</div>
</div>
);
}
if (activePanel === "terms") {
return (
<div className="grid gap-4 lg:grid-cols-[1fr_280px]">
<div className="grid gap-3 lg:grid-cols-2">
<StatusRow
label="Terms of service"
value="published"
detail="version 4 · current"
/>
<StatusRow
label="Privacy policy"
value="published"
detail="version 7 · current"
/>
<StatusRow
label="Refund policy"
value={
termsState === "publishing"
? "publishing"
: termsState === "published"
? "published"
: "draft"
}
detail={
termsState === "publishing"
? "publishing version 3 through BrandApp terms"
: termsState === "published"
? "version 3 · published just now"
: "legal review due tomorrow"
}
tone={termsState === "published" ? "success" : "warning"}
/>
<StatusRow
label="Cookie notice"
value="published"
detail="version 2 · current"
/>
</div>
<div className="border-border bg-surface rounded-lg border p-4">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-text-primary text-sm font-semibold">
Terms release
</p>
<p className="text-text-tertiary mt-1 text-xs">
Refund policy publishes through the lazy BrandApp terms client.
</p>
</div>
<Badge
variant={termsState === "published" ? "success" : "warning"}
size="sm"
dot
>
{termsState === "published" ? "current" : "draft"}
</Badge>
</div>
<Button
size="sm"
className="mt-4"
leftIcon={
<FileCheck2
className={cn(
"size-4",
termsState === "publishing" && "animate-pulse",
)}
aria-hidden
/>
}
disabled={termsState !== "draft"}
onClick={onPublishTerms}
>
{termsState === "publishing"
? "Publishing"
: termsState === "published"
? "Published"
: "Publish refund"}
</Button>
</div>
</div>
);
}
if (activePanel === "webhooks") {
return (
<div className="grid gap-4 lg:grid-cols-[1fr_300px]">
<div className="grid gap-3 lg:grid-cols-2">
<StatusRow
label="terms.published"
value={
webhookReplayState === "delivered"
? "delivered"
: webhookReplayState === "replaying"
? "replaying"
: "failed"
}
detail={
webhookReplayState === "delivered"
? "replayed with preserved event id"
: webhookReplayState === "replaying"
? "retrying with preserved event id"
: "last attempt timed out at customer endpoint"
}
tone={webhookReplayState === "delivered" ? "success" : "warning"}
/>
<StatusRow
label="eav.schema.changed"
value="delivered"
detail="customer sync endpoint acknowledged"
/>
<StatusRow
label="ai.credit.threshold"
value="queued"
detail="waits for credit guard policy publish"
tone="info"
/>
<StatusRow
label="Webhook signing"
value="verified"
detail="HMAC key stored server-side only"
/>
</div>
<div className="border-border bg-surface rounded-lg border p-4">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-text-primary text-sm font-semibold">
Webhook replay
</p>
<p className="text-text-tertiary mt-1 text-xs">
Re-send failed BrandApp events with the original idempotency
key.
</p>
</div>
<Badge
variant={
webhookReplayState === "delivered" ? "success" : "warning"
}
size="sm"
dot
>
{webhookReplayState === "replaying"
? "replaying"
: webhookReplayState === "delivered"
? "delivered"
: "failed"}
</Badge>
</div>
<div className="border-border-subtle my-3 rounded-lg border px-3 py-2 text-xs">
<p className="text-text-primary font-medium">terms.published</p>
<p className="text-text-tertiary mt-1">
webhook evt_terms_7f4 · endpoint /api/brandapp/webhooks
</p>
</div>
<Button
size="sm"
leftIcon={
<Webhook
className={cn(
"size-4",
webhookReplayState === "replaying" && "animate-pulse",
)}
aria-hidden
/>
}
disabled={webhookReplayState !== "failed"}
onClick={onReplayWebhook}
>
{webhookReplayState === "replaying"
? "Replaying"
: webhookReplayState === "delivered"
? "Delivered"
: "Replay webhook"}
</Button>
</div>
</div>
);
}
return (
<div className="grid gap-4 lg:grid-cols-4">
{metrics.map((metric) => (
<MetricCard key={metric.label} metric={metric} />
))}
</div>
);
}
function getVerifierCopy(state: VerifierState) {
switch (state) {
case "running":
return {
value: "running",
detail: "checking env, OAuth, clients, and webhook signing",
tone: "warning" as const,
buttonLabel: "Verifying",
};
case "passed":
return {
value: "passed",
detail: "server SDK contract verified just now",
tone: "success" as const,
buttonLabel: "Verified",
};
default:
return {
value: "ready",
detail: "verifies server-only config before release",
tone: "info" as const,
buttonLabel: "Verify SDK",
};
}
}
export function BrandappControlCenterDemo(props: BrandappExampleDemoProps) {
return (
<NextIntlClientProvider locale="ko" messages={{}}>
<ToastProvider position="bottom-right">
<BrandappControlCenterDemoInner {...props} />
</ToastProvider>
</NextIntlClientProvider>
);
}
function BrandappControlCenterDemoInner({
compact = false,
}: BrandappExampleDemoProps) {
const { notReal } = useExampleAction();
const [activePanel, setActivePanel] = useState<PanelId>("overview");
const [contractCopied, setContractCopied] = useState(false);
const [syncState, setSyncState] = useState<SyncState>("idle");
const [doctorState, setDoctorState] = useState<DoctorState>("idle");
const [verifierState, setVerifierState] = useState<VerifierState>("idle");
const [lastSyncLabel, setLastSyncLabel] = useState("48 seconds ago");
const [syncedToday, setSyncedToday] = useState(3);
const [schemaDriftCount, setSchemaDriftCount] = useState(2);
const [driftState, setDriftState] = useState<DriftState>("pending");
const [creditGuardState, setCreditGuardState] =
useState<CreditGuardState>("open");
const [termsState, setTermsState] = useState<TermsState>("draft");
const [secretState, setSecretState] = useState<SecretState>("due");
const [webhookReplayState, setWebhookReplayState] =
useState<WebhookReplayState>("failed");
const [auditLog, setAuditLog] = useState<AuditLogItem[]>(INITIAL_AUDIT_LOG);
const nextAuditLogIdRef = useRef(INITIAL_AUDIT_LOG.length + 1);
const verifierCopy = getVerifierCopy(verifierState);
const metrics: ControlMetric[] = METRICS.map((metric): ControlMetric => {
if (metric.label === "OAuth sessions") {
return {
...metric,
detail:
secretState === "rotated"
? "99.98% success · key rotated"
: "99.98% success · secret due",
tone: secretState === "rotated" ? "success" : "warning",
};
}
if (metric.label === "EAV entities") {
return {
...metric,
detail: `${syncedToday} synced today`,
};
}
if (metric.label === "Published terms") {
return {
...metric,
value: termsState === "published" ? "4/4" : "3/4",
detail:
termsState === "published"
? "all policies current"
: "refund policy draft",
tone: termsState === "published" ? "success" : "warning",
};
}
if (metric.label === "AI credits") {
return {
...metric,
detail:
creditGuardState === "locked"
? "guard enabled · 8,420 left"
: "of 10,000 left",
tone: creditGuardState === "locked" ? "success" : "warning",
};
}
return metric;
});
const handleSync = () => {
if (syncState === "syncing") return;
notReal("Sync");
setSyncState("syncing");
setActivePanel("overview");
window.setTimeout(() => {
setSyncState("complete");
setLastSyncLabel("just now");
setSyncedToday((current) => current + 1);
setAuditLog((current) => [
{
id: `audit-${nextAuditLogIdRef.current++}`,
label: "Manual SDK sync",
detail: "All BrandApp clients refreshed just now",
tone: "success",
},
...current,
]);
}, 700);
};
const handleRunDoctor = () => {
if (doctorState === "running") return;
notReal("Run doctor");
setDoctorState("running");
setActivePanel("eav");
window.setTimeout(() => {
setDoctorState("passed");
setSchemaDriftCount(0);
setDriftState("resolved");
setAuditLog((current) => [
{
id: `audit-${nextAuditLogIdRef.current++}`,
label: "BrandApp doctor passed",
detail:
"Auth callback, EAV schema, AI routing, and terms fallbacks verified just now",
tone: "success",
},
...current,
]);
}, 900);
};
const handleRunSdkVerifier = () => {
if (verifierState !== "idle") return;
notReal("Verify SDK");
setVerifierState("running");
setActivePanel("overview");
window.setTimeout(() => {
setVerifierState("passed");
setAuditLog((current) => [
{
id: `audit-${nextAuditLogIdRef.current++}`,
label: "SDK verifier passed",
detail:
"Env vars, OAuth redirect, EAV client, terms client, AI provider, and webhook signature verified",
tone: "success",
},
...current,
]);
}, 800);
};
const handlePublishTerms = () => {
if (termsState !== "draft") return;
notReal("Publish refund");
setTermsState("publishing");
setActivePanel("terms");
window.setTimeout(() => {
setTermsState("published");
setAuditLog((current) => [
{
id: `audit-${nextAuditLogIdRef.current++}`,
label: "Refund terms published",
detail: "Version 3 is live through the BrandApp terms client",
tone: "success",
},
...current,
]);
}, 800);
};
const handleResolveSchemaDrift = () => {
if (schemaDriftCount === 0 || driftState === "resolving") return;
notReal("Resolve drift");
const resolvedCount = schemaDriftCount;
setDriftState("resolving");
setActivePanel("eav");
window.setTimeout(() => {
setDriftState("resolved");
setSchemaDriftCount(0);
setSyncedToday((current) => current + 1);
setAuditLog((current) => [
{
id: `audit-${nextAuditLogIdRef.current++}`,
label: "Schema drift resolved",
detail: `${resolvedCount} optional attrs mapped to the local EAV file`,
tone: "success",
},
...current,
]);
}, 750);
};
const handleEnableCreditGuard = () => {
if (creditGuardState !== "open") return;
notReal("Enable budget guard");
setCreditGuardState("locking");
setActivePanel("ai");
window.setTimeout(() => {
setCreditGuardState("locked");
setAuditLog((current) => [
{
id: `audit-${nextAuditLogIdRef.current++}`,
label: "AI budget guard enabled",
detail:
"High-cost image and reasoning routes now require approval above 80% usage",
tone: "success",
},
...current,
]);
}, 750);
};
const handleRotateSecret = () => {
if (secretState !== "due") return;
notReal("Rotate secret");
setSecretState("rotating");
setActivePanel("auth");
window.setTimeout(() => {
setSecretState("rotated");
setAuditLog((current) => [
{
id: `audit-${nextAuditLogIdRef.current++}`,
label: "OAuth secret rotated",
detail:
"New server secret minted; old key expires in 24 hours with no client exposure",
tone: "success",
},
...current,
]);
}, 850);
};
const handleReplayWebhook = () => {
if (webhookReplayState !== "failed") return;
notReal("Replay webhook");
setWebhookReplayState("replaying");
setActivePanel("webhooks");
window.setTimeout(() => {
setWebhookReplayState("delivered");
setAuditLog((current) => [
{
id: `audit-${nextAuditLogIdRef.current++}`,
label: "Webhook replay delivered",
detail:
"terms.published replayed to /api/brandapp/webhooks with idempotency key evt_terms_7f4",
tone: "success",
},
...current,
]);
}, 800);
};
if (compact) {
return (
<div className="bg-surface border-border flex h-full w-full flex-col overflow-hidden rounded-lg border">
<div className="border-border-subtle flex items-center justify-between border-b px-3 py-2">
<div className="flex items-center gap-2">
<LockKeyhole className="text-text-tertiary size-4" aria-hidden />
<span className="text-text-primary text-sm font-semibold">
BrandApp Control
</span>
</div>
<Badge variant="success" size="sm">
healthy
</Badge>
</div>
<div className="grid grid-cols-2 gap-2 p-3">
{metrics.slice(0, 4).map((metric) => (
<div
key={metric.label}
className="border-border-subtle bg-bg-subtle rounded-lg border p-2"
>
<p className="text-text-primary text-base font-semibold">
{metric.value}
</p>
<p className="text-text-tertiary truncate text-xs">
{metric.label}
</p>
</div>
))}
</div>
<div className="border-border-subtle bg-bg-subtle mx-3 mb-3 rounded-lg border p-2">
<div className="flex items-center justify-between gap-2">
<span className="text-text-primary text-xs font-medium">
SDK verifier
</span>
<Badge variant={verifierCopy.tone} size="sm" dot>
{verifierCopy.value}
</Badge>
</div>
<p className="text-text-tertiary mt-1 text-xs">
server-only clients · webhooks · terms
</p>
</div>
</div>
);
}
return (
<div className="bg-surface border-border flex min-h-[640px] w-full overflow-hidden rounded-lg border shadow-sm">
<aside className="border-border-subtle bg-bg-subtle/60 hidden w-64 shrink-0 flex-col border-r lg:flex">
<div className="border-border-subtle border-b p-4">
<div className="flex items-center gap-3">
<div className="bg-accent text-accent-fg flex size-9 items-center justify-center rounded-lg">
<LockKeyhole className="size-4" aria-hidden />
</div>
<div className="min-w-0">
<p className="text-text-primary truncate text-sm font-semibold">
BrandApp Control
</p>
<p className="text-text-tertiary text-xs">SDK operations</p>
</div>
</div>
</div>
<nav className="flex flex-col gap-1 p-3" aria-label="SDK panels">
{PANELS.map((panel) => (
<PanelButton
key={panel.id}
{...panel}
active={panel.id === activePanel}
onSelect={setActivePanel}
/>
))}
</nav>
<div className="mt-auto p-4">
<div className="border-border bg-surface rounded-lg border p-3">
<div className="flex items-center justify-between">
<p className="text-text-primary text-xs font-medium">
Environment
</p>
<Badge variant="success" size="sm" dot>
{syncState === "syncing" ? "syncing" : "preview"}
</Badge>
</div>
<p className="text-text-tertiary mt-2 text-xs">
Last SDK check {lastSyncLabel}. Secrets stay in route handlers.
</p>
</div>
</div>
</aside>
<main className="flex min-w-0 flex-1 flex-col">
<header className="border-border-subtle flex flex-wrap items-center justify-between gap-3 border-b px-5 py-3">
<div>
<div className="flex items-center gap-2">
<Badge variant="success" dot>
connected
</Badge>
<span className="text-text-tertiary text-xs">
brandapp_8f2c...21ad · synced {lastSyncLabel}
</span>
</div>
<h2 className="text-text-primary mt-1 text-lg font-semibold">
SDK-backed admin center
</h2>
</div>
<div className="flex items-center gap-2">
<Avatar name="Eric Han" size="sm" status="online" />
<Button
size="sm"
variant="secondary"
leftIcon={<ShieldCheck className="size-4" aria-hidden />}
disabled={doctorState === "running"}
onClick={handleRunDoctor}
>
{doctorState === "running" ? "Checking" : "Run doctor"}
</Button>
<Button
size="sm"
variant="secondary"
leftIcon={
<RefreshCcw
className={cn(
"size-4",
syncState === "syncing" && "animate-spin",
)}
aria-hidden
/>
}
disabled={syncState === "syncing"}
onClick={handleSync}
>
{syncState === "syncing" ? "Syncing" : "Sync"}
</Button>
</div>
</header>
<div className="border-border-subtle border-b px-5 py-3 lg:hidden">
<select
aria-label="Select SDK panel"
value={activePanel}
onChange={(event) => setActivePanel(event.target.value as PanelId)}
className="border-border bg-surface text-text-primary focus-visible:ring-ring h-9 w-full rounded-lg border px-3 text-sm outline-none focus-visible:ring-2"
>
{PANELS.map((panel) => (
<option key={panel.id} value={panel.id}>
{panel.label}
</option>
))}
</select>
</div>
<div className="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto p-5">
<PanelContent
activePanel={activePanel}
metrics={metrics}
schemaDriftCount={schemaDriftCount}
driftState={driftState}
creditGuardState={creditGuardState}
secretState={secretState}
termsState={termsState}
webhookReplayState={webhookReplayState}
onResolveSchemaDrift={handleResolveSchemaDrift}
onEnableCreditGuard={handleEnableCreditGuard}
onRotateSecret={handleRotateSecret}
onPublishTerms={handlePublishTerms}
onReplayWebhook={handleReplayWebhook}
/>
<div className="grid gap-4 xl:grid-cols-[minmax(0,1fr)_360px]">
<section className="border-border bg-surface rounded-lg border p-4">
<div className="flex items-center justify-between gap-2">
<p className="text-text-primary text-sm font-semibold">
Runtime contract
</p>
<div className="flex items-center gap-2">
<Badge variant="info" size="sm">
lazy clients
</Badge>
<button
type="button"
onClick={() => {
setContractCopied(true);
window.setTimeout(() => setContractCopied(false), 1500);
void navigator.clipboard
?.writeText(SDK_ROUTE_SNIPPET)
.catch(() => {});
}}
className="text-text-secondary border-border-subtle hover:bg-bg-subtle hover:text-text-primary focus-visible:ring-ring inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none"
aria-label="런타임 계약 코드 복사"
>
{contractCopied ? (
<>
<Check className="size-3.5" aria-hidden />
Copied
</>
) : (
<>
<Copy className="size-3.5" aria-hidden />
Copy
</>
)}
</button>
</div>
</div>
<pre className="text-text-primary border-border-subtle bg-bg-subtle mt-4 max-h-80 overflow-auto rounded-lg border p-3 text-xs leading-5">
<code>{SDK_ROUTE_SNIPPET}</code>
</pre>
</section>
<section className="border-border bg-surface flex flex-col gap-3 rounded-lg border p-4">
<p className="text-text-primary text-sm font-semibold">
Health checks
</p>
<StatusRow
label="SDK verifier"
value={verifierCopy.value}
detail={verifierCopy.detail}
tone={verifierCopy.tone}
/>
<StatusRow
label="AI provider"
value="streaming"
detail="Vercel AI SDK UIMessage stream"
/>
<StatusRow
label="AI budget guard"
value={
creditGuardState === "locking"
? "locking"
: creditGuardState === "locked"
? "guarded"
: "watch"
}
detail={
creditGuardState === "locked"
? "high-cost model routes require approval"
: creditGuardState === "locking"
? "writing BrandApp AI route policy"
: "enable before image or long reasoning runs"
}
tone={creditGuardState === "locked" ? "success" : "warning"}
/>
<StatusRow
label="Webhook delivery"
value={
webhookReplayState === "replaying"
? "replaying"
: webhookReplayState === "delivered"
? "delivered"
: "failed"
}
detail={
webhookReplayState === "delivered"
? "terms.published replay delivered"
: webhookReplayState === "replaying"
? "retrying failed BrandApp webhook"
: "terms.published failed at customer endpoint"
}
tone={
webhookReplayState === "delivered" ? "success" : "warning"
}
/>
<StatusRow
label="EAV schema"
value={schemaDriftCount > 0 ? "watch" : "valid"}
detail={
schemaDriftCount > 0
? `${schemaDriftCount} optional attrs need review`
: `local hash matches console · ${lastSyncLabel}`
}
tone={schemaDriftCount > 0 ? "warning" : "success"}
/>
<StatusRow
label="Terms fallback"
value={termsState === "published" ? "current" : "review"}
detail={
termsState === "published"
? "refund policy published through BrandApp terms"
: "refund draft falls back to i18n copy"
}
tone={termsState === "published" ? "success" : "warning"}
/>
<StatusRow
label="Auth session"
value="fresh"
detail="expires in 58 minutes"
/>
<StatusRow
label="OAuth secret"
value={
secretState === "rotating"
? "rotating"
: secretState === "rotated"
? "current"
: "due"
}
detail={
secretState === "rotated"
? "rotated just now; old key expires in 24 hours"
: secretState === "rotating"
? "minting replacement OAuth client secret"
: "rotation due within 7 days"
}
tone={secretState === "rotated" ? "success" : "warning"}
/>
<StatusRow
label="SDK client cache"
value={syncState === "complete" ? "warm" : "ready"}
detail="route handlers reuse server clients"
tone="info"
/>
<StatusRow
label="BrandApp doctor"
value={
doctorState === "running"
? "checking"
: doctorState === "passed"
? "passed"
: "ready"
}
detail={
doctorState === "running"
? "checking auth, schema, terms, and AI"
: doctorState === "passed"
? "last doctor completed just now"
: "run before publishing config changes"
}
tone={
doctorState === "running"
? "warning"
: doctorState === "passed"
? "success"
: "info"
}
/>
<Button
size="sm"
variant="secondary"
className="mt-1"
leftIcon={
<ShieldCheck
className={cn(
"size-4",
verifierState === "running" && "animate-pulse",
)}
aria-hidden
/>
}
disabled={verifierState !== "idle"}
onClick={handleRunSdkVerifier}
>
{verifierCopy.buttonLabel}
</Button>
</section>
</div>
<section className="border-border bg-surface rounded-lg border p-4">
<div className="flex items-center justify-between gap-3">
<p className="text-text-primary text-sm font-semibold">
Operations log
</p>
<Badge variant="info" size="sm">
{Math.min(AUDIT_LOG_VISIBLE_LIMIT, auditLog.length)} of{" "}
{auditLog.length} events
</Badge>
</div>
<div className="mt-3 grid gap-2 lg:grid-cols-3">
{auditLog.slice(0, AUDIT_LOG_VISIBLE_LIMIT).map((item) => (
<div
key={item.id}
className="border-border-subtle rounded-lg border px-3 py-2"
>
<div className="flex items-center justify-between gap-2">
<p className="text-text-primary truncate text-sm font-medium">
{item.label}
</p>
<Badge variant={item.tone} size="sm" dot>
{AUDIT_TONE_LABEL[item.tone]}
</Badge>
</div>
<p className="text-text-tertiary mt-1 truncate text-xs">
{item.detail}
</p>
</div>
))}
</div>
</section>
</div>
</main>
</div>
);
}