admin-dashboard

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Admin & Developer Suite Development

管理与开发者套件开发

This skill helps you extend the admin dashboard and build internal tools following the established patterns.
本技能可帮助你遵循既定模式扩展管理控制台并构建内部工具。

Architecture Overview

架构概述

/admin     - Admin Dashboard (user metrics, access control, audit)
/dev       - Developer Portal (docs, code browser, feature map) [PLANNED]
/ops       - Operations Console (infrastructure, logs, incidents) [PLANNED]
See
docs/ADMIN-DEVELOPER-SUITE.md
for the full design specification.
/admin     - 管理控制台(用户指标、访问控制、审计)
/dev       - 开发者门户(文档、代码浏览器、功能地图)[规划中]
/ops       - 运维控制台(基础设施、日志、事件)[规划中]
完整设计规范请查看
docs/ADMIN-DEVELOPER-SUITE.md

Current Admin Dashboard Structure

当前管理控制台结构

Location:
src/app/admin/page.tsx
位置:
src/app/admin/page.tsx

Existing Tabs

现有标签页

TabPurposeData Source
OverviewQuick stats (users, check-ins, messages)
/api/admin/stats
FunnelUser engagement waterfall
/api/admin/stats
Page ViewsAnalytics by page path
/api/admin/stats
UsersUser roster with activity
/api/admin/stats
Access RequestsPending/approved/denied requests
/api/admin/access-requests
Allowed EmailsEmail whitelist management
/api/admin/allowed-emails
Email TemplatesPreview system emailsLocal data
标签页用途数据源
概览快速统计(用户、签到、消息)
/api/admin/stats
转化漏斗用户参与度瀑布图
/api/admin/stats
页面访问量按页面路径统计的分析数据
/api/admin/stats
用户含活动记录的用户列表
/api/admin/stats
访问请求待处理/已批准/已拒绝的请求
/api/admin/access-requests
允许邮箱邮箱白名单管理
/api/admin/allowed-emails
邮件模板预览系统邮件本地数据

Planned Tabs (from design)

规划中的标签页(来自设计文档)

TabPurposeStatus
Production HealthAPI latency, Core Web VitalsPending
Error TrackingHIPAA-safe error aggregationPending
External ServicesAnthropic, DB, Push statusPending
AI AnalyticsConversation metrics, tokensPending
Audit LogsHIPAA compliance viewerPending
标签页用途状态
生产环境健康度API延迟、核心Web指标待开发
错误追踪符合HIPAA标准的错误聚合待开发
外部服务Anthropic、数据库、推送服务状态待开发
AI分析对话指标、令牌使用量待开发
审计日志HIPAA合规查看器待开发

Adding a New Admin Tab

添加新的管理标签页

1. Create the Tab Content Component

1. 创建标签页内容组件

typescript
// In src/app/admin/page.tsx, add a new tab component

function ProductionHealthTab() {
  const [metrics, setMetrics] = useState<APIMetrics | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchMetrics() {
      const res = await fetch('/api/admin/metrics');
      const data = await res.json();
      setMetrics(data);
      setLoading(false);
    }
    fetchMetrics();
  }, []);

  if (loading) return <div>Loading...</div>;

  return (
    <div className="space-y-6">
      <div className="grid grid-cols-4 gap-4">
        <StatCard label="Uptime" value={metrics.uptime} />
        <StatCard label="Avg Latency" value={`${metrics.avgLatency}ms`} />
        <StatCard label="Errors (24h)" value={metrics.errorCount} />
        <StatCard label="Active Users" value={metrics.activeUsers} />
      </div>
      {/* More content */}
    </div>
  );
}
typescript
// In src/app/admin/page.tsx, add a new tab component

function ProductionHealthTab() {
  const [metrics, setMetrics] = useState<APIMetrics | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchMetrics() {
      const res = await fetch('/api/admin/metrics');
      const data = await res.json();
      setMetrics(data);
      setLoading(false);
    }
    fetchMetrics();
  }, []);

  if (loading) return <div>Loading...</div>;

  return (
    <div className="space-y-6">
      <div className="grid grid-cols-4 gap-4">
        <StatCard label="Uptime" value={metrics.uptime} />
        <StatCard label="Avg Latency" value={`${metrics.avgLatency}ms`} />
        <StatCard label="Errors (24h)" value={metrics.errorCount} />
        <StatCard label="Active Users" value={metrics.activeUsers} />
      </div>
      {/* More content */}
    </div>
  );
}

2. Add the Tab to the Tab List

2. 将标签页添加到标签列表

typescript
const tabs = [
  { id: 'overview', label: 'Overview' },
  { id: 'health', label: 'Production Health' }, // NEW
  { id: 'funnel', label: 'Funnel' },
  // ...
];
typescript
const tabs = [
  { id: 'overview', label: 'Overview' },
  { id: 'health', label: 'Production Health' }, // NEW
  { id: 'funnel', label: 'Funnel' },
  // ...
];

3. Add the Tab Content Renderer

3. 添加标签页内容渲染器

typescript
function renderTabContent(tabId: string) {
  switch (tabId) {
    case 'overview':
      return <OverviewTab stats={stats} />;
    case 'health':
      return <ProductionHealthTab />; // NEW
    // ...
  }
}
typescript
function renderTabContent(tabId: string) {
  switch (tabId) {
    case 'overview':
      return <OverviewTab stats={stats} />;
    case 'health':
      return <ProductionHealthTab />; // NEW
    // ...
  }
}

Creating Admin API Endpoints

创建管理API端点

Pattern: Admin Stats Endpoint

模式:管理统计数据端点

typescript
// src/app/api/admin/metrics/route.ts
import { requireAdmin } from '@/db/secure-db';
import { createRateLimiter } from '@/lib/rate-limit';
import { logAdminAction } from '@/lib/hipaa/audit';

const rateLimiter = createRateLimiter({
  windowMs: 60000,
  maxRequests: 60,
  keyPrefix: 'admin:metrics'
});

export async function GET(request: Request) {
  // 1. Check admin access
  const admin = await requireAdmin();
  if (!admin) {
    return Response.json({ error: 'Forbidden' }, { status: 403 });
  }

  // 2. Apply rate limiting
  const rateLimitResult = await rateLimiter.check(admin.id);
  if (!rateLimitResult.allowed) {
    return Response.json(
      { error: 'Rate limit exceeded' },
      { status: 429, headers: rateLimitResult.headers }
    );
  }

  // 3. Log admin action
  await logAdminAction(
    admin.id,
    AuditAction.ADMIN_STATS_VIEW,
    'metrics',
    null
  );

  // 4. Fetch and return data
  const metrics = await getAPIMetrics();
  return Response.json(metrics);
}
typescript
// src/app/api/admin/metrics/route.ts
import { requireAdmin } from '@/db/secure-db';
import { createRateLimiter } from '@/lib/rate-limit';
import { logAdminAction } from '@/lib/hipaa/audit';

const rateLimiter = createRateLimiter({
  windowMs: 60000,
  maxRequests: 60,
  keyPrefix: 'admin:metrics'
});

export async function GET(request: Request) {
  // 1. Check admin access
  const admin = await requireAdmin();
  if (!admin) {
    return Response.json({ error: 'Forbidden' }, { status: 403 });
  }

  // 2. Apply rate limiting
  const rateLimitResult = await rateLimiter.check(admin.id);
  if (!rateLimitResult.allowed) {
    return Response.json(
      { error: 'Rate limit exceeded' },
      { status: 429, headers: rateLimitResult.headers }
    );
  }

  // 3. Log admin action
  await logAdminAction(
    admin.id,
    AuditAction.ADMIN_STATS_VIEW,
    'metrics',
    null
  );

  // 4. Fetch and return data
  const metrics = await getAPIMetrics();
  return Response.json(metrics);
}

Key Patterns

核心模式

StatCard Component

StatCard组件

typescript
function StatCard({
  label,
  value,
  trend,
  status
}: {
  label: string;
  value: string | number;
  trend?: 'up' | 'down' | 'neutral';
  status?: 'good' | 'warning' | 'error';
}) {
  return (
    <div className="rounded-lg border bg-card p-4">
      <div className="text-sm text-muted-foreground">{label}</div>
      <div className="text-2xl font-bold">{value}</div>
      {trend && <TrendIndicator direction={trend} />}
      {status && <StatusBadge status={status} />}
    </div>
  );
}
typescript
function StatCard({
  label,
  value,
  trend,
  status
}: {
  label: string;
  value: string | number;
  trend?: 'up' | 'down' | 'neutral';
  status?: 'good' | 'warning' | 'error';
}) {
  return (
    <div className="rounded-lg border bg-card p-4">
      <div className="text-sm text-muted-foreground">{label}</div>
      <div className="text-2xl font-bold">{value}</div>
      {trend && <TrendIndicator direction={trend} />}
      {status && <StatusBadge status={status} />}
    </div>
  );
}

Data Fetching Pattern

数据获取模式

typescript
// Use SWR or React Query for real-time updates
import useSWR from 'swr';

function useAdminMetrics() {
  const { data, error, isLoading } = useSWR(
    '/api/admin/metrics',
    fetcher,
    { refreshInterval: 30000 } // Refresh every 30s
  );

  return { metrics: data, error, isLoading };
}
typescript
// Use SWR or React Query for real-time updates
import useSWR from 'swr';

function useAdminMetrics() {
  const { data, error, isLoading } = useSWR(
    '/api/admin/metrics',
    fetcher,
    { refreshInterval: 30000 } // Refresh every 30s
  );

  return { metrics: data, error, isLoading };
}

HIPAA-Safe Error Display

HIPAA合规的错误展示

typescript
// Never show user-specific error details
function ErrorList({ errors }: { errors: AggregatedError[] }) {
  return (
    <div>
      {errors.map(error => (
        <div key={error.hash}>
          <span className="font-mono">{error.type}</span>
          <span>{error.path}</span>
          <span>{error.count} occurrences</span>
          <span>{error.affectedUsers} users</span>
          {/* NO user IDs, NO error messages with PHI */}
        </div>
      ))}
    </div>
  );
}
typescript
// Never show user-specific error details
function ErrorList({ errors }: { errors: AggregatedError[] }) {
  return (
    <div>
      {errors.map(error => (
        <div key={error.hash}>
          <span className="font-mono">{error.type}</span>
          <span>{error.path}</span>
          <span>{error.count} occurrences</span>
          <span>{error.affectedUsers} users</span>
          {/* NO user IDs, NO error messages with PHI */}
        </div>
      ))}
    </div>
  );
}

Database Tables for Admin Features

管理功能相关的数据库表

Existing tables:
  • adminUsers
    - Admin role assignments
  • allowedEmails
    - Email whitelist
  • accessRequests
    - Access request queue
  • auditLog
    - HIPAA audit trail
  • pageViews
    - Navigation analytics
Planned tables (from design):
  • api_metrics
    - API timing data
  • app_errors
    - Aggregated errors
  • service_health
    - External service status
  • conversation_analytics
    - AI chat metadata
  • incidents
    - Incident tracking
现有表:
  • adminUsers
    - 管理员角色分配
  • allowedEmails
    - 邮箱白名单
  • accessRequests
    - 访问请求队列
  • auditLog
    - HIPAA审计日志
  • pageViews
    - 导航分析数据
规划中的表(来自设计文档):
  • api_metrics
    - API时序数据
  • app_errors
    - 聚合后的错误数据
  • service_health
    - 外部服务状态
  • conversation_analytics
    - AI聊天元数据
  • incidents
    - 事件追踪

Access Control

访问控制

typescript
// Always use requireAdmin() for admin routes
import { requireAdmin } from '@/db/secure-db';

// For super-admin only features
const admin = await requireAdmin();
if (admin.role !== 'super_admin') {
  return Response.json({ error: 'Super admin required' }, { status: 403 });
}
typescript
// Always use requireAdmin() for admin routes
import { requireAdmin } from '@/db/secure-db';

// For super-admin only features
const admin = await requireAdmin();
if (admin.role !== 'super_admin') {
  return Response.json({ error: 'Super admin required' }, { status: 403 });
}

Testing Admin Features

管理功能测试

typescript
// Mock admin authentication for tests
vi.mock('@/db/secure-db', () => ({
  requireAdmin: vi.fn().mockResolvedValue({
    id: 'test-admin',
    role: 'admin'
  })
}));

describe('Admin Metrics Endpoint', () => {
  it('returns metrics for authenticated admin', async () => {
    const response = await GET(mockRequest);
    expect(response.status).toBe(200);
  });

  it('returns 403 for non-admin', async () => {
    vi.mocked(requireAdmin).mockResolvedValueOnce(null);
    const response = await GET(mockRequest);
    expect(response.status).toBe(403);
  });
});
typescript
// Mock admin authentication for tests
vi.mock('@/db/secure-db', () => ({
  requireAdmin: vi.fn().mockResolvedValue({
    id: 'test-admin',
    role: 'admin'
  })
}));

describe('Admin Metrics Endpoint', () => {
  it('returns metrics for authenticated admin', async () => {
    const response = await GET(mockRequest);
    expect(response.status).toBe(200);
  });

  it('returns 403 for non-admin', async () => {
    vi.mocked(requireAdmin).mockResolvedValueOnce(null);
    const response = await GET(mockRequest);
    expect(response.status).toBe(403);
  });
});

Design Resources

设计资源

  • Full design spec:
    docs/ADMIN-DEVELOPER-SUITE.md
  • Design system: Use existing components from
    src/components/ui/
  • Colors: Follow therapeutic palette (navy, teal, coral, cream)
  • 完整设计规范:
    docs/ADMIN-DEVELOPER-SUITE.md
  • 设计系统:使用
    src/components/ui/
    中的现有组件
  • 配色:遵循治疗系调色板(藏青、蓝绿、珊瑚、米白)