9.8 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 04-frontend | 01 | execute | 1 |
|
true |
|
|
Purpose: These components and service methods are the foundation that Plan 02 wires into the Dashboard. Separating creation from wiring keeps each plan focused. Output: Three files ready to be imported and mounted in App.tsx.
<execution_context> @/home/jonathan/.claude/get-shit-done/workflows/execute-plan.md @/home/jonathan/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/04-frontend/04-RESEARCH.md @frontend/src/services/adminService.ts @frontend/src/components/Analytics.tsx @frontend/src/components/UploadMonitoringDashboard.tsx @frontend/src/utils/cn.ts Task 1: Extend adminService with monitoring API methods and types frontend/src/services/adminService.ts Add three exported interfaces and four new methods to the existing AdminService class in `frontend/src/services/adminService.ts`.Interfaces to add (above the AdminService class):
export interface AlertEvent {
id: string;
service_name: string;
alert_type: 'service_down' | 'service_degraded' | 'recovery';
status: 'active' | 'acknowledged' | 'resolved';
message: string | null;
details: Record<string, unknown> | null;
created_at: string;
acknowledged_at: string | null;
resolved_at: string | null;
}
export interface ServiceHealthEntry {
service: string;
status: 'healthy' | 'degraded' | 'down' | 'unknown';
checkedAt: string | null;
latencyMs: number | null;
errorMessage: string | null;
}
export interface AnalyticsSummary {
range: string;
totalUploads: number;
succeeded: number;
failed: number;
successRate: number;
avgProcessingMs: number | null;
generatedAt: string;
}
IMPORTANT type casing note (from RESEARCH Pitfall 4):
ServiceHealthEntryuses camelCase (backend admin.ts remaps to camelCase)AlertEventuses snake_case (backend returns raw model data)AnalyticsSummaryuses camelCase (from backend analyticsService.ts)
Methods to add inside the AdminService class:
async getHealth(): Promise<ServiceHealthEntry[]> {
const response = await apiClient.get('/admin/health');
return response.data.data;
}
async getAnalytics(range: string = '24h'): Promise<AnalyticsSummary> {
const response = await apiClient.get(`/admin/analytics?range=${range}`);
return response.data.data;
}
async getAlerts(): Promise<AlertEvent[]> {
const response = await apiClient.get('/admin/alerts');
return response.data.data;
}
async acknowledgeAlert(id: string): Promise<AlertEvent> {
const response = await apiClient.post(`/admin/alerts/${id}/acknowledge`);
return response.data.data;
}
Keep all existing methods and interfaces. Do not modify the apiClient interceptor or the ADMIN_EMAIL check.
cd /home/jonathan/Coding/cim_summary/frontend && npx tsc --noEmit --strict src/services/adminService.ts 2>&1 | head -20
Verify the file exports AlertEvent, ServiceHealthEntry, AnalyticsSummary interfaces and the four new methods
adminService.ts exports 3 new typed interfaces and 4 new methods (getHealth, getAnalytics, getAlerts, acknowledgeAlert) alongside all existing functionality
Props interface:
interface AlertBannerProps {
alerts: AlertEvent[];
onAcknowledge: (id: string) => Promise<void>;
}
Behavior:
- Filter alerts to show only
status === 'active'ANDalert_typeisservice_downorservice_degraded(per RESEARCH Pitfall —recoveryis informational, not critical) - If no critical alerts after filtering, return
null - Render a red banner (
bg-red-600 px-4 py-3) with each alert showing:AlertTriangleicon from lucide-react (h-5 w-5, flex-shrink-0)- Text:
{alert.service_name}: {alert.message ?? alert.alert_type}(text-sm font-medium text-white) - "Acknowledge" button with
Xicon from lucide-react (text-sm underline hover:no-underline)
onAcknowledgecalled withalert.idon button click- Import
AlertEventfrom../services/adminService - Import
cnfrom../utils/cn - Use
AlertTriangleandXfromlucide-react
AdminMonitoringDashboard.tsx — Create at frontend/src/components/AdminMonitoringDashboard.tsx:
This component contains two sections: Service Health Panel and Processing Analytics Panel.
State:
const [health, setHealth] = useState<ServiceHealthEntry[]>([]);
const [analytics, setAnalytics] = useState<AnalyticsSummary | null>(null);
const [range, setRange] = useState('24h');
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
Data fetching: Use useCallback + useEffect pattern matching existing Analytics.tsx:
loadData()callsPromise.all([adminService.getHealth(), adminService.getAnalytics(range)])- Sets loading/error state appropriately
- Re-fetches when
rangechanges
Service Health Panel:
- 2x2 grid on desktop (
grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4) - Each card: white bg, rounded-lg, shadow-soft, border border-gray-100, p-4
- Status dot:
w-3 h-3 rounded-fullwith color mapping:healthy→bg-green-500degraded→bg-yellow-500down→bg-red-500unknown→bg-gray-400
- Service display name mapping:
document_ai→ "Document AI",llm_api→ "LLM API",supabase→ "Supabase",firebase_auth→ "Firebase Auth" - Show
checkedAtasnew Date(checkedAt).toLocaleString()if available, otherwise "Never checked" - Show
latencyMswith "ms" suffix if available - Use
Activity,Clockicons from lucide-react
Processing Analytics Panel:
- Range selector:
<select>with options24h,7d,30d— onChange updatesrangestate - Stat cards in 1x5 grid: Total Uploads, Succeeded, Failed, Success Rate (formatted as
(successRate * 100).toFixed(1)%), Avg Processing Time (formatavgProcessingMsas seconds:(avgProcessingMs / 1000).toFixed(1)s, or "N/A" if null) - Include a "Refresh" button that calls
loadData()— matches existing Analytics.tsx refresh pattern - Use
RefreshCwicon from lucide-react for refresh button
Loading state: Show animate-spin rounded-full h-8 w-8 border-b-2 border-accent-500 centered (matching existing App.tsx pattern).
Error state: Show error message with retry button.
Import ServiceHealthEntry, AnalyticsSummary from ../services/adminService.
Import adminService from ../services/adminService.
Import cn from ../utils/cn.
cd /home/jonathan/Coding/cim_summary/frontend && npx tsc --noEmit 2>&1 | head -30
Check that AlertBanner.tsx and AdminMonitoringDashboard.tsx exist and export their components
AlertBanner renders critical alerts with acknowledge buttons; AdminMonitoringDashboard renders health status grid with colored dots and analytics summary with range selector and refresh
<success_criteria> All three files compile without TypeScript errors. Components follow existing project patterns (Tailwind, lucide-react, cn utility). Types match backend API response shapes exactly (camelCase for health/analytics, snake_case for alerts). </success_criteria>
After completion, create `.planning/phases/04-frontend/04-01-SUMMARY.md`