# Admin Onboarding System - Implementation Guide

## Overview

This guide provides step-by-step instructions to complete the admin onboarding system implementation for production deployment. The system includes a 6-step wizard, invite management, email notifications, and comprehensive audit logging.

---

## Phase 1: Database Migration

### Step 1: Execute Migration SQL

The migration SQL file is located at: `drizzle/migrations/0005_add_admin_onboarding_tables.sql`

**Option A: Using webdev_execute_sql Tool**

```bash
# Call webdev_execute_sql with the migration SQL content
# This will create 4 new tables:
# - admin_onboarding_progress
# - admin_profiles
# - admin_device_registrations
# - onboarding_analytics
```

**Option B: Manual MySQL Execution**

```bash
# Connect to your database
mysql -h your-host -u your-user -p your-database

# Execute the migration
source drizzle/migrations/0005_add_admin_onboarding_tables.sql;

# Verify tables were created
SHOW TABLES LIKE 'admin_%';
SHOW TABLES LIKE 'onboarding_%';
```

### Step 2: Verify Table Creation

```sql
-- Check admin_onboarding_progress table
DESC admin_onboarding_progress;

-- Check admin_profiles table
DESC admin_profiles;

-- Check admin_device_registrations table
DESC admin_device_registrations;

-- Check onboarding_analytics table
DESC onboarding_analytics;
```

### Step 3: Create Indexes (if not created by migration)

```sql
-- Create indexes for performance
CREATE INDEX idx_admin_onboarding_adminId ON admin_onboarding_progress(adminId);
CREATE INDEX idx_admin_onboarding_currentStep ON admin_onboarding_progress(currentStep);
CREATE INDEX idx_admin_profiles_adminId ON admin_profiles(adminId);
CREATE INDEX idx_admin_devices_adminId ON admin_device_registrations(adminId);
CREATE INDEX idx_onboarding_analytics_date ON onboarding_analytics(dateRecorded);
```

---

## Phase 2: Email Provider Configuration

### Step 1: Choose Email Provider

Select one of the following providers:

#### **Option 1: SendGrid (Recommended)**

**Installation:**
```bash
npm install @sendgrid/mail
# or
pnpm add @sendgrid/mail
```

**Environment Variables:**
```bash
EMAIL_PROVIDER=sendgrid
EMAIL_API_KEY=your-sendgrid-api-key
EMAIL_FROM_ADDRESS=noreply@coinkrazy.com
EMAIL_FROM_NAME=CoinKrazy Admin
```

**Get API Key:**
1. Go to https://sendgrid.com
2. Sign up or log in
3. Navigate to Settings → API Keys
4. Create new API key with Mail Send permission
5. Copy the key to EMAIL_API_KEY

#### **Option 2: Mailgun**

**Installation:**
```bash
npm install mailgun.js form-data
# or
pnpm add mailgun.js form-data
```

**Environment Variables:**
```bash
EMAIL_PROVIDER=mailgun
EMAIL_API_KEY=your-mailgun-api-key
MAILGUN_DOMAIN=mg.coinkrazy.com
EMAIL_FROM_ADDRESS=noreply@coinkrazy.com
EMAIL_FROM_NAME=CoinKrazy Admin
```

**Get API Key:**
1. Go to https://mailgun.com
2. Sign up or log in
3. Navigate to API Keys
4. Copy your API key to EMAIL_API_KEY

#### **Option 3: AWS SES**

**Installation:**
```bash
npm install @aws-sdk/client-ses
# or
pnpm add @aws-sdk/client-ses
```

**Environment Variables:**
```bash
EMAIL_PROVIDER=aws_ses
EMAIL_API_KEY=your-aws-secret-access-key
AWS_ACCESS_KEY_ID=your-aws-access-key-id
AWS_REGION=us-east-1
EMAIL_FROM_ADDRESS=noreply@coinkrazy.com
EMAIL_FROM_NAME=CoinKrazy Admin
```

#### **Option 4: SMTP**

**Installation:**
```bash
npm install nodemailer
# or
pnpm add nodemailer
```

**Environment Variables:**
```bash
EMAIL_PROVIDER=smtp
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
EMAIL_FROM_ADDRESS=noreply@coinkrazy.com
EMAIL_FROM_NAME=CoinKrazy Admin
```

### Step 2: Test Email Configuration

Create a test file to verify email sending:

```typescript
// test-email.ts
import { sendEmail, generateWelcomeEmailTemplate } from './server/_core/emailService';

async function testEmail() {
  const result = await sendEmail({
    to: 'test@example.com',
    subject: 'Test Email',
    html: generateWelcomeEmailTemplate(
      'Test Admin',
      'admin',
      'https://coinkrazy.com/admin/accept-invite?token=test123'
    ),
  });

  console.log('Email result:', result);
}

testEmail().catch(console.error);
```

Run the test:
```bash
npx ts-node test-email.ts
```

---

## Phase 3: Wire Database Queries

### Step 1: Update adminOnboardingRouter

Replace placeholder implementations with actual database queries:

```typescript
// server/routers/adminOnboarding.ts

export const adminOnboardingRouter = router({
  getProgress: protectedProcedure.query(async ({ ctx }) => {
    const db = await getDb();
    if (!db) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR' });
    
    // Query actual database
    const progress = await db.query.adminOnboardingProgress.findFirst({
      where: eq(adminOnboardingProgress.adminId, ctx.user.id),
    });

    if (!progress) {
      // Create initial progress record
      const [newProgress] = await db
        .insert(adminOnboardingProgress)
        .values({
          adminId: ctx.user.id,
          currentStep: 'welcome',
          completedSteps: [],
          startedAt: new Date(),
        })
        .returning();
      return newProgress;
    }

    return progress;
  }),

  updateProgress: protectedProcedure
    .input(z.object({
      currentStep: z.enum(['welcome', 'role_assignment', 'permission_training', 'security_training', 'device_registration', 'completion']),
      completedSteps: z.array(z.string()),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR' });

      const [updated] = await db
        .update(adminOnboardingProgress)
        .set({
          currentStep: input.currentStep,
          completedSteps: input.completedSteps,
          lastActivityAt: new Date(),
        })
        .where(eq(adminOnboardingProgress.adminId, ctx.user.id))
        .returning();

      return updated;
    }),

  // ... implement other procedures similarly
});
```

### Step 2: Update adminInvitesRouter

Wire invite creation and tracking:

```typescript
// server/routers/adminInvites.ts

export const adminInvitesRouter = router({
  createInvite: adminProcedure
    .input(z.object({
      email: z.string().email(),
      name: z.string(),
      role: z.enum(['admin', 'moderator', 'finance_team', 'developer', 'support_lead']),
      message: z.string().optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR' });

      // Generate invite token
      const token = generateInviteToken();
      const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 days

      // Save invite to database (you'll need to create this table)
      const [invite] = await db
        .insert(adminInvites)
        .values({
          token,
          email: input.email,
          name: input.name,
          role: input.role,
          invitedBy: ctx.user.id,
          expiresAt,
          createdAt: new Date(),
        })
        .returning();

      // Send invite email
      await sendEmail({
        to: input.email,
        subject: 'You\'re Invited to Join CoinKrazy Admin Team',
        html: generateWelcomeEmailTemplate(
          input.name,
          input.role,
          `${process.env.VITE_APP_URL}/admin/accept-invite?token=${token}`
        ),
      });

      // Log activity
      await logActivity({
        adminId: ctx.user.id,
        action: 'INVITE_CREATED',
        resourceType: 'admin_invite',
        resourceId: token,
        details: { email: input.email, role: input.role },
      });

      return { success: true, token };
    }),

  // ... implement other procedures similarly
});
```

### Step 3: Create Missing Database Table for Invites

Add to `drizzle/schema.ts`:

```typescript
export const adminInvites = mysqlTable('admin_invites', {
  id: int('id').autoincrement().primaryKey(),
  token: varchar('token', { length: 255 }).notNull().unique(),
  email: varchar('email', { length: 255 }).notNull(),
  name: varchar('name', { length: 255 }).notNull(),
  role: mysqlEnum('role', ['admin', 'moderator', 'finance_team', 'developer', 'support_lead']).notNull(),
  invitedBy: int('invitedBy').notNull(),
  acceptedAt: timestamp('acceptedAt'),
  expiresAt: timestamp('expiresAt').notNull(),
  createdAt: timestamp('createdAt').defaultNow().notNull(),
});
```

Run migration:
```bash
pnpm drizzle-kit generate
# Then execute the generated SQL
```

---

## Phase 4: Frontend Integration

### Step 1: Update AdminOnboardingWizard

Ensure components call tRPC procedures:

```typescript
// client/src/pages/AdminOnboardingWizard.tsx

export default function AdminOnboardingWizard() {
  const [currentStep, setCurrentStep] = useState(0);
  const { data: progress, isLoading } = trpc.adminOnboarding.getProgress.useQuery();
  const updateProgressMutation = trpc.adminOnboarding.updateProgress.useMutation();

  const handleStepComplete = async (stepName: string) => {
    const newCompleted = [...(progress?.completedSteps || []), stepName];
    await updateProgressMutation.mutateAsync({
      currentStep: stepName as any,
      completedSteps: newCompleted,
    });
    setCurrentStep(currentStep + 1);
  };

  // ... rest of component
}
```

### Step 2: Update AdminInviteManagement

Wire invite creation form:

```typescript
// client/src/pages/AdminInviteManagement.tsx

export default function AdminInviteManagement() {
  const createInviteMutation = trpc.adminInvites.createInvite.useMutation();
  const { data: pendingInvites } = trpc.adminInvites.getPendingInvites.useQuery();

  const handleCreateInvite = async (formData: any) => {
    try {
      await createInviteMutation.mutateAsync(formData);
      showSuccess('Invite sent successfully');
      // Refresh pending invites
    } catch (error) {
      showError('Failed to create invite');
    }
  };

  // ... rest of component
}
```

---

## Phase 5: Testing

### Step 1: End-to-End Testing

**Test Scenario 1: Admin Invite Flow**
1. Go to `/admin/invite-management`
2. Create a new invite with test email
3. Verify email was sent
4. Click invite link from email
5. Complete onboarding wizard
6. Verify data saved to database

**Test Scenario 2: Onboarding Progress**
1. Start onboarding as new admin
2. Complete each step
3. Verify progress saved in `admin_onboarding_progress` table
4. Refresh page and verify progress persists

**Test Scenario 3: 2FA Setup**
1. During onboarding, reach 2FA step
2. Scan QR code with authenticator app
3. Enter TOTP code
4. Verify 2FA enabled in `admin_profiles` table

### Step 2: Database Verification

```sql
-- Check onboarding progress
SELECT * FROM admin_onboarding_progress WHERE adminId = 1;

-- Check admin profile
SELECT * FROM admin_profiles WHERE adminId = 1;

-- Check device registrations
SELECT * FROM admin_device_registrations WHERE adminId = 1;

-- Check analytics
SELECT * FROM onboarding_analytics ORDER BY dateRecorded DESC LIMIT 1;
```

---

## Phase 6: Deployment

### Step 1: Environment Variables

Add to your `.env` file:

```bash
# Email Configuration
EMAIL_PROVIDER=sendgrid
EMAIL_API_KEY=your-api-key
EMAIL_FROM_ADDRESS=noreply@coinkrazy.com
EMAIL_FROM_NAME=CoinKrazy Admin

# App URLs
VITE_APP_URL=https://coinkrazy.com
```

### Step 2: Deploy

```bash
# Install dependencies
pnpm install

# Build
pnpm build

# Deploy to production
# (Use your deployment method: Railway, Vercel, Docker, etc.)
```

### Step 3: Verify Deployment

1. Test invite creation at `/admin/invite-management`
2. Verify email sends successfully
3. Test accept invite flow
4. Verify database queries work
5. Check admin activity logs

---

## Troubleshooting

### Email Not Sending

**Check:**
1. EMAIL_API_KEY is set correctly
2. EMAIL_PROVIDER is correct
3. EMAIL_FROM_ADDRESS is verified with provider
4. Check email service logs for errors

**Solution:**
```bash
# Test email service
npx ts-node test-email.ts

# Check server logs
tail -f .manus-logs/devserver.log
```

### Database Queries Failing

**Check:**
1. Migration SQL was executed successfully
2. Tables exist: `SHOW TABLES LIKE 'admin_%'`
3. Database connection string is correct
4. User has proper permissions

**Solution:**
```bash
# Verify database connection
mysql -h your-host -u your-user -p your-database -e "SELECT 1;"

# Re-run migration
mysql -h your-host -u your-user -p your-database < drizzle/migrations/0005_add_admin_onboarding_tables.sql
```

### Onboarding Progress Not Saving

**Check:**
1. tRPC procedures are wired to database
2. Database connection is working
3. User is authenticated
4. Check browser console for errors

**Solution:**
```bash
# Check server logs
tail -f .manus-logs/devserver.log | grep -i "onboarding"

# Verify database has data
SELECT * FROM admin_onboarding_progress;
```

---

## Architecture Overview

```
Admin Onboarding System
├── Frontend (React)
│   ├── AdminOnboardingWizard (6 steps)
│   ├── AdminInviteManagement (create/manage invites)
│   ├── AdminAcceptInvite (accept invite flow)
│   └── AdminProfileSetup (post-onboarding)
│
├── Backend (tRPC)
│   ├── adminOnboardingRouter (10 procedures)
│   ├── adminInvitesRouter (6 procedures)
│   ├── adminWelcomeRouter (4 procedures)
│   └── adminInviteTrackingRouter (5 procedures)
│
├── Database (MySQL)
│   ├── admin_onboarding_progress
│   ├── admin_profiles
│   ├── admin_device_registrations
│   ├── onboarding_analytics
│   └── admin_invites
│
└── Services
    ├── emailService (multi-provider)
    ├── activityLogger (audit trail)
    ├── alertEmitter (notifications)
    └── adminRoles (RBAC)
```

---

## Support

For issues or questions:
1. Check troubleshooting section above
2. Review server logs in `.manus-logs/`
3. Verify all environment variables are set
4. Test database connection directly
5. Check email provider dashboard for delivery logs

---

## Next Steps

1. ✅ Execute database migration
2. ✅ Configure email provider
3. ✅ Wire database queries
4. ✅ Test end-to-end flow
5. ✅ Deploy to production
6. Monitor admin activity logs
7. Gather feedback from admins
8. Iterate on UX improvements
