# Vendor Bidding Flow & Super Admin Oversight Design

## Overview

This document describes the implementation of a self-service vendor bidding system with super admin oversight capabilities.

---

## 1. Architecture

### Context Switch Mechanism

Super Admin users with VENDOR role can toggle between admin and vendor views:

- **Header component** (`src/components/layouts/header.tsx`): Add "Switch to Vendor View" toggle button
- **Session context**: Store current view mode in React context
- **Routing**: When in vendor view, routes redirect to `/vendor-portal/*`
- **Auth**: Same session, same permissions, different UI layout

### Portal Structure

| Role                     | Dashboard Access | Vendor Portal Access |
| ------------------------ | ---------------- | -------------------- |
| Super Admin (vendor)     | `/dashboard/*`   | `/vendor-portal/*`   |
| Super Admin (non-vendor) | `/dashboard/*`   | No access            |
| Admin Staff              | `/dashboard/*`   | No access            |
| Vendor (non-admin)       | No access        | `/vendor-portal/*`   |

---

## 2. Bid Submission Flow

### Approval Logic

```typescript
type BidApprovalPath = "DIRECT" | "PENDING_APPROVAL";

function determineApprovalPath(
  tenderType: "PROJECT" | "CATEGORY",
  vendorVerification: "PENDING" | "VERIFIED" | "REJECTED",
  tenderAutoApprove: boolean,
): BidApprovalPath {
  // Category tenders + verified vendor + auto-approve enabled = direct
  if (
    tenderType === "CATEGORY" &&
    vendorVerification === "VERIFIED" &&
    tenderAutoApprove
  ) {
    return "DIRECT";
  }

  // Verified vendors = direct submission
  if (vendorVerification === "VERIFIED") {
    return "DIRECT";
  }

  // All others need approval
  return "PENDING_APPROVAL";
}
```

### Bid Status Updates

Add new status to `BidStatus` enum:

```prisma
enum BidStatus {
    DRAFT
    PENDING_APPROVAL  // NEW: awaiting admin approval
    SUBMITTED
    WITHDRAWN
    APPROVED          // NEW: approved by admin
    REJECTED          // NEW: rejected by admin
}
```

### Submission Endpoint Changes

**File:** `src/server/routers/bid.router.ts`

```typescript
submit: protectedProcedure.mutation(async ({ ctx, input }) => {
  // ... existing vendor validation ...

  const approvalPath = determineApprovalPath(
    tender.tenderType,
    vendor.verificationStatus,
    tender.autoApproveBids ?? false,
  );

  const status = approvalPath === "DIRECT" ? "SUBMITTED" : "PENDING_APPROVAL";

  // Create bid with appropriate status
  const result = await ctx.db.bidSubmission.create({
    data: {
      // ... existing fields ...
      status,
    },
  });

  // If pending approval, notify super admin
  if (approvalPath === "PENDING_APPROVAL") {
    await notifySuperAdmins("BID_PENDING_APPROVAL", {
      tenderId: input.tenderId,
      vendorId,
      bidId: result.id,
    });
  }

  return result;
});
```

---

## 3. Super Admin Oversight

### New Pages

#### 3.1 `/dashboard/vendor-oversight` - Main Oversight Dashboard

**Sections:**

1. **Pending Approvals** (cards)
   - Count of bids awaiting review
   - Quick action buttons

2. **All Bids Table**
   - Columns: Vendor, Tender, Amount, Status, Submitted Date, Actions
   - Filters: Status, Tender Type, Date Range, Vendor

3. **Analytics Cards**
   - Total bids this month
   - Average bid amount
   - Approval rate

#### 3.2 `/dashboard/tender/[id]/bids` - Per-Tender Bid Management

**Sections:**

1. **Tender Summary** - tender details header
2. **Bids List** - all bids for this tender
3. **Comparison View** - side-by-side bid comparison
4. **Actions Panel** - bulk actions

### New API Endpoints

**File:** `src/server/routers/bid.router.ts`

```typescript
// Get all bids (super admin only)
getAllBids: adminProcedure
  .input(z.object({
    status: z.enum(['PENDING_APPROVAL', 'SUBMITTED', 'APPROVED', 'REJECTED']).optional(),
    tenderType: z.enum(['PROJECT', 'CATEGORY']).optional(),
    vendorId: z.string().optional(),
    fromDate: z.date().optional(),
    toDate: z.date().optional(),
    limit: z.number().default(20),
    offset: z.number().default(0),
  }))
  .query(async ({ ctx, input }) => {
    // Filter and return all bids across tenders
  }),

// Approve bid
approveBid: adminProcedure
  .input(z.object({ bidId: z.string(), notes: z.string().optional() }))
  .mutation(async ({ ctx, input }) => {
    // Update status to APPROVED
    // Notify vendor
    // Log audit
  }),

// Reject bid
rejectBid: adminProcedure
  .input(z.object({ bidId: z.string(), reason: z.string() }))
  .mutation(async ({ ctx, input }) => {
    // Update status to REJECTED
    // Notify vendor with reason
    // Log audit
  }),

// Edit bid (admin override)
adminEditBid: adminProcedure
  .input(z.object({
    bidId: z.string(),
    lineItems: z.array(z.object({...}))
  }))
  .mutation(async ({ ctx, input }) => {
    // Allow admin to modify bid
    // Log all changes in audit
  }),

// Withdraw bid (admin override)
adminWithdrawBid: adminProcedure
  .input(z.object({ bidId: z.string(), reason: z.string() }))
  .mutation(async ({ ctx, input }) => {
    // Set status to WITHDRAWN
    // Notify vendor
    // Log audit
  }),

// Send notification to vendor
notifyVendor: adminProcedure
  .input(z.object({
    bidId: z.string(),
    message: z.string(),
    type: z.enum(['APPROVAL', 'REJECTION', 'CLARIFICATION', 'GENERAL'])
  }))
  .mutation(async ({ ctx, input }) => {
    // Create notification for vendor
    // Optionally send email
  }),

// Get bid analytics
getBidAnalytics: adminProcedure
  .query(async ({ ctx }) => {
    // Aggregate stats for dashboard
  })
```

---

## 4. Database Schema Changes

### Modify BidSubmission

```prisma
model BidSubmission {
    id            String    @id @default(cuid())
    tenderId      String
    vendorId      String
    referenceNo   String    @unique
    status        BidStatus @default(DRAFT)
    totalAmount   Decimal?  @db.Decimal(15, 2)
    submittedAt   DateTime?
    approvedAt    DateTime?  // NEW
    approvedById  String?     // NEW
    rejectedAt    DateTime?  // NEW
    rejectedById  String?    // NEW
    rejectionReason String?   // NEW
    createdAt     DateTime  @default(now())
    updatedAt     DateTime  @updatedAt

    tender        TenderNotice  @relation(fields: [tenderId], references: [id])
    vendor        Vendor        @relation(fields: [vendorId], references: [id])
    approvedBy    User?         @relation("BidApprovals", fields: [approvedById], references: [id])  // NEW
    rejectedBy    User?         @relation("BidRejections", fields: [rejectedById], references: [id])  // NEW
    bidLineItems  BidLineItem[]
    versions      BidVersion[]

    @@unique([tenderId, vendorId])
}
```

### Modify TenderNotice

```prisma
model TenderNotice {
    // ... existing fields ...
    autoApproveBids Boolean @default(false)  // NEW: allow direct submission
}
```

---

## 5. Notifications

### Notification Types

```typescript
// For vendors
type VendorNotificationType =
  | "BID_SUBMITTED"
  | "BID_PENDING_APPROVAL"
  | "BID_APPROVED"
  | "BID_REJECTED"
  | "BID_WITHDRAWN"
  | "ADMIN_MESSAGE";

// For admins
type AdminNotificationType = "BID_PENDING_APPROVAL" | "VENDOR_MESSAGE";
```

### Email Triggers

| Event                   | Recipient   | Template               |
| ----------------------- | ----------- | ---------------------- |
| Bid submitted (pending) | Super Admin | `bid-pending-approval` |
| Bid approved            | Vendor      | `bid-approved`         |
| Bid rejected            | Vendor      | `bid-rejected`         |

---

## 6. Context Switch Implementation

### Header Component

**File:** `src/components/layouts/header.tsx`

```typescript
'use client';

import { useState } from 'react';
import { useRouter } from 'next/navigation';

export function Header() {
  const [isVendorView, setIsVendorView] = useState(false);
  const router = useRouter();

  const handleToggle = () => {
    const newMode = !isVendorView;
    setIsVendorView(newMode);

    if (newMode) {
      // Switch to vendor portal
      router.push('/vendor-portal/tenders');
    } else {
      // Switch to admin dashboard
      router.push('/dashboard');
    }
  };

  return (
    <header>
      {/* ... existing header content ... */}

      {/* Vendor View Toggle - only for users with both roles */}
      {canAccessVendorPortal && (
        <button onClick={handleToggle}>
          {isVendorView ? 'Switch to Admin View' : 'Switch to Vendor View'}
        </button>
      )}
    </header>
  );
}
```

---

## 7. UI Components Needed

### New Components

| Component            | Location               | Purpose                     |
| -------------------- | ---------------------- | --------------------------- |
| `BidApprovalCard`    | `src/components/bids/` | Pending approval card       |
| `BidComparisonTable` | `src/components/bids/` | Side-by-side bid comparison |
| `BidStatusBadge`     | `src/components/bids/` | Status indicator            |
| `VendorBidFilters`   | `src/components/bids/` | Filter bar for admin view   |

---

## 8. Permissions

### Add to `permissions.ts`

```typescript
const rolePermissions: Record<Role, Permission[]> = {
  // ... existing permissions ...

  SUPER_ADMIN: [
    // ... existing ...
    "bids:read", // NEW
    "bids:approve", // NEW
    "bids:reject", // NEW
    "bids:edit", // NEW
    "bids:withdraw", // NEW
  ],

  VENDOR: [
    "tenders:read",
    "bids:submit", // NEW
    "bids:read:own", // NEW
    "bids:edit:own", // NEW - own bids only
  ],
};
```

---

## 9. Implementation Order

1. **Database migrations** - Add new fields to schema
2. **API endpoints** - Add admin oversight endpoints to `bid.router.ts`
3. **Context switch** - Implement toggle in header
4. **Admin pages** - Create vendor oversight dashboard
5. **Vendor portal** - Update bid submission flow with approval logic
6. **Notifications** - Add email/notification triggers
7. **Testing** - Verify all approval paths work

---

## 10. Acceptance Criteria

- [ ] Super admin can toggle between admin and vendor views
- [ ] Vendors can submit bids to category tenders (if verified, direct)
- [ ] Vendors submitting to project tenders require approval
- [ ] Super admin sees all pending bids in oversight dashboard
- [ ] Super admin can approve/reject bids with notes
- [ ] Super admin can edit/withdraw bids on behalf of vendors
- [ ] Vendors receive notifications for bid status changes
- [ ] All admin actions are logged in audit trail
