CROP
ProjectsAdmin Panel

Admin API Migration Plan

> Status: RECOMMENDATION > Created: 2025-12-10 > Priority: High (Security)

Admin API Migration Plan

Status: RECOMMENDATION Created: 2025-12-10 Priority: High (Security)

Executive Summary

Currently, the admin panel (crop-front-admin on Vercel) connects directly to MongoDB Atlas, requiring 0.0.0.0/0 IP whitelist which is a security anti-pattern. This document outlines the plan to migrate all MongoDB access through the existing catalog-service microservice.

Current Architecture (Problem)

┌─────────────────────────────────────────────────────────────────┐
│                   VERCEL (crop-front-admin)                     │
│                                                                 │
│   Next.js API Routes ──► Direct MongoDB Connection              │
│                          (requires 0.0.0.0/0 whitelist)         │
└─────────────────────────────────────────────────────────────────┘

                                ▼ ❌ INSECURE
┌─────────────────────────────────────────────────────────────────┐
│                      MongoDB Atlas                              │
│                                                                 │
│   IP Whitelist: 0.0.0.0/0 (allows ALL IPs)                     │
│   Only protected by username/password                           │
└─────────────────────────────────────────────────────────────────┘

Security Issues

IssueRisk LevelDescription
Open IP WhitelistCRITICAL0.0.0.0/0 allows any IP to attempt connection
No Network IsolationHIGHSingle layer of defense (credentials only)
Brute Force ExposureHIGHAttackers can attempt password guessing
Compliance ViolationMEDIUMFails SOC2, PCI-DSS requirements
Audit DifficultyMEDIUMCannot trace attack sources by IP

Target Architecture (Solution)

┌─────────────────────────────────────────────────────────────────┐
│                   VERCEL (crop-front-admin)                     │
│                                                                 │
│   Next.js App ──► fetch("https://api.crop-dev.app/catalog/...") │
│                   (No direct MongoDB access)                    │
└─────────────────────────────────────────────────────────────────┘

                                ▼ HTTPS + JWT
┌─────────────────────────────────────────────────────────────────┐
│                 CLOUDFLARE (api.crop-dev.app)                   │
│                                                                 │
│   Worker: Route /catalog/* → GCP API Gateway                    │
│   Features: Edge caching, DDoS protection, WAF                  │
└─────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│                    GCP API GATEWAY                              │
│                                                                 │
│   - Clerk JWT validation                                        │
│   - Rate limiting                                               │
│   - Request logging                                             │
└─────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│              CLOUD RUN: catalog-service (EXISTS)                │
│                                                                 │
│   VPC Connector: crop-connector                                 │
│   Egress: ALL_TRAFFIC via VPC                                   │
└─────────────────────────────────────────────────────────────────┘

                                ▼ Private Link (PSC)
┌─────────────────────────────────────────────────────────────────┐
│              MongoDB Atlas (Private Endpoint)                   │
│                                                                 │
│   pl-00-xxx.dkwuhg.mongodb.net                                  │
│   IP Whitelist: Only VPC IPs (NO 0.0.0.0/0)                    │
└─────────────────────────────────────────────────────────────────┘

Security Benefits

BenefitDescription
Network IsolationMongoDB only accessible via Private Link
Defense in DepthMultiple security layers (Cloudflare → Gateway → VPC)
JWT ValidationClerk tokens validated at API Gateway
IP RestrictionRemove 0.0.0.0/0, whitelist only VPC IPs
Audit TrailAll requests logged at Gateway level
DDoS ProtectionCloudflare edge protection

Existing Infrastructure

Already Implemented

ComponentStatusLocation
catalog-service✅ EXISTS/CROP-parts-services/services/catalog/
Vendor endpoints✅ EXISTS/catalog/vendors/*
Parts endpoints✅ EXISTS/catalog/parts/*
Quality endpoints✅ EXISTS/catalog/quality/*
VPC + Private Link✅ EXISTScrop-vpc → MongoDB PSC
Cloudflare Worker✅ EXISTSapi.crop-dev.app
API Gateway✅ EXISTScrop-gateway

catalog-service Endpoints (Already Available)

# Vendors
GET    /catalog/vendors                    # List vendors
POST   /catalog/vendors                    # Create vendor
GET    /catalog/vendors/:code              # Get vendor
PATCH  /catalog/vendors/:code              # Update vendor
DELETE /catalog/vendors/:code              # Archive vendor
POST   /catalog/vendors/:code/status       # Change status
POST   /catalog/vendors/refresh-readiness  # Bulk refresh

# Parts
GET    /catalog/parts/:vendorCode          # List parts by vendor
POST   /catalog/parts/:vendorCode          # Create part
GET    /catalog/parts/:vendorCode/:partNumber  # Get part
PATCH  /catalog/parts/:vendorCode/:partNumber  # Update part
DELETE /catalog/parts/:vendorCode/:partNumber  # Delete part

# Quality
GET    /catalog/quality/summary            # All vendors quality
GET    /catalog/quality/:vendorCode        # Single vendor quality
POST   /catalog/quality/revalidate         # Cache revalidation

# Collections
GET    /catalog/collections                # List collections
GET    /catalog/collections/:name          # Collection schema

# Sync
POST   /catalog/sync                       # Full ES sync
POST   /catalog/sync/:vendorCode           # Vendor ES sync

Migration Scope

Routes to Migrate (from crop-front-admin)

Current RouteTargetComplexity
/api/vendors/catalog/vendorsLow (direct map)
/api/vendors/[code]/catalog/vendors/:codeLow
/api/vendors/[code]/status/catalog/vendors/:code/statusLow
/api/catalog/quality/vendors/catalog/quality/summaryLow
/api/catalog/quality/vendors/[code]/catalog/quality/:codeLow
/api/catalog/health/vendors/catalog/health/vendorsMedium
/api/parts/catalog/partsMedium
/api/parts/[slug]/catalog/parts/:vendor/:partNumberMedium
/api/dashboard/statsNEW endpoint neededMedium
/api/ordersSeparate serviceLow
/api/health/collections/catalog/collectionsLow

Code to Remove (after migration)

crop-front-admin/
├── lib/
│   ├── mongodb.ts              # DELETE - No longer needed
│   ├── db/
│   │   ├── crud.ts             # DELETE - Move to catalog-service
│   │   └── collections.ts      # DELETE - Move to catalog-service
│   └── services/
│       └── vendor-readiness.ts # DELETE - Already in catalog-service
└── app/api/
    ├── vendors/                # REFACTOR - Proxy to catalog-service
    ├── parts/                  # REFACTOR - Proxy to catalog-service
    ├── catalog/                # REFACTOR - Proxy to catalog-service
    └── health/                 # REFACTOR - Proxy to catalog-service

Environment Variables to Remove (Vercel)

# REMOVE from Vercel after migration
MONGODB_URI          # No longer needed
MONGODB_DB_NAME      # No longer needed

Implementation Phases

Phase 1: Infrastructure Setup (0.5 days)

Tasks:

  1. Add /catalog/* routes to API Gateway OpenAPI spec
  2. Update Cloudflare Worker to route /catalog/* to Gateway
  3. Verify catalog-service is deployed with VPC connector
  4. Test connectivity: Vercel → Cloudflare → Gateway → catalog-service → MongoDB

Files to modify:

  • /CROP-parts-services/gateway.yaml - Add catalog routes
  • /CROP-parts-services/cloudflare/api-proxy/src/index.ts - Add routing

Phase 2: Authentication Integration (1 day)

Tasks:

  1. Add Clerk JWT validation to catalog-service
  2. Extract user info for audit trail (activatedBy, deactivatedBy)
  3. Add role-based access control (admin only)

Files to modify:

  • /CROP-parts-services/services/catalog/src/middleware/clerk-auth.ts - NEW
  • /CROP-parts-services/services/catalog/src/routes/vendors.ts - Add user tracking

Clerk JWT Middleware Example:

import { verifyToken } from '@clerk/backend';

export async function clerkAuth(c: Context, next: Next) {
  const authHeader = c.req.header('Authorization');
  if (!authHeader?.startsWith('Bearer ')) {
    return c.json({ error: 'Unauthorized' }, 401);
  }

  try {
    const token = authHeader.slice(7);
    const payload = await verifyToken(token, {
      secretKey: process.env.CLERK_SECRET_KEY,
    });
    c.set('userId', payload.sub);
    c.set('userEmail', payload.email);
    await next();
  } catch {
    return c.json({ error: 'Invalid token' }, 401);
  }
}

Phase 3: Frontend API Client (1 day)

Tasks:

  1. Create lib/api/catalog-client.ts in admin panel
  2. Add request interceptor for Clerk token injection
  3. Add error handling and retry logic

New file: lib/api/catalog-client.ts

import { auth } from '@clerk/nextjs/server';

const CATALOG_API_URL = process.env.NEXT_PUBLIC_API_GATEWAY_URL || 'https://api.crop-dev.app';

export async function catalogFetch<T>(
  endpoint: string,
  options: RequestInit = {}
): Promise<T> {
  const { getToken } = await auth();
  const token = await getToken();

  const response = await fetch(`${CATALOG_API_URL}/catalog${endpoint}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`,
      ...options.headers,
    },
  });

  if (!response.ok) {
    throw new Error(`Catalog API error: ${response.status}`);
  }

  return response.json();
}

// Typed API methods
export const catalogApi = {
  vendors: {
    list: (catalog?: string) =>
      catalogFetch<VendorListResponse>(`/vendors?catalog=${catalog || 'crop_stage'}`),
    get: (code: string) =>
      catalogFetch<Vendor>(`/vendors/${code}`),
    create: (data: CreateVendorInput) =>
      catalogFetch<Vendor>('/vendors', { method: 'POST', body: JSON.stringify(data) }),
    update: (code: string, data: UpdateVendorInput) =>
      catalogFetch<Vendor>(`/vendors/${code}`, { method: 'PATCH', body: JSON.stringify(data) }),
    changeStatus: (code: string, status: VendorStatus) =>
      catalogFetch<Vendor>(`/vendors/${code}/status`, { method: 'POST', body: JSON.stringify({ status }) }),
  },
  quality: {
    summary: (catalog?: string) =>
      catalogFetch<QualitySummary>(`/quality/summary?catalog=${catalog || 'crop_stage'}`),
    vendor: (code: string) =>
      catalogFetch<VendorQuality>(`/quality/${code}`),
  },
  // ... more methods
};

Phase 4: Route Migration (2 days)

Tasks:

  1. Refactor each API route to use catalogApi client
  2. Keep route structure same (for frontend compatibility)
  3. Add feature flag for gradual rollout

Example refactor: /app/api/vendors/route.ts

// BEFORE (direct MongoDB)
import { getClient } from '@/lib/mongodb';

export async function GET(req: NextRequest) {
  const client = await getClient();
  const db = client.db('crop_stage');
  const vendors = await db.collection('vendors').find({}).toArray();
  return NextResponse.json({ vendors });
}

// AFTER (via catalog-service)
import { catalogApi } from '@/lib/api/catalog-client';

export async function GET(req: NextRequest) {
  const catalog = new URL(req.url).searchParams.get('catalog');
  const response = await catalogApi.vendors.list(catalog);
  return NextResponse.json(response);
}

Phase 5: Testing & Validation (1 day)

Tasks:

  1. E2E tests for all migrated routes
  2. Performance comparison (latency before/after)
  3. Error handling verification
  4. Rollback procedure documentation

Test checklist:

  • Vendor CRUD operations
  • Vendor status transitions
  • Quality metrics loading
  • Parts listing and search
  • Dashboard stats
  • Error responses (401, 403, 404, 500)
  • Rate limiting behavior

Phase 6: Cleanup & Security Hardening (0.5 days)

Tasks:

  1. Remove MONGODB_URI from Vercel environment
  2. Delete lib/mongodb.ts and related files
  3. Remove 0.0.0.0/0 from MongoDB Atlas whitelist
  4. Update documentation

MongoDB Atlas Network Access (final state):

# REMOVE
0.0.0.0/0 (Allow from anywhere)

# KEEP
10.0.0.0/24 (crop-vpc)
34.74.212.119/32 (payment-vpc NAT)

Timeline

PhaseDurationDependencies
Phase 1: Infrastructure0.5 daysNone
Phase 2: Authentication1 dayPhase 1
Phase 3: API Client1 dayPhase 1
Phase 4: Route Migration2 daysPhase 2, 3
Phase 5: Testing1 dayPhase 4
Phase 6: Cleanup0.5 daysPhase 5
Total6 days

Rollback Plan

If issues occur during migration:

  1. Feature Flag Rollback

    const USE_CATALOG_API = process.env.USE_CATALOG_API === 'true';
    
    if (USE_CATALOG_API) {
      return catalogApi.vendors.list();
    } else {
      return directMongoQuery(); // fallback
    }
  2. Environment Rollback

    • Re-add MONGODB_URI to Vercel
    • Re-add 0.0.0.0/0 to Atlas (temporary)
    • Deploy previous version
  3. Monitoring

    • Set up alerts for 5xx errors on catalog routes
    • Monitor latency increase > 500ms
    • Track error rates during rollout

Success Criteria

MetricTarget
MongoDB 0.0.0.0/0 removed
All admin routes via catalog-service
Latency increase< 100ms
Error rate< 0.1%
Clerk JWT validation working
Audit trail for status changes

Appendix: Current Duplication

The following code is duplicated between admin panel and catalog-service:

File (admin)File (catalog)Action
lib/services/vendor-readiness.tssrc/services/vendor-readiness.tsKeep catalog, delete admin
lib/types/vendor.tssrc/types/vendor.tsKeep catalog, delete admin
lib/db/collections.tssrc/services/mongodb.tsKeep catalog, delete admin

After migration, admin panel will have zero MongoDB-related code.

References

On this page