Files
Sankofa/docs/infrastructure/IMPLEMENTATION_STEPS.md
defiQUG 9daf1fd378 Apply Composer changes: comprehensive API updates, migrations, middleware, and infrastructure improvements
- Add comprehensive database migrations (001-024) for schema evolution
- Enhance API schema with expanded type definitions and resolvers
- Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth
- Implement new services: AI optimization, billing, blockchain, compliance, marketplace
- Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage)
- Update Crossplane provider with enhanced VM management capabilities
- Add comprehensive test suite for API endpoints and services
- Update frontend components with improved GraphQL subscriptions and real-time updates
- Enhance security configurations and headers (CSP, CORS, etc.)
- Update documentation and configuration files
- Add new CI/CD workflows and validation scripts
- Implement design system improvements and UI enhancements
2025-12-12 18:01:35 -08:00

1035 lines
28 KiB
Markdown

# Infrastructure Documentation Dashboard - Complete Implementation Steps
## Overview
This document provides step-by-step implementation instructions for all enhancements, organized by phase and priority. Each step includes specific actions, file paths, code structure, and time estimates.
---
## Phase 1: Critical Foundation (Weeks 1-2) - 80-120 hours
### Step 1.1: Install Dependencies
**Time:** 15 minutes
**Action:** Add required packages to package.json
```bash
npm install html2canvas jspdf xlsx mapbox-gl react-map-gl @tanstack/react-virtual
```
**Files to Modify:**
- `package.json`
**Verification:**
- Run `npm install`
- Verify packages in node_modules
---
### Step 1.2: Create Validation Schemas
**Time:** 2-3 hours
**File:** `src/lib/validation/schemas/infrastructure.ts`
**Implementation Steps:**
1. Import Zod
2. Create `countrySchema`:
```typescript
export const countrySchema = z.object({
name: z.string().min(1),
region: z.enum(['Africa (Sub-Saharan)', 'Middle East & North Africa', 'Americas', 'Asia-Pacific', 'Europe']),
relationshipType: z.enum(['Full Diplomatic Relations', 'Official (Non-Diplomatic)', 'Ambassador Level', 'Full Diplomatic Relations (Special Mission)']),
priority: z.enum(['Critical', 'High', 'Medium', 'Low']),
cloudflareCoverage: z.boolean(),
networkInfrastructurePriority: z.string(),
notes: z.string().optional(),
coordinates: z.object({
lat: z.number().min(-90).max(90),
lng: z.number().min(-180).max(180)
}).optional()
})
```
3. Create `topologyNodeSchema`:
```typescript
export const topologyNodeSchema = z.object({
id: z.string(),
type: z.enum(['region', 'datacenter', 'tunnel', 'vm', 'service']),
label: z.string().min(1),
region: z.string(),
entity: z.string(),
position: z.object({
x: z.number(),
y: z.number()
}),
metadata: z.record(z.any())
})
```
4. Create `topologyEdgeSchema`:
```typescript
export const topologyEdgeSchema = z.object({
id: z.string(),
source: z.string(),
target: z.string(),
type: z.enum(['tunnel', 'peering', 'network-route']),
metadata: z.record(z.any())
})
```
5. Create `networkTopologySchema`:
```typescript
export const networkTopologySchema = z.object({
nodes: z.array(topologyNodeSchema),
edges: z.array(topologyEdgeSchema),
region: z.string(),
entity: z.string(),
lastUpdated: z.string().datetime()
})
```
6. Create `complianceRequirementSchema`:
```typescript
export const complianceRequirementSchema = z.object({
country: z.string().min(1),
region: z.string(),
frameworks: z.array(z.string()).min(1),
status: z.enum(['Compliant', 'Partial', 'Pending', 'Non-Compliant']),
requirements: z.array(z.string()),
lastAuditDate: z.string().datetime().optional(),
notes: z.string().optional()
})
```
7. Create `deploymentMilestoneSchema`:
```typescript
export const deploymentMilestoneSchema = z.object({
id: z.string(),
title: z.string().min(1),
region: z.string(),
entity: z.string(),
priority: z.enum(['Critical', 'High', 'Medium', 'Low']),
startDate: z.string().datetime(),
endDate: z.string().datetime(),
status: z.enum(['Planned', 'In Progress', 'Complete', 'Blocked']),
dependencies: z.array(z.string()).optional(),
cost: z.number().min(0).optional(),
description: z.string().optional()
}).refine((data) => new Date(data.endDate) > new Date(data.startDate), {
message: "End date must be after start date",
path: ["endDate"]
})
```
8. Create `costEstimateSchema`:
```typescript
export const costEstimateSchema = z.object({
region: z.string(),
entity: z.string(),
category: z.enum(['Infrastructure', 'Network', 'Compliance', 'Operations']),
monthly: z.number().min(0),
annual: z.number().min(0),
breakdown: z.object({
compute: z.number().min(0).optional(),
storage: z.number().min(0).optional(),
network: z.number().min(0).optional(),
licenses: z.number().min(0).optional(),
personnel: z.number().min(0).optional()
}),
currency: z.string().optional(),
lastUpdated: z.string().datetime().optional()
}).refine((data) => {
const breakdownSum = (data.breakdown.compute || 0) +
(data.breakdown.storage || 0) +
(data.breakdown.network || 0) +
(data.breakdown.licenses || 0) +
(data.breakdown.personnel || 0)
return Math.abs(breakdownSum - data.monthly) < 0.01
}, {
message: "Breakdown sum must equal monthly cost",
path: ["breakdown"]
})
```
9. Create input schemas for mutations:
- `updateTopologyInputSchema`
- `createMilestoneInputSchema`
- `updateMilestoneInputSchema`
- `updateComplianceInputSchema`
- `updateCostEstimateInputSchema`
10. Export all schemas
**Testing:**
- Test each schema with valid data
- Test each schema with invalid data
- Verify error messages
---
### Step 1.3: Create Data Serving API Route
**Time:** 1-2 hours
**File:** `src/app/api/infrastructure/data/[filename]/route.ts`
**Implementation Steps:**
1. Create route handler:
```typescript
import { NextRequest, NextResponse } from 'next/server'
import * as fs from 'fs'
import * as path from 'path'
export async function GET(
request: NextRequest,
{ params }: { params: { filename: string } }
) {
try {
const filePath = path.join(process.cwd(), 'docs/infrastructure/data', params.filename)
if (!fs.existsSync(filePath)) {
return NextResponse.json(
{ error: 'File not found' },
{ status: 404 }
)
}
const fileContent = fs.readFileSync(filePath, 'utf-8')
const data = JSON.parse(fileContent)
const stats = fs.statSync(filePath)
const response = NextResponse.json({
data,
metadata: {
lastModified: stats.mtime.toISOString(),
filename: params.filename
}
})
// Add caching headers
response.headers.set('ETag', `"${stats.mtime.getTime()}"`)
response.headers.set('Last-Modified', stats.mtime.toUTCString())
response.headers.set('Cache-Control', 'public, max-age=3600')
return response
} catch (error) {
return NextResponse.json(
{ error: 'Failed to load file' },
{ status: 500 }
)
}
}
```
2. Add error handling for invalid JSON
3. Add security checks (prevent directory traversal)
4. Add rate limiting (optional)
5. Test with various filenames
6. Test error cases
**Testing:**
- Test with valid filename
- Test with invalid filename
- Test with missing file
- Test caching headers
---
### Step 1.4: Update Data Loading Hook
**Time:** 2-3 hours
**File:** `src/lib/hooks/useInfrastructureData.ts`
**Implementation Steps:**
1. Import React Query:
```typescript
import { useQuery } from '@tanstack/react-query'
```
2. Update DATA_BASE_PATH:
```typescript
const DATA_BASE_PATH = '/api/infrastructure/data'
```
3. Create data fetcher function:
```typescript
async function fetchJSONData<T>(filename: string): Promise<T[]> {
const response = await fetch(`${DATA_BASE_PATH}/${filename}`)
if (!response.ok) {
throw new Error(`Failed to load ${filename}: ${response.statusText}`)
}
const result = await response.json()
return result.data || []
}
```
4. Update useCountries hook:
```typescript
export function useCountries(filter?: {...}) {
return useQuery({
queryKey: ['countries', filter],
queryFn: () => fetchJSONData<Country>('smom_countries.json'),
staleTime: 5 * 60 * 1000, // 5 minutes
retry: 3,
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000)
})
}
```
5. Apply same pattern to all hooks:
- useNetworkTopologies
- useComplianceRequirements
- useDeploymentMilestones
- useCostEstimates
- useInfrastructureSummary
6. Add filtering logic after data fetch
7. Add error handling
8. Test all hooks
**Testing:**
- Test data loading
- Test filtering
- Test error handling
- Test caching
---
### Step 1.5: Implement Topology PNG Export
**Time:** 1-2 hours
**File:** `src/components/infrastructure/NetworkTopologyDocs.tsx`
**Implementation Steps:**
1. Import html2canvas:
```typescript
import html2canvas from 'html2canvas'
```
2. Add ref to topology container:
```typescript
const topologyRef = useRef<HTMLDivElement>(null)
```
3. Implement handleExportPNG:
```typescript
const handleExportPNG = async () => {
if (!topologyRef.current) return
setExporting(true)
try {
const canvas = await html2canvas(topologyRef.current, {
backgroundColor: '#000000',
scale: 2, // High resolution
logging: false
})
canvas.toBlob((blob) => {
if (!blob) return
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `topology-${selectedRegion}-${Date.now()}.png`
a.click()
URL.revokeObjectURL(url)
toast({
title: 'Export successful',
description: 'Topology exported as PNG',
variant: 'success'
})
}, 'image/png')
} catch (error) {
toast({
title: 'Export failed',
description: error instanceof Error ? error.message : 'Unknown error',
variant: 'error'
})
} finally {
setExporting(false)
}
}
```
4. Add exporting state
5. Add loading indicator to button
6. Test export functionality
**Testing:**
- Test PNG export
- Test with different topologies
- Test error handling
- Verify file download
---
### Step 1.6: Implement Topology SVG Export
**Time:** 1 hour
**File:** `src/components/infrastructure/NetworkTopologyDocs.tsx`
**Implementation Steps:**
1. Implement handleExportSVG:
```typescript
const handleExportSVG = () => {
const svgElement = topologyRef.current?.querySelector('svg')
if (!svgElement) return
try {
const svgData = new XMLSerializer().serializeToString(svgElement)
const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' })
const url = URL.createObjectURL(svgBlob)
const a = document.createElement('a')
a.href = url
a.download = `topology-${selectedRegion}-${Date.now()}.svg`
a.click()
URL.revokeObjectURL(url)
toast({
title: 'Export successful',
description: 'Topology exported as SVG',
variant: 'success'
})
} catch (error) {
toast({
title: 'Export failed',
description: error instanceof Error ? error.message : 'Unknown error',
variant: 'error'
})
}
}
```
2. Test SVG export
3. Verify SVG quality
---
### Step 1.7: Implement Timeline PDF Export
**Time:** 3-4 hours
**File:** `src/components/infrastructure/DeploymentTimeline.tsx`
**Implementation Steps:**
1. Import libraries:
```typescript
import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
```
2. Create handleExportPDF function:
```typescript
const handleExportPDF = async () => {
setExporting(true)
try {
const pdf = new jsPDF('landscape', 'mm', 'a4')
// Page 1: Title and metadata
pdf.setFontSize(20)
pdf.text('Deployment Timeline', 20, 20)
pdf.setFontSize(12)
pdf.text(`Region: ${selectedRegion}`, 20, 30)
pdf.text(`Entity: ${selectedEntity}`, 20, 35)
pdf.text(`Export Date: ${new Date().toLocaleDateString()}`, 20, 40)
// Page 2: Gantt chart
const chartElement = document.getElementById('gantt-chart')
if (chartElement) {
const canvas = await html2canvas(chartElement)
const imgData = canvas.toDataURL('image/png')
pdf.addPage()
pdf.addImage(imgData, 'PNG', 10, 10, 277, 190)
}
// Page 3: Milestone list
pdf.addPage()
pdf.setFontSize(16)
pdf.text('Milestone List', 20, 20)
let y = 30
milestones.forEach((milestone, index) => {
if (y > 270) {
pdf.addPage()
y = 20
}
pdf.setFontSize(12)
pdf.text(`${index + 1}. ${milestone.title}`, 20, y)
pdf.setFontSize(10)
pdf.text(`Status: ${milestone.status} | Priority: ${milestone.priority}`, 20, y + 5)
y += 15
})
pdf.save(`deployment-timeline-${Date.now()}.pdf`)
toast({
title: 'Export successful',
description: 'Timeline exported as PDF',
variant: 'success'
})
} catch (error) {
toast({
title: 'Export failed',
description: error instanceof Error ? error.message : 'Unknown error',
variant: 'error'
})
} finally {
setExporting(false)
}
}
```
3. Add exporting state
4. Test PDF generation
5. Adjust layout and formatting
---
### Step 1.8: Implement Cost Estimates Excel Export
**Time:** 3-4 hours
**File:** `src/components/infrastructure/CostEstimates.tsx`
**Implementation Steps:**
1. Import xlsx:
```typescript
import * as XLSX from 'xlsx'
```
2. Create handleExportExcel function:
```typescript
const handleExportExcel = () => {
try {
const workbook = XLSX.utils.book_new()
// Summary sheet
const summaryData = [
['Total Monthly', (totalMonthly / 1000).toFixed(0) + 'K'],
['Total Annual', (totalAnnual / 1000000).toFixed(1) + 'M'],
['Number of Estimates', estimates.length]
]
const summarySheet = XLSX.utils.aoa_to_sheet(summaryData)
XLSX.utils.book_append_sheet(workbook, summarySheet, 'Summary')
// Detailed breakdown sheet
const detailData = estimates.map(e => ({
Region: e.region,
Entity: e.entity,
Category: e.category,
'Monthly (USD)': e.monthly,
'Annual (USD)': e.annual,
'Compute': e.breakdown.compute || 0,
'Storage': e.breakdown.storage || 0,
'Network': e.breakdown.network || 0,
'Licenses': e.breakdown.licenses || 0,
'Personnel': e.breakdown.personnel || 0
}))
const detailSheet = XLSX.utils.json_to_sheet(detailData)
// Format currency columns
const range = XLSX.utils.decode_range(detailSheet['!ref'] || 'A1')
for (let C = 3; C <= 4; ++C) {
for (let R = 1; R <= range.e.r; ++R) {
const cellAddress = XLSX.utils.encode_cell({ r: R, c: C })
if (!detailSheet[cellAddress]) continue
detailSheet[cellAddress].z = '$#,##0.00'
}
}
XLSX.utils.book_append_sheet(workbook, detailSheet, 'Detailed Breakdown')
// By region sheet
const byRegion = estimates.reduce((acc, e) => {
acc[e.region] = (acc[e.region] || 0) + e.annual
return acc
}, {} as Record<string, number>)
const regionData = Object.entries(byRegion).map(([region, annual]) => ({
Region: region,
'Annual Cost (USD)': annual
}))
const regionSheet = XLSX.utils.json_to_sheet(regionData)
XLSX.utils.book_append_sheet(workbook, regionSheet, 'By Region')
XLSX.writeFile(workbook, `cost-estimates-${Date.now()}.xlsx`)
toast({
title: 'Export successful',
description: 'Cost estimates exported as Excel',
variant: 'success'
})
} catch (error) {
toast({
title: 'Export failed',
description: error instanceof Error ? error.message : 'Unknown error',
variant: 'error'
})
}
}
```
3. Test Excel export
4. Verify formatting
---
### Step 1.9: Create Error Boundary Component
**Time:** 1-2 hours
**File:** `src/components/infrastructure/InfrastructureErrorBoundary.tsx`
**Implementation Steps:**
1. Create error boundary class component:
```typescript
'use client'
import React from 'react'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { AlertTriangle } from 'lucide-react'
interface Props {
children: React.ReactNode
fallback?: React.ComponentType<{ error: Error; reset: () => void }>
}
interface State {
hasError: boolean
error: Error | null
}
export class InfrastructureErrorBoundary extends React.Component<Props, State> {
constructor(props: Props) {
super(props)
this.state = { hasError: false, error: null }
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error }
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('Infrastructure error:', error, errorInfo)
// Log to Sentry if available
if (typeof window !== 'undefined' && (window as any).Sentry) {
(window as any).Sentry.captureException(error, { contexts: { react: errorInfo } })
}
}
reset = () => {
this.setState({ hasError: false, error: null })
}
render() {
if (this.state.hasError) {
if (this.props.fallback) {
const Fallback = this.props.fallback
return <Fallback error={this.state.error!} reset={this.reset} />
}
return (
<Card className="m-4">
<CardHeader>
<div className="flex items-center gap-2">
<AlertTriangle className="h-5 w-5 text-red-400" />
<CardTitle>Something went wrong</CardTitle>
</div>
<CardDescription>
An error occurred while loading infrastructure data
</CardDescription>
</CardHeader>
<CardContent>
{process.env.NODE_ENV === 'development' && this.state.error && (
<pre className="text-sm text-red-400 mb-4">
{this.state.error.message}
{this.state.error.stack}
</pre>
)}
<Button onClick={this.reset}>Try Again</Button>
</CardContent>
</Card>
)
}
return this.props.children
}
}
```
2. Test error boundary
3. Add to all page components
---
### Step 1.10: Wrap Views with Error Boundary
**Time:** 30 minutes
**Files:** All page components
**Implementation:**
1. Import InfrastructureErrorBoundary
2. Wrap each view:
```typescript
export default function TopologyPage() {
return (
<InfrastructureErrorBoundary>
<div className="container mx-auto py-8 px-4">
<NetworkTopologyDocs />
</div>
</InfrastructureErrorBoundary>
)
}
```
---
## Phase 2: Edit Mode Implementation (Weeks 2-3) - 60-80 hours
### Step 2.1: Create Edit Compliance Form
**Time:** 3-4 hours
**File:** `src/components/infrastructure/forms/EditComplianceForm.tsx`
**Implementation Steps:**
1. Create form component structure:
```typescript
'use client'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { useUpdateComplianceRequirement } from '@/lib/graphql/hooks/useInfrastructure'
import { useToast } from '@/components/ui/use-toast'
import { complianceRequirementSchema } from '@/lib/validation/schemas/infrastructure'
import type { ComplianceRequirement } from '@/lib/types/infrastructure'
interface EditComplianceFormProps {
open: boolean
onOpenChange: (open: boolean) => void
requirement: ComplianceRequirement
}
export function EditComplianceForm({ open, onOpenChange, requirement }: EditComplianceFormProps) {
const { updateCompliance, loading, error } = useUpdateComplianceRequirement()
const { toast } = useToast()
const form = useForm<ComplianceRequirement>({
resolver: zodResolver(complianceRequirementSchema),
defaultValues: requirement
})
const onSubmit = async (data: ComplianceRequirement) => {
try {
await updateCompliance({
variables: {
country: requirement.country,
input: {
frameworks: data.frameworks,
status: data.status,
requirements: data.requirements,
lastAuditDate: data.lastAuditDate,
notes: data.notes
}
}
})
toast({
title: 'Success',
description: 'Compliance requirement updated',
variant: 'success'
})
onOpenChange(false)
} catch (err) {
toast({
title: 'Error',
description: err instanceof Error ? err.message : 'Failed to update',
variant: 'error'
})
}
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle>Edit Compliance Requirement</DialogTitle>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="country"
render={({ field }) => (
<FormItem>
<FormLabel>Country</FormLabel>
<FormControl>
<Input {...field} disabled />
</FormControl>
</FormItem>
)}
/>
{/* Add all other fields similarly */}
<DialogFooter>
<Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
Cancel
</Button>
<Button type="submit" disabled={loading}>
{loading ? 'Saving...' : 'Save'}
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
)
}
```
2. Add all form fields with proper types
3. Add multi-select for frameworks
4. Add date picker for lastAuditDate
5. Add textarea for requirements (one per line)
6. Test form validation
7. Test form submission
---
### Step 2.2: Create Edit Milestone Form
**Time:** 4-5 hours
**File:** `src/components/infrastructure/forms/EditMilestoneForm.tsx`
**Implementation Steps:**
1. Create form with all fields
2. Add date range validation
3. Add dependency selector (multi-select of other milestones)
4. Add dependency validation (no circular refs)
5. Add cost field with currency formatting
6. Handle create vs edit modes
7. Show dependency graph preview
8. Test all validations
---
### Step 2.3: Create Edit Cost Estimate Form
**Time:** 3-4 hours
**File:** `src/components/infrastructure/forms/EditCostEstimateForm.tsx`
**Implementation Steps:**
1. Create form with cost fields
2. Add auto-calculation (monthly * 12 = annual)
3. Add breakdown fields
4. Add validation (breakdown sum = monthly)
5. Add currency selector
6. Test calculations
7. Test validation
---
### Step 2.4: Create Edit Topology Node Form
**Time:** 3-4 hours
**File:** `src/components/infrastructure/forms/EditTopologyNodeForm.tsx`
**Implementation Steps:**
1. Create form with node fields
2. Add position X/Y fields
3. Add metadata editor (JSON or key-value)
4. Add validation (unique label, valid coordinates)
5. Integrate with topology update
6. Test node editing
---
### Step 2.5: Wire Up Edit Forms
**Time:** 2-3 hours per component
**Files:** All infrastructure component files
**Implementation Steps:**
1. Import form components
2. Add state for dialog open/close
3. Add state for item being edited
4. Connect edit buttons:
```typescript
<Button onClick={() => {
setEditingItem(requirement)
setDialogOpen(true)
}}>
Edit
</Button>
```
5. Add form component:
```typescript
<EditComplianceForm
open={dialogOpen}
onOpenChange={setDialogOpen}
requirement={editingItem!}
/>
```
6. Refresh data after successful edit
7. Test edit workflow
---
### Step 2.6: Implement Topology Edit Mode
**Time:** 6-8 hours
**File:** `src/components/infrastructure/NetworkTopologyDocs.tsx`
**Implementation Steps:**
1. Add edit mode state management
2. Implement node dragging:
```typescript
const onNodeDrag = useCallback((event: NodeDragEvent, node: Node) => {
// Update node position in state
setTopology(prev => ({
...prev,
nodes: prev.nodes.map(n =>
n.id === node.id
? { ...n, position: { x: node.position.x, y: node.position.y } }
: n
)
}))
}, [])
```
3. Add "Add Node" button and dialog
4. Implement edge creation (click source, then target)
5. Add delete functionality
6. Add context menu
7. Implement bulk selection
8. Add save button
9. Integrate with mutation
10. Add undo/redo
---
### Step 2.7: Implement Timeline Drag-and-Drop
**Time:** 4-5 hours
**File:** `src/components/infrastructure/DeploymentTimeline.tsx`
**Implementation Steps:**
1. Set up @dnd-kit:
```typescript
import { DndContext, DragEndEvent } from '@dnd-kit/core'
import { SortableContext, useSortable } from '@dnd-kit/sortable'
```
2. Make milestones draggable
3. Implement drop handler
4. Validate date constraints
5. Check dependencies
6. Auto-save on drop
7. Show loading state
---
## Phase 3: React Flow Integration (Week 3) - 20-25 hours
### Step 3.1: Create React Flow Topology Component
**Time:** 4-5 hours
**File:** `src/components/infrastructure/topology/ReactFlowTopology.tsx`
**Implementation Steps:**
1. Import React Flow:
```typescript
import ReactFlow, {
Background,
Controls,
MiniMap,
Node,
Edge,
Connection,
useNodesState,
useEdgesState,
addEdge,
onNodesChange,
onEdgesChange
} from 'reactflow'
import 'reactflow/dist/style.css'
```
2. Convert topology data:
```typescript
const nodes: Node[] = topology.nodes.map(node => ({
id: node.id,
type: node.type,
position: node.position,
data: { label: node.label, ...node.metadata }
}))
const edges: Edge[] = topology.edges.map(edge => ({
id: edge.id,
source: edge.source,
target: edge.target,
type: edge.type,
label: edge.metadata.bandwidth || edge.type
}))
```
3. Set up React Flow component
4. Add minimap and controls
5. Add background grid
6. Implement zoom/pan
7. Add fit view
---
### Step 3.2-3.4: Create Custom Nodes and Edges
**Time:** 8-10 hours
**Files:** Multiple files
**Implementation Steps:**
1. Create base node component
2. Create specialized nodes (5 files)
3. Create custom edge component
4. Register node/edge types
5. Integrate into main component
6. Test all node types
7. Test edit mode with React Flow
---
## Phase 4: Map Visualization (Week 4) - 8-10 hours
### Step 4.1-4.3: Mapbox Integration
**Time:** 8-10 hours
**Files:** Multiple files
**Implementation Steps:**
1. Set up Mapbox token
2. Create ComplianceMapView component
3. Load country coordinates
4. Create markers
5. Add popups
6. Implement clustering
7. Add layer controls
8. Integrate into compliance component
---
## Phase 5-8: Additional Phases
(Continue with similar detailed steps for remaining phases...)
---
## Testing Checklist
After each phase, test:
- [ ] All exports work correctly
- [ ] Forms validate properly
- [ ] Mutations succeed and update UI
- [ ] Error handling works
- [ ] Loading states display
- [ ] Empty states display
- [ ] Filters work correctly
- [ ] No console errors
- [ ] Responsive design works
- [ ] Accessibility features work
---
## Deployment Checklist
Before deploying:
- [ ] All dependencies installed
- [ ] Environment variables set
- [ ] API routes tested
- [ ] Error boundaries tested
- [ ] Performance tested
- [ ] Security reviewed
- [ ] Documentation complete
- [ ] Tests passing