# Admin Form Connection Guide

This guide explains how to connect all admin UI forms to tRPC backend procedures for data persistence.

## Overview

All admin components have form UIs with mock data. To make them functional, we need to:

1. **Create tRPC procedures** in backend routers
2. **Connect form submissions** to tRPC mutations in React components
3. **Handle loading/error states** with proper UX feedback
4. **Validate data** on both client and server

## Database Tables Required

Execute `migrations/training_tables.sql` to create:
- `training_videos` - Video content
- `training_questions` - Quiz questions
- `training_certifications` - Certification definitions
- `admin_certifications_earned` - Issued certificates
- `admin_training_progress` - Admin progress tracking
- `admin_quiz_responses` - Quiz answer history
- `admin_audit_logs` - Audit trail
- `admin_bulk_operations` - Operation history
- `admin_notifications` - Real-time notifications

## AdminContentManager Connection

### Current State
- Form collects: video title, URL, description, module
- Mock data shows 3 videos

### To Connect:

**Backend (server/routers/admin.training.ts):**
```typescript
createVideo: protectedProcedure
  .input(z.object({
    title: z.string().min(1),
    url: z.string().url(),
    description: z.string(),
    module: z.string(),
  }))
  .mutation(async ({ ctx, input }) => {
    return await db.insert(trainingVideos).values({
      ...input,
      createdBy: ctx.user.id,
      createdAt: new Date(),
    });
  }),
```

**Frontend (client/src/pages/AdminContentManagerConnected.tsx):**
```typescript
const createVideoMutation = trpc.admin.training.createVideo.useMutation({
  onSuccess: () => {
    toast.success("Video created successfully");
    // Refresh video list
    trpc.admin.training.getVideos.refetch();
  },
  onError: (error) => {
    toast.error(error.message);
  },
});

const handleCreateVideo = async (formData) => {
  await createVideoMutation.mutateAsync(formData);
};
```

## AdminCertificateManagement Connection

### Current State
- Shows 5 mock certificates
- Revoke/reissue buttons not functional

### To Connect:

**Backend:**
```typescript
revokeCertificate: protectedProcedure
  .input(z.object({ certificateId: z.string() }))
  .mutation(async ({ ctx, input }) => {
    return await db
      .update(adminCertificationsEarned)
      .set({ revokedAt: new Date(), revokedBy: ctx.user.id })
      .where(eq(adminCertificationsEarned.id, input.certificateId));
  }),
```

**Frontend:**
```typescript
const revokeMutation = trpc.admin.training.revokeCertificate.useMutation({
  onSuccess: () => {
    toast.success("Certificate revoked");
    refetchCertificates();
  },
});

const handleRevoke = (certificateId) => {
  revokeMutation.mutate({ certificateId });
};
```

## AdminTrainingAnalytics Connection

### Current State
- Shows mock analytics data
- Charts display hardcoded values

### To Connect:

**Backend:**
```typescript
getAnalytics: protectedProcedure
  .query(async ({ ctx }) => {
    const admins = await db.query.users.findMany({
      where: eq(users.role, 'admin'),
    });
    
    const progress = await db.query.adminTrainingProgress.findMany();
    
    return {
      totalAdmins: admins.length,
      avgScore: calculateAverage(progress.map(p => p.quizScore)),
      certificationsEarned: progress.filter(p => p.certificationEarned).length,
      totalTimeSpent: progress.reduce((sum, p) => sum + p.totalTimeSpent, 0),
    };
  }),
```

**Frontend:**
```typescript
const { data: analytics, isLoading } = trpc.admin.training.getAnalytics.useQuery();

// Use analytics.avgScore, analytics.totalAdmins, etc. in components
```

## AdminTrainingLeaderboard Connection

### Current State
- Shows mock leaderboard with 5 admins
- Badges are hardcoded

### To Connect:

**Backend:**
```typescript
getLeaderboard: protectedProcedure
  .input(z.object({ timeframe: z.enum(['week', 'month', 'all']) }))
  .query(async ({ input }) => {
    const startDate = getStartDate(input.timeframe);
    
    const leaderboard = await db.query.adminTrainingProgress.findMany({
      where: gte(adminTrainingProgress.lastActivity, startDate),
      orderBy: desc(adminTrainingProgress.totalPoints),
      limit: 50,
    });
    
    return leaderboard.map((entry, index) => ({
      rank: index + 1,
      ...entry,
    }));
  }),
```

**Frontend:**
```typescript
const { data: leaderboard } = trpc.admin.training.getLeaderboard.useQuery({
  timeframe: selectedTimeframe,
});

// Render leaderboard.map((entry) => ...)
```

## AdminBulkOperations Connection

### Current State
- Simulates bulk operations with 500ms intervals
- No actual backend execution

### To Connect:

**Backend:**
```typescript
executeBulkOperation: protectedProcedure
  .input(z.object({
    action: z.string(),
    adminIds: z.array(z.string()),
  }))
  .mutation(async ({ ctx, input }) => {
    const operation = await db.insert(adminBulkOperations).values({
      name: input.action,
      status: 'running',
      totalItems: input.adminIds.length,
      createdBy: ctx.user.id,
      createdAt: new Date(),
    });
    
    // Execute async
    processBulkOperation(operation.id, input.action, input.adminIds);
    
    return operation;
  }),
```

**Frontend:**
```typescript
const executeMutation = trpc.admin.training.executeBulkOperation.useMutation({
  onSuccess: (operation) => {
    // Add to operations list
    setOperations(prev => [operation, ...prev]);
    // Poll for updates
    pollOperationStatus(operation.id);
  },
});
```

## Email Configuration

### SMTP Setup

Set environment variables:
```
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
SMTP_FROM=noreply@coinkrazy.com
```

### Test Email Service

```typescript
// server/_core/certificationEmailService.ts
const testConfig = await testEmailConfiguration();
if (!testConfig.success) {
  console.error("Email configuration failed:", testConfig.error);
}
```

## WebSocket Real-Time Notifications

### Setup

```typescript
// server/_core/websocket.ts
import { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ server });

wss.on('connection', (ws) => {
  ws.on('message', (data) => {
    const message = JSON.parse(data);
    // Handle admin events
    broadcastToAdmins(message);
  });
});
```

### Frontend

```typescript
// client/src/hooks/useAdminNotifications.ts
const { notifications, subscribe } = useAdminNotifications();

useEffect(() => {
  subscribe('certificate-issued', (data) => {
    toast.success(`Certificate issued to ${data.adminName}`);
  });
}, []);
```

## Testing Checklist

- [ ] Database migrations executed successfully
- [ ] All tRPC procedures return correct data
- [ ] Form submissions persist to database
- [ ] Loading states show during mutations
- [ ] Error messages display on failures
- [ ] Success toasts appear after operations
- [ ] Data refreshes after mutations
- [ ] Email notifications send correctly
- [ ] WebSocket connections establish
- [ ] Real-time updates appear in UI

## Common Issues & Solutions

### Issue: "Cannot read property 'id' of undefined"
**Solution:** Ensure `ctx.user` is properly set by `protectedProcedure`

### Issue: "Mutation not triggering"
**Solution:** Check that form submission calls `mutateAsync()` or `mutate()`

### Issue: "Data not persisting"
**Solution:** Verify database connection and table exists

### Issue: "Email not sending"
**Solution:** Check SMTP credentials and firewall rules

## Next Steps

1. Execute database migrations
2. Implement tRPC procedures one by one
3. Connect each admin component to its procedures
4. Test end-to-end workflows
5. Deploy and monitor in production
