# Sites & Site Builder Removal Guide

**Version:** 1.0  
**Date:** November 29, 2025  
**Purpose:** Complete guide to remove separate sites/site-builder containers and integrate functionality into main frontend app

---

## Executive Summary

This document provides a **safe, step-by-step process** to:
1. Remove the `/sites/` container and folder
2. Remove the `/site-builder/` folder (already empty/deprecated)
3. Integrate Sites Renderer and Site Builder features into the main `/frontend/` application
4. Update all affected components, configurations, and documentation

**Current State:**
- 3 separate containers: `igny8_frontend`, `igny8_sites`, `igny8_marketing_dev`
- Site Builder UI in separate `/sites/` container (port 8024)
- Sites Renderer in separate `/sites/` container (port 8024)

**Target State:**
- 2 containers: `igny8_frontend`, `igny8_marketing_dev`
- Site Builder UI integrated into main frontend
- Sites Renderer integrated into main frontend
- Single unified application on port 8021

---

## Impact Analysis

### Features That Will Be Affected

#### 1. **Site Blueprint Management** (Site Builder)
**Current Location:** `/sites/src/builder/`  
**Current Routes:** `/builder/*` (separate container)  
**Functionality:**
- Site structure wizard
- Blueprint creation and management
- Preview canvas for site layouts
- Blueprint history dashboard

**Backend Dependencies:**
- API: `/api/v1/site-builder/blueprints/`
- Module: `backend/igny8_core/modules/site_builder/`
- Business Logic: `backend/igny8_core/business/site_building/`

**Impact:** Medium - Needs route integration into main app

---

#### 2. **Sites Renderer** (Public Site Viewing)
**Current Location:** `/sites/src/pages/SiteRenderer.tsx`  
**Current Routes:** `/:siteSlug/:pageSlug?` (separate container)  
**Functionality:**
- Loads site definitions from `/data/app/sites-data/`
- Renders published sites for public viewing
- No authentication required

**Backend Dependencies:**
- API: `/api/v1/publisher/sites/{site_id}/definition/`
- Service: `backend/igny8_core/business/publishing/services/adapters/sites_renderer_adapter.py`
- Data: `/data/app/sites-data/clients/{site_id}/v{version}/`

**Impact:** High - Public-facing feature, needs careful route handling

---

#### 3. **Backend Modules** (Keep These)
**Modules to Keep:**
```
backend/igny8_core/
├── modules/
│   ├── site_builder/        ✅ KEEP (API endpoints)
│   └── publisher/           ✅ KEEP (publishing logic)
└── business/
    ├── site_building/       ✅ KEEP (business logic)
    └── publishing/          ✅ KEEP (renderer adapter)
```

**Rationale:** Backend functionality is used by the main frontend app, just changing the UI container.

---

## Removal & Integration Plan

### Phase 1: Preparation & Backup

#### Step 1.1: Create Backup
```bash
# Backup current state
cd /data/app/igny8
tar -czf backup-sites-$(date +%Y%m%d-%H%M%S).tar.gz sites/ site-builder/

# Backup docker-compose
cp docker-compose.app.yml docker-compose.app.yml.backup

# Verify backup
ls -lh backup-sites-*.tar.gz
```

#### Step 1.2: Document Current Routes
```bash
# Document current running containers
docker ps | grep igny8 > current-containers.txt

# Test current site builder access
curl -I http://localhost:8024/builder/

# Test current sites renderer
curl -I http://localhost:8024/
```

---

### Phase 2: Frontend Integration

#### Step 2.1: Copy Site Builder Components to Frontend

**Source:** `/sites/src/builder/`  
**Destination:** `/frontend/src/pages/Sites/`

```bash
cd /data/app/igny8

# Create target directory
mkdir -p frontend/src/pages/Sites/Builder

# Copy builder components
cp -r sites/src/builder/pages/* frontend/src/pages/Sites/Builder/
cp -r sites/src/builder/components/* frontend/src/components/sites/builder/

# Copy shared types if needed
cp sites/src/types/index.ts frontend/src/types/siteBuilder.types.ts
```

**Files to Copy:**
```
sites/src/builder/
├── pages/
│   ├── wizard/
│   │   └── WizardPage.tsx           → frontend/src/pages/Sites/Builder/Wizard.tsx
│   ├── preview/
│   │   └── PreviewCanvas.tsx        → frontend/src/pages/Sites/Builder/Preview.tsx
│   └── dashboard/
│       └── SiteDashboard.tsx        → frontend/src/pages/Sites/Builder/Dashboard.tsx
└── components/
    └── layout/
        └── BuilderLayout.tsx        → frontend/src/components/sites/BuilderLayout.tsx
```

---

#### Step 2.2: Copy Sites Renderer to Frontend

**Source:** `/sites/src/pages/SiteRenderer.tsx`  
**Destination:** `/frontend/src/pages/Sites/`

```bash
# Copy renderer components
cp sites/src/pages/SiteRenderer.tsx frontend/src/pages/Sites/PublicSiteRenderer.tsx
cp sites/src/loaders/loadSiteDefinition.ts frontend/src/services/siteRenderer.api.ts
cp -r sites/src/utils/* frontend/src/utils/siteRenderer/
```

**Files to Copy:**
```
sites/src/
├── pages/
│   └── SiteRenderer.tsx             → frontend/src/pages/Sites/PublicSiteRenderer.tsx
├── loaders/
│   └── loadSiteDefinition.ts        → frontend/src/services/siteRenderer.api.ts
└── utils/
    ├── layoutRenderer.tsx           → frontend/src/utils/siteRenderer/layoutRenderer.tsx
    ├── pageTypeRenderer.tsx         → frontend/src/utils/siteRenderer/pageTypeRenderer.tsx
    └── templateEngine.tsx           → frontend/src/utils/siteRenderer/templateEngine.tsx
```

---

#### Step 2.3: Update Frontend Routes

**File:** `/frontend/src/App.tsx`

**Add these imports:**
```tsx
// Site Builder pages
const SiteBuilderWizard = lazy(() => import("./pages/Sites/Builder/Wizard"));
const SiteBuilderPreview = lazy(() => import("./pages/Sites/Builder/Preview"));
const SiteBuilderDashboard = lazy(() => import("./pages/Sites/Builder/Dashboard"));

// Public Sites Renderer
const PublicSiteRenderer = lazy(() => import("./pages/Sites/PublicSiteRenderer"));
```

**Add these routes:**
```tsx
{/* Site Builder Routes - Protected */}
<Route
  path="/sites/builder"
  element={
    <ProtectedRoute>
      <ModuleGuard module="site_builder">
        <SiteBuilderWizard />
      </ModuleGuard>
    </ProtectedRoute>
  }
/>
<Route
  path="/sites/builder/preview"
  element={
    <ProtectedRoute>
      <ModuleGuard module="site_builder">
        <SiteBuilderPreview />
      </ModuleGuard>
    </ProtectedRoute>
  }
/>
<Route
  path="/sites/builder/dashboard"
  element={
    <ProtectedRoute>
      <ModuleGuard module="site_builder">
        <SiteBuilderDashboard />
      </ModuleGuard>
    </ProtectedRoute>
  }
/>

{/* Public Sites Renderer - No Auth Required */}
<Route path="/sites/view/:siteSlug/:pageSlug?" element={<PublicSiteRenderer />} />
```

**Note:** Public renderer routes changed from `/:siteSlug/*` to `/sites/view/:siteSlug/*` to avoid route conflicts.

---

#### Step 2.4: Update API Client for Sites Data

**File:** `/frontend/src/services/siteRenderer.api.ts`

**Update the API URL resolution:**
```typescript
function getApiBaseUrl(): string {
  // Use environment variable
  const envUrl = import.meta.env.VITE_API_URL || import.meta.env.VITE_BACKEND_URL;
  if (envUrl) {
    return envUrl.endsWith('/api') ? envUrl : `${envUrl}/api`;
  }
  
  // Auto-detect based on current origin
  if (typeof window !== 'undefined') {
    const origin = window.location.origin;
    
    // If accessing via IP, use backend port 8011
    if (/^\d+\.\d+\.\d+\.\d+/.test(origin) || origin.includes('localhost')) {
      return origin.replace(':8021', ':8011') + '/api';
    }
  }
  
  // Production: use subdomain
  return 'https://api.igny8.com/api';
}
```

---

#### Step 2.5: Update Navigation Menu

**File:** `/frontend/src/components/sidebar/AppSidebar.tsx` or navigation component

**Add Site Builder menu item:**
```tsx
{
  title: "Site Builder",
  icon: <LayoutGrid className="h-5 w-5" />,
  items: [
    { title: "New Blueprint", path: "/sites/builder" },
    { title: "Preview", path: "/sites/builder/preview" },
    { title: "History", path: "/sites/builder/dashboard" },
  ],
}
```

---

### Phase 3: Docker Configuration Updates

#### Step 3.1: Update docker-compose.app.yml

**File:** `/docker-compose.app.yml`

**Remove the igny8_sites service:**
```yaml
# REMOVE THIS ENTIRE SERVICE:
  # igny8_sites:
  #   image: igny8-sites-dev:latest
  #   container_name: igny8_sites
  #   restart: always
  #   ports:
  #     - "0.0.0.0:8024:5176"
  #   environment:
  #     VITE_API_URL: "https://api.igny8.com/api"
  #     SITES_DATA_PATH: "/sites"
  #   volumes:
  #     - /data/app/igny8/sites:/app:rw
  #     - /data/app/sites-data:/sites:ro
  #     - /data/app/igny8/frontend:/frontend:ro
  #   networks: [igny8_net]
```

**Update igny8_frontend service to access sites-data:**
```yaml
  igny8_frontend:
    image: igny8-frontend-dev:latest
    container_name: igny8_frontend
    restart: always
    ports:
      - "0.0.0.0:8021:5173"
    environment:
      VITE_BACKEND_URL: "https://api.igny8.com/api"
      SITES_DATA_PATH: "/sites"  # ADD THIS
    volumes:      
      - /data/app/igny8/frontend:/app:rw
      - /data/app/sites-data:/sites:ro  # ADD THIS - Read-only access to sites data
    depends_on:
      igny8_backend:
        condition: service_healthy
    networks: [igny8_net]
```

---

#### Step 3.2: Update Vite Configuration

**File:** `/frontend/vite.config.ts`

**Add environment variable for sites data path:**
```typescript
export default defineConfig({
  // ... existing config
  define: {
    'import.meta.env.SITES_DATA_PATH': JSON.stringify(
      process.env.SITES_DATA_PATH || '/sites'
    ),
  },
  // ... rest of config
});
```

---

### Phase 4: Backend Updates (Minor)

#### Step 4.1: Update CORS Settings (if needed)

**File:** `/backend/igny8_core/settings.py`

**Verify CORS allows frontend port:**
```python
CORS_ALLOWED_ORIGINS = [
    'http://localhost:5173',  # Frontend dev server
    'http://localhost:8021',  # Frontend external port
    'https://app.igny8.com',
    # Remove: 'http://localhost:8024',  # Old sites container
]
```

---

#### Step 4.2: Update Site Definition API (Optional Enhancement)

**File:** `/backend/igny8_core/modules/publisher/views.py`

**No changes required** - API already works, just being called from different container.

**Optional:** Add CORS header for public site renderer if needed:
```python
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny

@api_view(['GET'])
@permission_classes([AllowAny])  # Public endpoint
def get_site_definition(request, site_id):
    # ... existing code
```

---

### Phase 5: Testing & Verification

#### Step 5.1: Build Updated Frontend
```bash
cd /data/app/igny8/frontend

# Install any new dependencies (if added)
npm install

# Build to verify no errors
npm run build

# Rebuild Docker image
cd /data/app/igny8/frontend
docker build -t igny8-frontend-dev:latest -f Dockerfile.dev .
```

---

#### Step 5.2: Stop Old Container
```bash
# Stop and remove sites container
docker stop igny8_sites
docker rm igny8_sites

# Verify it's stopped
docker ps | grep sites
```

---

#### Step 5.3: Start Updated Stack
```bash
cd /data/app/igny8

# Start with updated docker-compose
docker compose -f docker-compose.app.yml up -d igny8_frontend

# Check logs
docker logs -f igny8_frontend
```

---

#### Step 5.4: Test Functionality

**Test Site Builder:**
```bash
# Test builder routes (should require auth)
curl -I http://localhost:8021/sites/builder

# Test in browser:
# http://localhost:8021/sites/builder (wizard)
# http://localhost:8021/sites/builder/preview
# http://localhost:8021/sites/builder/dashboard
```

**Test Sites Renderer:**
```bash
# Test public site renderer
curl -I http://localhost:8021/sites/view/test-site

# Test in browser:
# http://localhost:8021/sites/view/{siteSlug}
# http://localhost:8021/sites/view/{siteSlug}/{pageSlug}
```

**Test Existing API:**
```bash
# Verify site builder API still works
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8011/api/v1/site-builder/blueprints/

# Verify site definition API
curl http://localhost:8011/api/v1/publisher/sites/1/definition/
```

---

### Phase 6: Cleanup

#### Step 6.1: Remove Folders (After Verification)

**Only after confirming everything works:**
```bash
cd /data/app/igny8

# Remove sites folder
rm -rf sites/

# Remove site-builder folder (already empty)
rm -rf site-builder/

# Remove empty frontend module
rm -rf frontend/src/modules/siteBuilder/

# Verify removal
ls -la | grep -E "site-builder|sites"
```

---

#### Step 6.2: Remove Docker Image (Optional)
```bash
# Remove unused sites image
docker rmi igny8-sites-dev:latest

# Verify
docker images | grep sites
```

---

#### Step 6.3: Clean Up Build Instructions

**File:** `/docker-compose.app.yml` (comments at top)

**Remove this line:**
```yaml
# Remove:
#   cd /data/app/igny8/sites && docker build -t igny8-sites-dev:latest -f Dockerfile.dev .
```

---

### Phase 7: Update Documentation

#### Step 7.1: Update Files List

**Files to update:**

1. **README.md**
   - Remove references to `/sites/` container
   - Update port mapping (remove 8024)
   - Update build instructions

2. **CHANGELOG.md**
   - Add entry: "Merged Sites & Site Builder into main frontend app"

3. **docs/MASTER_REFERENCE.md**
   - Update architecture diagram
   - Remove igny8_sites container reference
   - Update route documentation

4. **docs/API-COMPLETE-REFERENCE.md**
   - Update base URLs if needed
   - Verify endpoint documentation

---

#### Step 7.2: Update Architecture Diagram

**In MASTER_REFERENCE.md, update:**

**OLD:**
```
┌──────────────────┐    ┌──────────────────┐    ┌──────────────────┐
│  Frontend (8021) │    │  Sites (8024)    │    │  Backend (8011)  │
└──────────────────┘    └──────────────────┘    └──────────────────┘
```

**NEW:**
```
┌──────────────────┐    ┌──────────────────┐
│  Frontend (8021) │    │  Backend (8011)  │
│  - Main App      │    │  - Django API    │
│  - Site Builder  │    │  - Celery        │
│  - Site Renderer │    │                  │
└──────────────────┘    └──────────────────┘
```

---

## Files & Folders Impact Summary

### Files to Modify

| File | Action | Reason |
|------|--------|--------|
| `/frontend/src/App.tsx` | **UPDATE** | Add site builder and renderer routes |
| `/frontend/src/services/siteRenderer.api.ts` | **CREATE** | Site renderer API client |
| `/frontend/src/pages/Sites/Builder/` | **CREATE** | Copy from sites/src/builder/ |
| `/frontend/src/components/sites/builder/` | **CREATE** | Builder components |
| `/frontend/vite.config.ts` | **UPDATE** | Add SITES_DATA_PATH env var |
| `/docker-compose.app.yml` | **UPDATE** | Remove igny8_sites service |
| `/backend/igny8_core/settings.py` | **VERIFY** | CORS settings (minor) |
| `/README.md` | **UPDATE** | Architecture docs |
| `/docs/MASTER_REFERENCE.md` | **UPDATE** | Remove sites container refs |

---

### Files to Delete (After Verification)

| File/Folder | Safe to Delete | Notes |
|-------------|----------------|-------|
| `/sites/` | ✅ YES | After copying to frontend |
| `/site-builder/` | ✅ YES | Already empty |
| `/frontend/src/modules/siteBuilder/` | ✅ YES | Empty folders |
| `docker-compose.app.yml.backup` | ✅ YES | After successful migration |
| `backup-sites-*.tar.gz` | ⚠️ KEEP | Keep for 30 days as rollback |

---

### Backend Files - NO CHANGES NEEDED

**These stay exactly as they are:**
```
backend/igny8_core/
├── modules/
│   ├── site_builder/          ✅ KEEP - No changes
│   └── publisher/             ✅ KEEP - No changes
├── business/
│   ├── site_building/         ✅ KEEP - No changes
│   └── publishing/            ✅ KEEP - No changes
└── api/
    └── wordpress_publishing.py ✅ KEEP - No changes
```

**Rationale:** Backend APIs remain unchanged; only the frontend UI container changes.

---

## Rollback Plan

If issues occur, rollback is simple:

### Option 1: Quick Rollback (Docker)
```bash
# Restore backup docker-compose
cp docker-compose.app.yml.backup docker-compose.app.yml

# Restart sites container
docker compose -f docker-compose.app.yml up -d igny8_sites

# Verify
docker ps | grep sites
curl -I http://localhost:8024/
```

---

### Option 2: Full Rollback (Restore Files)
```bash
# Extract backup
cd /data/app/igny8
tar -xzf backup-sites-YYYYMMDD-HHMMSS.tar.gz

# Rebuild image
cd sites
docker build -t igny8-sites-dev:latest -f Dockerfile.dev .

# Restart
docker compose -f docker-compose.app.yml up -d igny8_sites
```

---

## Migration Checklist

**Pre-Migration:**
- [ ] Backup `/sites/` folder
- [ ] Backup `/docker-compose.app.yml`
- [ ] Document current container ports
- [ ] Test current site builder functionality
- [ ] Test current sites renderer functionality

**Migration Steps:**
- [ ] Copy site builder components to `/frontend/src/pages/Sites/Builder/`
- [ ] Copy sites renderer to `/frontend/src/pages/Sites/PublicSiteRenderer.tsx`
- [ ] Copy utilities to `/frontend/src/utils/siteRenderer/`
- [ ] Update `/frontend/src/App.tsx` with new routes
- [ ] Create `/frontend/src/services/siteRenderer.api.ts`
- [ ] Update `/frontend/vite.config.ts`
- [ ] Update `/docker-compose.app.yml` (remove igny8_sites, update igny8_frontend)
- [ ] Rebuild frontend Docker image
- [ ] Stop igny8_sites container
- [ ] Start updated igny8_frontend container

**Testing:**
- [ ] Test site builder wizard at `/sites/builder`
- [ ] Test site builder preview at `/sites/builder/preview`
- [ ] Test site builder dashboard at `/sites/builder/dashboard`
- [ ] Test public site renderer at `/sites/view/{siteSlug}`
- [ ] Verify API calls work from frontend
- [ ] Check browser console for errors
- [ ] Test with authenticated user
- [ ] Test without authentication (public renderer)

**Post-Migration:**
- [ ] Verify all tests pass
- [ ] Update documentation (README, MASTER_REFERENCE)
- [ ] Remove `/sites/` folder
- [ ] Remove `/site-builder/` folder
- [ ] Remove empty `/frontend/src/modules/siteBuilder/`
- [ ] Remove Docker image `igny8-sites-dev:latest`
- [ ] Keep backup for 30 days
- [ ] Update portable package documentation

---

## FAQ

### Q: Will this break existing site blueprints?
**A:** No. Backend database and APIs remain unchanged. Only the UI container changes.

### Q: What about published sites in `/data/app/sites-data/`?
**A:** They remain accessible. The frontend will mount `/sites-data` and load from there.

### Q: Do I need to update WordPress integration?
**A:** No. WordPress talks to backend API, which doesn't change.

### Q: What if I want to keep sites as separate container?
**A:** Keep current setup. This migration is optional for simplification.

### Q: Will public site URLs change?
**A:** Yes, from `http://localhost:8024/:siteSlug` to `http://localhost:8021/sites/view/:siteSlug`. Update any hardcoded links.

### Q: Can I run both containers during transition?
**A:** Yes, for testing. Run sites on 8024 and updated frontend on 8021, compare functionality.

---

## Support & Troubleshooting

### Issue: Routes not working after migration
**Solution:** Check route order in `App.tsx`. Public renderer routes should be after protected routes.

### Issue: API calls failing
**Solution:** Verify `VITE_BACKEND_URL` in environment and check CORS settings.

### Issue: Sites data not loading
**Solution:** Verify `/data/app/sites-data` is mounted in docker-compose frontend service.

### Issue: Build errors
**Solution:** Run `npm install` to ensure dependencies match between sites and frontend.

---

## Timeline Estimate

| Phase | Time | Complexity |
|-------|------|------------|
| Phase 1: Preparation | 30 min | Low |
| Phase 2: Frontend Integration | 2-3 hours | Medium |
| Phase 3: Docker Updates | 30 min | Low |
| Phase 4: Backend Updates | 15 min | Low |
| Phase 5: Testing | 1-2 hours | Medium |
| Phase 6: Cleanup | 15 min | Low |
| Phase 7: Documentation | 1 hour | Low |
| **Total** | **5-7 hours** | **Medium** |

---

**End of Document**
