# IGNY8 Phase 0: GitHub Repository Consolidation ## Document 00A: Complete GitHub Repo Consolidation Strategy **Document Version:** 1.1 **Last Updated:** 2026-03-23 **Status:** In Development **Phase:** Phase 0 - Infrastructure Setup **Priority:** High (blocking all other development) **Source of Truth:** Codebase at `/data/app/igny8/` --- ## 1. Current State ### 1.1 Existing Repository Architecture #### Remote Repositories - **Gitea Instance (Legacy):** - URL: Running on old VPS (details in deployment configs) - Repositories hosted: `igny8-stack`, `igny8-app`, WordPress plugin repository - Status: To be decommissioned (see 00E-legacy-cleanup.md) - Risk: Single point of failure, no public visibility, backup dependency - **GitHub Account:** - Status: Created but empty or sparsely populated - Current repos: None or minimal presence - Status: Target consolidation destination #### Local Repository State - **Source-Codes Folder:** `/mnt/Source-Codes/` (EcoSystem structure) - Igny8/ subfolder (may contain working copies or submodules) - Structure not yet standardized across all repos - **Docker-based Development:** - `igny8-stack` contains Dockerfile, docker-compose.yml, infrastructure configs - `igny8-app` contains Django/React application code - Both typically cloned/mounted in development containers ### 1.2 Current Stack Versions (Verified from codebase) ``` Backend: Django >=5.2.7 (requirements.txt), Python 3.11-slim (Dockerfile) Frontend: React ^19.0.0, TypeScript ~5.7.2, Vite ^6.1.0, Node 18-alpine (Dockerfile.dev) Database: PostgreSQL (external container, version set by infra stack) Cache: Redis (external container, version set by infra stack) Proxy: Caddy 2 (external container) Task Queue: Celery >=5.3.0 (requirements.txt) State: Zustand ^5.0.8 CSS: Tailwind ^4.0.8 Orchestration: Docker Compose External Network: igny8_net ``` ### 1.3 Security Issues to Address - Sensitive data (.env files, API keys) currently in Gitea or local clones - No standardized .gitignore across all repos - No GitHub Secrets configuration - No branch protection rules - Missing documentation on secret management workflow ### 1.4 GitHub Access Requirements - GitHub personal access token (PAT) needed for setup - Repository admin permissions required - GitHub Actions enabled for CI/CD (if implementing) - SSH keys configured for local git operations (optional, recommended) --- ## 2. What to Build ### 2.1 End-State Architecture ``` GitHub Account: [organization/user account] ├── igny8-stack/ (Infrastructure & Docker configs) ├── igny8-app/ (Django backend + React frontend) ├── igny8-wordpress-plugin/ (WordPress integration plugin) └── [any other scattered repos consolidated here] EcoSystem File Structure: /mnt/Source-Codes/Igny8/ ├── igny8-stack/ (git working copy, linked to GitHub) ├── igny8-app/ (git working copy, linked to GitHub) ├── igny8-wordpress-plugin/ (git working copy, linked to GitHub) └── .git-config/ (Shared git configuration) GitHub Configuration: - Branch strategy: main (production) → staging → feature/* (development) - Branch protection on main: require PR reviews, status checks - Secrets management: GitHub Secrets for .env values - CI/CD: GitHub Actions workflows (basic setup) - Documentation: README.md in each repo, centralized docs in IGNY8 wiki ``` ### 2.2 Detailed Objectives 1. **Consolidate all IGNY8 repositories to single GitHub account** - Identify all existing repos (Gitea + scattered locations) - Migrate repositories with full history (git fast-export/import) - Verify all commits, branches, and tags preserved 2. **Set up proper branch strategy** - `main`: production-ready code, protected branch - `staging`: staging/QA environment code - `feature/*`: feature development branches - Establish merge workflow (feature → staging → main) 3. **Link GitHub repos to EcoSystem Source-Codes/ structure** - Create standardized directory layout - Configure git remotes properly - Ensure all team members can clone with correct setup 4. **Implement GitHub security & configuration** - Branch protection rules (main branch) - Code review requirements (PRs) - GitHub Secrets for sensitive environment variables - .gitignore standardization (no .env, secrets, large binaries) - CODEOWNERS file for automatic reviewer assignment 5. **Remove Gitea dependency** - Decommission Gitea container (handled in 00E) - Verify all data migrated to GitHub - Archive old backup if needed 6. **GitHub Actions CI/CD (optional, recommended)** - Basic linting workflows - Test execution on push/PR - Docker build validation - Automated deployments (optional for Phase 1) 7. **Documentation** - README.md in each repo with setup instructions - CONTRIBUTING.md with branch strategy and PR workflow - DEVELOPMENT.md with environment setup guide - GitHub wiki for team documentation ### 2.3 Out of Scope (Phase 1+) - Advanced CI/CD pipelines (covered in Phase 1) - Automated deployments to staging/production - Security scanning/SAST tools integration - Release automation and versioning strategy - Multi-environment configuration (covered in Phase 2) --- ## 3. Data Models / APIs ### 3.1 Repository Structure Definition #### igny8-stack Repository ``` igny8-stack/ ├── .github/ │ ├── workflows/ # GitHub Actions workflows │ │ ├── lint.yml │ │ └── docker-build.yml │ └── CODEOWNERS # Automatic reviewer assignment ├── docker/ │ ├── Dockerfile.backend # Django application │ ├── Dockerfile.frontend # React application │ ├── Dockerfile.nginx # Reverse proxy (if applicable) │ └── entrypoint.sh ├── docker-compose.yml # Main orchestration file ├── docker-compose.override.yml # Development overrides ├── nginx/ # Caddy/Nginx configurations │ ├── Caddyfile │ ├── default.conf │ └── ssl/ ├── postgres/ │ ├── init-db.sql # Database initialization │ └── backup/ # (not in git, see .gitignore) ├── redis/ │ └── redis.conf ├── scripts/ │ ├── start-dev.sh # Development startup │ ├── start-prod.sh # Production startup │ ├── backup-db.sh # Database backup script │ └── migrate-repos.sh # Migration helper (in this doc) ├── docs/ │ ├── ARCHITECTURE.md │ ├── SETUP.md │ └── DEPLOYMENT.md ├── .gitignore # Strict: excludes all .env files ├── .dockerignore # Prevents including secrets in images ├── README.md # Project overview ├── CONTRIBUTING.md # Contribution guidelines ├── LICENSE # MIT or appropriate license └── VERSION # Version tracking file (optional) ``` #### igny8-app Repository ``` igny8-app/ ├── .github/ │ ├── workflows/ │ │ ├── test-backend.yml # Django/pytest │ │ ├── test-frontend.yml # React/jest │ │ └── lint.yml │ └── CODEOWNERS ├── backend/ │ ├── igny8/ # Django project package │ │ ├── settings/ │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── dev.py # Development settings │ │ │ ├── staging.py # Staging settings │ │ │ └── production.py # Production settings │ │ ├── urls.py │ │ ├── wsgi.py │ │ └── asgi.py │ ├── apps/ # Django apps │ │ ├── api/ │ │ ├── auth/ │ │ ├── core/ │ │ └── [other apps]/ │ ├── tests/ # Test suite │ ├── requirements.txt # Python dependencies │ ├── requirements-dev.txt # Development dependencies │ ├── manage.py │ └── pytest.ini ├── frontend/ │ ├── src/ │ │ ├── components/ │ │ ├── pages/ │ │ ├── hooks/ │ │ ├── services/ │ │ ├── App.jsx │ │ └── index.jsx │ ├── public/ │ ├── tests/ # Jest tests │ ├── package.json │ ├── package-lock.json │ ├── vite.config.js │ ├── tailwind.config.js # If using Tailwind CSS │ └── .eslintrc.json ├── docs/ │ ├── API.md │ ├── DATABASE_SCHEMA.md │ └── COMPONENT_LIBRARY.md ├── .gitignore # Strict: excludes .env, node_modules, etc. ├── .dockerignore ├── README.md ├── CONTRIBUTING.md ├── DEVELOPMENT.md # Setup local dev environment └── LICENSE ``` #### igny8-wordpress-plugin Repository ``` igny8-wordpress-plugin/ ├── igny8-plugin.php # Main plugin file ├── includes/ │ ├── class-igny8-api.php │ ├── class-igny8-settings.php │ └── [other classes]/ ├── admin/ │ ├── partials/ │ └── [admin UI]/ ├── public/ │ ├── css/ │ ├── js/ │ └── [public assets]/ ├── tests/ │ └── [WordPress plugin tests]/ ├── readme.txt # WordPress plugin readme ├── .gitignore ├── README.md ├── CONTRIBUTING.md └── LICENSE ``` ### 3.2 .gitignore Template (all repos) **File: .gitignore** (standardized across all repos) ```plaintext # Environment variables - NEVER commit secrets .env .env.local .env.*.local .env.production.local # IDE and editor files .vscode/ .idea/ *.swp *.swo *.swn *~ .DS_Store *.sublime-project *.sublime-workspace # Backend (Python/Django) __pycache__/ *.py[cod] *$py.class *.so .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST .venv/ venv/ ENV/ env/ .mypy_cache/ .dmypy.json dmypy.json .pyre/ .pytest_cache/ # Frontend (Node/React) node_modules/ npm-debug.log* yarn-debug.log* yarn-error.log* .pnpm-debug.log* dist/ build/ .next/ out/ # Docker .dockerignore docker-compose.override.yml (local development only) # Database files *.sqlite3 *.db postgres_data/ pgdata/ # Logs *.log logs/ # OS files Thumbs.db .DS_Store # Sensitive data secrets/ .aws/credentials .credentials *.pem *.key private/ # Large files / binaries (use Git LFS if needed) *.zip *.tar.gz *.rar # Cache and temp .cache/ tmp/ temp/ ``` ### 3.3 GitHub Secrets Configuration Secrets to be configured in GitHub (Settings → Secrets and variables → Actions): ```yaml # Backend Database DB_HOST: "postgres" DB_PORT: "5432" DB_NAME: "igny8_db" DB_USER: "igny8_user" DB_PASSWORD: "[SECURE - set in UI]" # Django Security DJANGO_SECRET_KEY: "[SECURE - set in UI]" DEBUG: "False" ALLOWED_HOSTS: "localhost,127.0.0.1,yourdomain.com" # Redis REDIS_HOST: "redis" REDIS_PORT: "6379" REDIS_DB: "0" # API Keys (external services) SENDGRID_API_KEY: "[if using email service]" STRIPE_API_KEY: "[if using payments]" AWS_ACCESS_KEY_ID: "[if using AWS]" AWS_SECRET_ACCESS_KEY: "[if using AWS]" # GitHub Actions CI/CD (optional) DOCKERHUB_USERNAME: "[if using Docker Hub]" DOCKERHUB_TOKEN: "[if using Docker Hub]" ``` ### 3.4 GitHub Actions Workflow Structure #### Basic Linting Workflow (.github/workflows/lint.yml) ```yaml name: Lint on: push: branches: [main, staging, develop, 'feature/*'] pull_request: branches: [main, staging, develop] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Run Black run: pip install black && black --check . - name: Run Flake8 run: pip install flake8 && flake8 . - name: Run isort run: pip install isort && isort --check-only . ``` #### Docker Build Validation (.github/workflows/docker-build.yml) ```yaml name: Docker Build on: push: branches: [main, staging, develop] pull_request: branches: [main, staging] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build Docker images run: docker-compose build - name: Run docker-compose validation run: docker-compose config ``` ### 3.5 Branch Protection Rule Configuration **For main branch:** ``` - Require pull request reviews before merging: YES (1 review minimum) - Require status checks to pass before merging: YES - Required status checks: lint, docker-build (if using CI/CD) - Require branches to be up to date before merging: YES - Include administrators: YES - Restrict who can push to matching branches: YES (admin only) - Allow auto-merge: NO ``` **For staging branch:** ``` - Require pull request reviews before merging: YES (1 review minimum) - Require status checks to pass before merging: YES (if CI/CD enabled) - Allow direct pushes from: restricted (maintainers only) ``` --- ## 4. Implementation Steps ### 4.1 Prerequisites **Before starting, ensure you have:** 1. GitHub account with admin access to target organization/user account 2. GitHub Personal Access Token (PAT) with full repo scope - Generate at: Settings → Developer settings → Personal access tokens (classic) - Required scopes: `repo`, `write:packages`, `delete:repo` 3. Git installed locally (v2.28+) 4. Access to current Gitea instance (to export repos) 5. SSH key configured on local machine (optional but recommended) 6. Write access to `/mnt/Source-Codes/` directory structure **Command: Verify prerequisites** ```bash git --version # Should be 2.28+ gh --version # GitHub CLI (optional but helpful) ssh-keygen -t ed25519 -N "" # Generate SSH key if not present (optional) ``` ### 4.2 Step 1: Identify and Document All Repositories **Objective:** Create complete inventory of all IGNY8 repositories **Commands:** ```bash # List all Gitea repositories (if accessible) # Note: Adjust Gitea URL based on your configuration curl -H "Authorization: token [GITEA_TOKEN]" \ https://gitea.oldvps.com/api/v1/repos/igny8 | jq '.[] | {name, full_name, clone_url}' # Document current local repositories find /mnt/Source-Codes -name ".git" -type d | head -20 # List any other scattered IGNY8 repos grep -r "igny8" /mnt --include=".git" 2>/dev/null || echo "No other repos found" ``` **Expected Output Inventory:** ``` Repository List: 1. igny8-stack - Current Location: Gitea or /mnt/Source-Codes/Igny8/igny8-stack/ - Clone URL (Gitea): [gitea-url]/igny8-stack.git - Size: ~50MB - Branches: main, develop, feature/* - Last Update: [date] 2. igny8-app - Current Location: Gitea or /mnt/Source-Codes/Igny8/igny8-app/ - Clone URL (Gitea): [gitea-url]/igny8-app.git - Size: ~200MB (includes node_modules history if present) - Branches: main, develop, staging, feature/* - Last Update: [date] 3. igny8-wordpress-plugin - Current Location: [location] - Size: ~5MB - Status: [active/archived] 4. [Any additional repos] ``` **Documentation:** Save this inventory to `/mnt/Documents/EcoSystem/Projects/APPS/Igny8/repo-migration-inventory.txt` --- ### 4.3 Step 2: Create GitHub Repositories **Objective:** Set up empty GitHub repositories to receive migrated code **Commands:** ```bash # Using GitHub CLI (recommended) gh auth login # Authenticate if not already done # Create igny8-stack repository gh repo create igny8-stack \ --public \ --description "IGNY8 Infrastructure, Docker configs, and orchestration" \ --homepage "https://github.com/[username/org]/igny8-stack" # Create igny8-app repository gh repo create igny8-app \ --public \ --description "IGNY8 Django backend + React frontend application" \ --homepage "https://github.com/[username/org]/igny8-app" # Create igny8-wordpress-plugin repository (if applicable) gh repo create igny8-wordpress-plugin \ --public \ --description "IGNY8 WordPress plugin integration" # Verify repositories created gh repo list [username/org] --json name,url ``` **Alternative (Web UI):** 1. Go to GitHub.com → Your repositories 2. Click "New" button 3. Repository name: `igny8-stack` 4. Description: "IGNY8 Infrastructure, Docker configs, and orchestration" 5. Visibility: Public (or Private if preferred) 6. Do NOT initialize with README (we'll import existing code) 7. Create repository 8. Repeat for `igny8-app` and `igny8-wordpress-plugin` **Verification:** ```bash # Confirm repositories exist gh api repos/[username]/igny8-stack gh api repos/[username]/igny8-app gh api repos/[username]/igny8-wordpress-plugin ``` --- ### 4.4 Step 3: Migrate Repositories from Gitea to GitHub **Objective:** Transfer all code history from Gitea to GitHub using mirror clone **Commands:** ```bash # Create temporary migration directory mkdir -p /tmp/igny8-migration cd /tmp/igny8-migration # For each repository, perform a mirror clone and push to GitHub # This preserves all branches, tags, and commit history # === MIGRATE igny8-stack === git clone --mirror https://gitea.oldvps.com/igny8/igny8-stack.git igny8-stack-mirror.git cd igny8-stack-mirror.git git push --mirror https://github.com/[username]/igny8-stack.git cd .. # === MIGRATE igny8-app === git clone --mirror https://gitea.oldvps.com/igny8/igny8-app.git igny8-app-mirror.git cd igny8-app-mirror.git git push --mirror https://github.com/[username]/igny8-app.git cd .. # === MIGRATE igny8-wordpress-plugin === # (if hosted on Gitea) git clone --mirror https://gitea.oldvps.com/igny8/igny8-wordpress-plugin.git igny8-wordpress-plugin-mirror.git cd igny8-wordpress-plugin-mirror.git git push --mirror https://github.com/[username]/igny8-wordpress-plugin.git cd .. # Verify migration cd /tmp/igny8-migration git clone https://github.com/[username]/igny8-stack.git test-clone cd test-clone git log --oneline | head -20 # Should show full commit history git branch -a # Should show all branches ``` **Alternative Method (if Gitea access is limited):** If you have a local clone of the repository already, use: ```bash cd /path/to/existing/igny8-stack git remote add github https://github.com/[username]/igny8-stack.git git push -u github --all git push -u github --tags git remote set-url origin https://github.com/[username]/igny8-stack.git ``` **Verification Checklist:** - [ ] All commits present in GitHub - [ ] All branches pushed to GitHub - [ ] All tags preserved - [ ] No .env files or secrets in any commit (verify with: `git log --all -S "password" --oneline`) - [ ] Repository size reasonable (check GitHub repo page) --- ### 4.5 Step 4: Cleanse Repositories of Secrets **Objective:** Remove any accidentally committed secrets using git history rewriting **Critical:** Only perform if secrets were committed. If confirmed, use BFG Repo-Cleaner: ```bash # Download BFG Repo-Cleaner cd /tmp wget https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar # Clone repository to clean git clone --mirror https://github.com/[username]/igny8-app.git igny8-app-clean.git cd igny8-app-clean.git # Remove secrets (example: .env files) java -jar /tmp/bfg-1.14.0.jar --delete-files .env igny8-app-clean.git # Reflog expire and garbage collect git reflog expire --expire=now --all git gc --prune=now --aggressive # Force push cleaned history back to GitHub git push --force --mirror https://github.com/[username]/igny8-app.git ``` **Alternative (BFG not available):** ```bash # Use git filter-branch (slower but no dependencies) git filter-branch --tree-filter 'rm -f .env .env.local' -- --all git push --force --all git push --force --tags ``` **Verification:** ```bash # Search for any remaining secrets (case-sensitive) git log --all -p | grep -i "password\|secret\|api_key\|token" || echo "No secrets found" ``` --- ### 4.6 Step 5: Set Up Local Development Clones **Objective:** Establish standardized directory structure and clones in EcoSystem **Commands:** ```bash # Create main Igny8 source code directory mkdir -p /mnt/Source-Codes/Igny8 cd /mnt/Source-Codes/Igny8 # Clone igny8-stack git clone https://github.com/[username]/igny8-stack.git igny8-stack cd igny8-stack # Configure local git git config user.name "Your Name" git config user.email "your.email@domain.com" # Verify all branches available git branch -a # Set default branch if different from main git checkout main || git checkout master cd .. # Clone igny8-app git clone https://github.com/[username]/igny8-app.git igny8-app cd igny8-app git config user.name "Your Name" git config user.email "your.email@domain.com" git branch -a git checkout staging # or appropriate default branch cd .. # Clone igny8-wordpress-plugin git clone https://github.com/[username]/igny8-wordpress-plugin.git igny8-wordpress-plugin cd igny8-wordpress-plugin git config user.name "Your Name" git config user.email "your.email@domain.com" cd .. # Verify structure ls -la /mnt/Source-Codes/Igny8/ tree -L 2 /mnt/Source-Codes/Igny8/ --dirsfirst ``` **Expected Structure:** ``` /mnt/Source-Codes/Igny8/ ├── igny8-stack/ │ ├── .git/ │ ├── docker/ │ ├── docker-compose.yml │ └── [other files] ├── igny8-app/ │ ├── .git/ │ ├── backend/ │ ├── frontend/ │ └── [other files] └── igny8-wordpress-plugin/ ├── .git/ └── [plugin files] ``` --- ### 4.7 Step 6: Configure GitHub Branch Strategy **Objective:** Set up branch protection rules and merge workflow **Commands (GitHub CLI):** ```bash cd /mnt/Source-Codes/Igny8/igny8-stack # Fetch all remotes to ensure updated git fetch origin # Create staging branch if it doesn't exist git checkout -b staging origin/staging || git checkout -b staging origin/main git push -u origin staging # Create develop branch if it doesn't exist git checkout -b develop origin/develop || git checkout -b develop origin/staging git push -u origin develop # List all branches git branch -a ``` **Set Branch Protection Rules (requires GitHub UI or gh CLI with advanced permissions):** Using GitHub CLI: ```bash # This requires additional GitHub CLI extension or manual UI configuration # For now, configure via GitHub Web UI: # For igny8-stack repository: # 1. Go to GitHub.com → igny8-stack → Settings → Branches # 2. Click "Add rule" under "Branch protection rules" # 3. Pattern: main # 4. Check: "Require pull request reviews before merging" (1 review) # 5. Check: "Dismiss stale pull request approvals when new commits are pushed" # 6. Check: "Require status checks to pass before merging" (if using CI/CD) # 7. Check: "Require branches to be up to date before merging" # 8. Check: "Include administrators" # 9. Save echo "Branch protection rules must be configured via GitHub Web UI" echo "See GitHub documentation for detailed steps" ``` **Manual Web UI Setup (3 minutes per repo):** For each repository (igny8-stack, igny8-app, igny8-wordpress-plugin): 1. Navigate to: https://github.com/[username]/[repo-name]/settings/branches 2. Click "Add rule" 3. **Branch name pattern:** `main` 4. Enable: - ✅ "Require pull request reviews before merging" (min 1) - ✅ "Require status checks to pass before merging" - ✅ "Require branches to be up to date before merging" - ✅ "Include administrators" 5. Click "Create" or "Save" Repeat for `staging` branch (with fewer restrictions if preferred): - Branch name pattern: `staging` - ✅ Require PR review (1 minimum) - Optional: status checks --- ### 4.8 Step 7: Configure GitHub Secrets **Objective:** Set up environment variables for CI/CD and deployments **Commands (GitHub CLI):** ```bash # Authenticate with GitHub gh auth login cd /mnt/Source-Codes/Igny8/igny8-app # Set secrets for igny8-app repository # Interactive input for sensitive values gh secret set DB_PASSWORD \ --repo [username]/igny8-app \ --body "$(read -sp 'Enter DB password: ' pwd; echo $pwd)" gh secret set DJANGO_SECRET_KEY \ --repo [username]/igny8-app \ --body "$(python3 -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())')" gh secret set SENDGRID_API_KEY \ --repo [username]/igny8-app \ --body "$(read -sp 'Enter SendGrid API Key: ' key; echo $key)" # For other secrets, use GitHub Web UI or repeat above pattern ``` **Manual Web UI Setup (recommended for sensitive data):** For each repository: 1. Navigate to: Settings → Secrets and variables → Actions 2. Click "New repository secret" 3. Enter secret name and value 4. Click "Add secret" Secrets to configure: ``` DB_PASSWORD DJANGO_SECRET_KEY REDIS_PASSWORD (if applicable) SENDGRID_API_KEY (if applicable) STRIPE_API_KEY (if applicable) AWS_ACCESS_KEY_ID (if applicable) AWS_SECRET_ACCESS_KEY (if applicable) DOCKERHUB_TOKEN (if using Docker Hub) ``` **Verification:** ```bash # List configured secrets (names only, not values) gh secret list --repo [username]/igny8-app ``` --- ### 4.9 Step 9: Add .gitignore and .dockerignore **Objective:** Prevent accidental commits of secrets and unwanted files **Commands:** For each repository, copy standardized .gitignore: ```bash cd /mnt/Source-Codes/Igny8/igny8-stack # Create .gitignore (copy from Section 3.2) cat > .gitignore << 'EOF' # Environment variables - NEVER commit secrets .env .env.local .env.*.local .env.production.local # IDE and editor files .vscode/ .idea/ *.swp *.swo *~ .DS_Store # Docker docker-compose.override.yml # Database files *.sqlite3 postgres_data/ # Logs *.log # OS files Thumbs.db EOF # Commit .gitignore git add .gitignore git commit -m "chore: add standardized .gitignore" git push origin $(git rev-parse --abbrev-ref HEAD) # Create .dockerignore cat > .dockerignore << 'EOF' .git .gitignore .env .env.local .vscode .idea node_modules __pycache__ .pytest_cache .DS_Store *.log docker-compose.override.yml postgres_data/ redis_data/ EOF git add .dockerignore git commit -m "chore: add .dockerignore" git push origin $(git rev-parse --abbrev-ref HEAD) # Repeat for igny8-app cd /mnt/Source-Codes/Igny8/igny8-app # ... (same steps as above) ``` --- ### 4.10 Step 10: Add Documentation Files **Objective:** Ensure each repo has clear setup and contribution guidelines **Commands:** For each repository, add README.md and CONTRIBUTING.md: ```bash cd /mnt/Source-Codes/Igny8/igny8-stack # Create README.md cat > README.md << 'EOF' # IGNY8 Stack Infrastructure, Docker configurations, and orchestration for the IGNY8 ecosystem. ## Quick Start ```bash git clone https://github.com/[username]/igny8-stack.git cd igny8-stack docker-compose up -d ``` ## Architecture - **Backend:** Django 5.1 - **Frontend:** React 19 - **Database:** PostgreSQL 16 - **Cache:** Redis 7 - **Proxy:** Caddy 2 - **Orchestration:** Docker Compose ## Documentation - [SETUP.md](./docs/SETUP.md) - Development environment setup - [ARCHITECTURE.md](./docs/ARCHITECTURE.md) - System architecture overview - [DEPLOYMENT.md](./docs/DEPLOYMENT.md) - Deployment procedures ## Contributing See [CONTRIBUTING.md](./CONTRIBUTING.md) for contribution guidelines and branch strategy. ## License MIT License - see LICENSE file EOF # Create CONTRIBUTING.md cat > CONTRIBUTING.md << 'EOF' # Contributing to IGNY8 Stack ## Branch Strategy - **main** - Production-ready code, protected branch - **staging** - Staging/QA environment code - **develop** - Development branch - **feature/** - Feature branches ## Workflow 1. Create feature branch from `develop`: ```bash git checkout develop git pull origin develop git checkout -b feature/your-feature-name ``` 2. Make changes and commit: ```bash git commit -m "type: description" ``` 3. Push and create Pull Request: ```bash git push -u origin feature/your-feature-name ``` 4. After review and merge to `staging` → `main` ## Commit Message Format ``` type(scope): description body (optional) footer (optional) ``` Types: feat, fix, docs, style, refactor, test, chore ## Code Review - All PRs require 1 approval - Status checks must pass - Maintain up-to-date with base branch EOF git add README.md CONTRIBUTING.md git commit -m "docs: add README and CONTRIBUTING guidelines" git push origin $(git rev-parse --abbrev-ref HEAD) ``` Repeat for `igny8-app` with appropriate content. --- ### 4.11 Step 11: Add CODEOWNERS File **Objective:** Automatically assign reviewers based on file changes **Commands:** ```bash # For igny8-stack cd /mnt/Source-Codes/Igny8/igny8-stack mkdir -p .github cat > .github/CODEOWNERS << 'EOF' # Default owners * @[primary-maintainer] # Docker configuration owners docker/ @[infrastructure-team] docker-compose.yml @[infrastructure-team] # Database owners postgres/ @[dba-team] # Cache owners redis/ @[backend-team] # Documentation owners docs/ @[documentation-team] README.md @[primary-maintainer] EOF git add .github/CODEOWNERS git commit -m "chore: add CODEOWNERS for automatic PR assignment" git push origin $(git rev-parse --abbrev-ref HEAD) # Repeat for igny8-app with appropriate owners cd /mnt/Source-Codes/Igny8/igny8-app mkdir -p .github cat > .github/CODEOWNERS << 'EOF' * @[primary-maintainer] # Backend owners backend/ @[backend-team] backend/requirements*.txt @[backend-team] # Frontend owners frontend/ @[frontend-team] frontend/package.json @[frontend-team] # Tests **/tests/ @[qa-team] # Documentation docs/ @[documentation-team] README.md @[primary-maintainer] EOF git add .github/CODEOWNERS git commit -m "chore: add CODEOWNERS for automatic PR assignment" git push origin $(git rev-parse --abbrev-ref HEAD) ``` --- ### 4.12 Step 12: Configure GitHub Actions (Optional but Recommended) **Objective:** Set up basic CI/CD workflows **For igny8-stack repository:** ```bash cd /mnt/Source-Codes/Igny8/igny8-stack mkdir -p .github/workflows # Create Docker build validation workflow cat > .github/workflows/docker-build.yml << 'EOF' name: Docker Build Validation on: push: branches: [main, staging, develop] pull_request: branches: [main, staging, develop] jobs: docker-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Validate docker-compose.yml run: docker-compose config - name: Build images run: docker-compose build - name: Check image sizes run: docker images --format "{{.Repository}}\t{{.Size}}" EOF # Create linting workflow cat > .github/workflows/lint.yml << 'EOF' name: Lint on: push: branches: [main, staging, develop, 'feature/*'] pull_request: branches: [main, staging, develop] jobs: lint-yaml: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Lint YAML files run: | pip install yamllint yamllint . --no-warnings EOF git add .github/workflows/ git commit -m "ci: add GitHub Actions workflows" git push origin $(git rev-parse --abbrev-ref HEAD) ``` **For igny8-app repository:** ```bash cd /mnt/Source-Codes/Igny8/igny8-app mkdir -p .github/workflows # Create backend test workflow cat > .github/workflows/test-backend.yml << 'EOF' name: Backend Tests on: push: branches: [main, staging, develop] pull_request: branches: [main, staging, develop] jobs: test: runs-on: ubuntu-latest services: postgres: image: postgres:16 env: POSTGRES_DB: test_igny8 POSTGRES_USER: test_user POSTGRES_PASSWORD: test_pass options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 redis: image: redis:7 options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: | cd backend pip install -r requirements-dev.txt - name: Run tests env: DATABASE_URL: postgresql://test_user:test_pass@localhost/test_igny8 REDIS_URL: redis://localhost:6379/0 run: | cd backend pytest EOF # Create frontend test workflow cat > .github/workflows/test-frontend.yml << 'EOF' name: Frontend Tests on: push: branches: [main, staging, develop] pull_request: branches: [main, staging, develop] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: | cd frontend npm ci - name: Run tests run: | cd frontend npm test - name: Run linting run: | cd frontend npm run lint EOF git add .github/workflows/ git commit -m "ci: add GitHub Actions test workflows" git push origin $(git rev-parse --abbrev-ref HEAD) ``` --- ### 4.13 Step 13: Verify and Document Migration **Objective:** Confirm all repos successfully migrated and accessible **Commands:** ```bash # Create migration verification checklist cat > /mnt/Documents/EcoSystem/Projects/APPS/Igny8/github-migration-checklist.md << 'EOF' # GitHub Repository Migration Verification Checklist ## Repository: igny8-stack ### Migration Verification - [ ] Repository exists on GitHub - [ ] All commits migrated (count matches source) - [ ] All branches visible (`git branch -a` shows all) - [ ] All tags present (`git tag -l` shows all) - [ ] No .env files in history (`git log --all -p | grep -i "\.env" | wc -l == 0`) ### Configuration - [ ] .gitignore committed and active - [ ] .dockerignore present - [ ] README.md present and complete - [ ] CONTRIBUTING.md present - [ ] CODEOWNERS file configured - [ ] Branch protection rules on main branch - [ ] Branch protection rules on staging branch ### GitHub Actions - [ ] Docker build validation workflow running - [ ] Lint workflow running - [ ] All workflows passing ### Local Setup - [ ] Local clone at /mnt/Source-Codes/Igny8/igny8-stack/ - [ ] Remote origin points to GitHub - [ ] All branches fetchable locally ## Repository: igny8-app ### Migration Verification - [ ] Repository exists on GitHub - [ ] All commits migrated (count matches source) - [ ] All branches visible - [ ] All tags present - [ ] No .env files in history - [ ] No API keys in history ### Configuration - [ ] .gitignore committed (excludes node_modules, __pycache__) - [ ] .dockerignore present - [ ] README.md with setup instructions - [ ] CONTRIBUTING.md with workflow - [ ] CODEOWNERS file configured - [ ] Branch protection rules on main ### GitHub Actions - [ ] Backend test workflow configured - [ ] Frontend test workflow configured - [ ] Docker build validation configured ### Local Setup - [ ] Local clone at /mnt/Source-Codes/Igny8/igny8-app/ - [ ] Remote origin points to GitHub - [ ] All branches fetchable locally ### GitHub Secrets - [ ] DB_PASSWORD configured - [ ] DJANGO_SECRET_KEY configured - [ ] API keys configured (Sendgrid, Stripe, AWS, etc.) ## Repository: igny8-wordpress-plugin - [ ] Repository exists and migrated - [ ] Documentation present - [ ] Local clone configured - [ ] Branch strategy established ## Cleanup - [ ] All repositories confirmed on GitHub - [ ] Old Gitea instance verified as redundant (backup created) - [ ] Team members notified of new GitHub URLs - [ ] SSH keys configured for developers - [ ] Credentials updated in any CI/CD systems pointing to repos EOF # Run verification commands echo "=== igny8-stack Verification ===" cd /mnt/Source-Codes/Igny8/igny8-stack echo "Commit count:" git rev-list --count HEAD echo "Branch count:" git branch | wc -l echo "Remote URL:" git config --get remote.origin.url echo -e "\n=== igny8-app Verification ===" cd /mnt/Source-Codes/Igny8/igny8-app echo "Commit count:" git rev-list --count HEAD echo "Branch count:" git branch | wc -l echo "Remote URL:" git config --get remote.origin.url echo -e "\n=== igny8-wordpress-plugin Verification ===" cd /mnt/Source-Codes/Igny8/igny8-wordpress-plugin echo "Commit count:" git rev-list --count HEAD echo "Remote URL:" git config --get remote.origin.url ``` --- ## 5. Acceptance Criteria ### 5.1 Mandatory Criteria (Must Have) 1. **Repository Migration** - ✅ All three main repositories exist on GitHub with correct names - ✅ All commit history from Gitea migrated to GitHub (commit counts match) - ✅ All branches from source repos present on GitHub - ✅ All git tags preserved - ✅ No confidential data (.env files, API keys, secrets) in any repo history 2. **Local Development Setup** - ✅ All repos cloned to `/mnt/Source-Codes/Igny8/[repo-name]/` - ✅ Git remotes correctly configured pointing to GitHub - ✅ `git status` returns clean working directory after initial clone - ✅ `git branch -a` shows all remote branches 3. **GitHub Configuration** - ✅ .gitignore present and excludes .env files, secrets, build artifacts - ✅ .dockerignore present to prevent secrets in container images - ✅ README.md in each repository with project description - ✅ CONTRIBUTING.md in each repository with branch strategy - ✅ Branch protection rules on `main` branch (require 1 PR review, status checks) - ✅ GitHub Secrets configured for database passwords, API keys, Django secret key 4. **Branch Strategy** - ✅ `main` branch exists and is production-ready code - ✅ `staging` branch exists for QA/pre-production - ✅ `develop` or equivalent development branch exists - ✅ Merge workflow documented (feature → develop → staging → main) 5. **Documentation** - ✅ Migration completion documented with dates and verification results - ✅ Each repo has setup instructions for new developers - ✅ Branch protection rules and workflow documented - ✅ GitHub Secrets list documented (names, not values) ### 5.2 Quality Criteria (Should Have) 1. **GitHub Actions Setup** - ✅ Basic Docker build validation workflow exists - ✅ Linting workflow for code quality (Python, YAML) - ✅ Status checks configured as branch protection requirement - ✅ Workflows passing on `develop` and `staging` branches 2. **Team Collaboration** - ✅ CODEOWNERS file configured for automatic PR assignment - ✅ GitHub team/org structure set up (if using GitHub Organization) - ✅ All team members have repository access - ✅ SSH keys or personal access tokens configured for team 3. **Repository Quality** - ✅ No merge conflicts in migration - ✅ Repository size reasonable (not including node_modules, venv, etc.) - ✅ All workflows passing (green checkmarks on main branch) ### 5.3 Verification Commands Run these commands to verify acceptance criteria: ```bash # Run in /mnt/Source-Codes/Igny8/ # Verify all repos exist for repo in igny8-stack igny8-app igny8-wordpress-plugin; do if [ -d "$repo" ]; then echo "✓ $repo directory exists" else echo "✗ $repo directory missing" fi done # Verify no secrets in history (sample check) cd igny8-app if git log --all -p | grep -q "DJANGO_SECRET\|password.*=\|api_key"; then echo "⚠ WARNING: Potential secrets found in history" else echo "✓ No obvious secrets detected in history" fi # Verify GitHub connection cd igny8-stack REMOTE=$(git config --get remote.origin.url) if [[ $REMOTE == *"github.com"* ]]; then echo "✓ igny8-stack points to GitHub" else echo "✗ igny8-stack remote not GitHub: $REMOTE" fi # Verify files present for repo in igny8-stack igny8-app igny8-wordpress-plugin; do echo -e "\nChecking $repo..." cd /mnt/Source-Codes/Igny8/$repo [ -f ".gitignore" ] && echo " ✓ .gitignore" || echo " ✗ .gitignore missing" [ -f "README.md" ] && echo " ✓ README.md" || echo " ✗ README.md missing" [ -f "CONTRIBUTING.md" ] && echo " ✓ CONTRIBUTING.md" || echo " ✗ CONTRIBUTING.md missing" [ -d ".github" ] && echo " ✓ .github/ directory" || echo " ✗ .github/ missing" done ``` --- ## 6. Claude Code Instructions This section provides step-by-step instructions for Claude Code to execute the entire repository consolidation process. ### 6.1 Pre-Execution Checklist Before running Claude Code, **verify and provide:** ``` Required Information: - [ ] GitHub username or organization name: _______________ - [ ] GitHub Personal Access Token (PAT): [provided securely] - [ ] Gitea instance URL (if migrating from Gitea): _______________ - [ ] Gitea admin token (if applicable): [provided securely] - [ ] Primary maintainer GitHub username: _______________ - [ ] Team member GitHub usernames (for CODEOWNERS): _______________ - [ ] Confirmation: Old Gitea repos backed up? YES / NO ``` ### 6.2 Full Automated Execution Plan **Claude Code should execute the following sequence:** ```bash #!/bin/bash # IGNY8 Phase 0: GitHub Repository Consolidation - Full Execution # This script automates all migration steps set -e # Exit on error GITHUB_USERNAME="${1:-[your-username]}" GITHUB_TOKEN="${2:-[your-token]}" GITEA_URL="${3:-https://gitea.oldvps.com}" MIGRATION_DIR="/tmp/igny8-github-migration" SOURCE_DIR="/mnt/Source-Codes/Igny8" echo "==========================================" echo "IGNY8 GitHub Repository Consolidation" echo "==========================================" echo "Target GitHub Account: $GITHUB_USERNAME" echo "Gitea Source: $GITEA_URL" echo "Local Directory: $SOURCE_DIR" echo "" # Step 1: Create migration directory echo "[STEP 1] Creating migration directory..." mkdir -p $MIGRATION_DIR cd $MIGRATION_DIR # Step 2: Create GitHub repositories (via API) echo "[STEP 2] Creating GitHub repositories..." for REPO in "igny8-stack" "igny8-app" "igny8-wordpress-plugin"; do echo " Creating $REPO..." curl -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/user/repos \ -d "{ \"name\":\"$REPO\", \"description\":\"IGNY8 Repository\", \"private\":false }" || echo " (Repo may already exist)" done # Step 3: Migrate repositories from Gitea echo "[STEP 3] Migrating repositories from Gitea to GitHub..." for REPO in "igny8-stack" "igny8-app" "igny8-wordpress-plugin"; do echo " Migrating $REPO..." git clone --mirror "$GITEA_URL/igny8/$REPO.git" "$REPO-mirror.git" || { echo " WARNING: Could not clone from Gitea, using local copy method" continue } cd "$REPO-mirror.git" git push --mirror "https://$GITHUB_TOKEN@github.com/$GITHUB_USERNAME/$REPO.git" cd .. done # Step 4: Create local clones echo "[STEP 4] Setting up local development clones..." mkdir -p $SOURCE_DIR cd $SOURCE_DIR for REPO in "igny8-stack" "igny8-app" "igny8-wordpress-plugin"; do if [ ! -d "$REPO" ]; then echo " Cloning $REPO..." git clone "https://github.com/$GITHUB_USERNAME/$REPO.git" "$REPO" else echo " $REPO already exists, updating..." cd "$REPO" git fetch origin cd .. fi done # Step 5: Add documentation and configuration files echo "[STEP 5] Adding .gitignore, README, and CONTRIBUTING files..." for REPO in "igny8-stack" "igny8-app" "igny8-wordpress-plugin"; do echo " Configuring $REPO..." cd "$SOURCE_DIR/$REPO" # Add .gitignore if not present if [ ! -f ".gitignore" ]; then cat > .gitignore << 'EOF' .env .env.local .env.*.local .vscode/ .idea/ *.pyc __pycache__/ node_modules/ *.log .DS_Store docker-compose.override.yml postgres_data/ .pytest_cache/ EOF git add .gitignore git commit -m "chore: add .gitignore" || true fi # Add .dockerignore if not present if [ ! -f ".dockerignore" ]; then cat > .dockerignore << 'EOF' .git .gitignore .env .vscode .idea node_modules __pycache__ .DS_Store *.log docker-compose.override.yml EOF git add .dockerignore git commit -m "chore: add .dockerignore" || true fi # Add README if not present if [ ! -f "README.md" ]; then cat > README.md << EOF # $REPO Part of the IGNY8 ecosystem. ## Quick Start \`\`\`bash git clone https://github.com/$GITHUB_USERNAME/$REPO.git cd $REPO \`\`\` ## Contributing See CONTRIBUTING.md for guidelines. ## License MIT EOF git add README.md git commit -m "docs: add README" || true fi done # Step 6: Push changes echo "[STEP 6] Pushing configuration changes to GitHub..." for REPO in "igny8-stack" "igny8-app" "igny8-wordpress-plugin"; do cd "$SOURCE_DIR/$REPO" echo " Pushing $REPO..." git push origin $(git rev-parse --abbrev-ref HEAD) || true done # Step 7: Create GitHub Secrets (manual step - cannot be automated via API from outside GitHub Actions) echo "" echo "[STEP 7] GitHub Secrets Configuration (MANUAL):" echo " Visit GitHub repository Settings → Secrets and variables → Actions" echo " Add the following secrets:" echo " - DB_PASSWORD" echo " - DJANGO_SECRET_KEY" echo " - SENDGRID_API_KEY (if applicable)" echo "" echo "==========================================" echo "Migration Complete!" echo "==========================================" echo "" echo "Next Steps:" echo "1. Verify repositories on GitHub" echo "2. Configure GitHub Secrets (see above)" echo "3. Set up branch protection rules (GitHub UI)" echo "4. Notify team of new GitHub URLs" echo "5. See 00E-legacy-cleanup.md for Gitea decommissioning" echo "" echo "Repository URLs:" echo " https://github.com/$GITHUB_USERNAME/igny8-stack" echo " https://github.com/$GITHUB_USERNAME/igny8-app" echo " https://github.com/$GITHUB_USERNAME/igny8-wordpress-plugin" ``` ### 6.3 Execution Instructions for Claude Code **Run the consolidated migration script:** ```bash # Provide required information interactively read -p "GitHub Username: " GITHUB_USERNAME read -sp "GitHub Personal Access Token: " GITHUB_TOKEN read -p "Gitea URL (default: https://gitea.oldvps.com): " GITEA_URL GITEA_URL=${GITEA_URL:-https://gitea.oldvps.com} # Execute migration script (see 6.2 above) bash /mnt/Documents/EcoSystem/Projects/APPS/Igny8/execute-github-migration.sh \ "$GITHUB_USERNAME" \ "$GITHUB_TOKEN" \ "$GITEA_URL" ``` **Verification after execution:** ```bash # Verify all repos cloned ls -la /mnt/Source-Codes/Igny8/ # Verify GitHub connectivity for repo in igny8-stack igny8-app igny8-wordpress-plugin; do cd /mnt/Source-Codes/Igny8/$repo echo "=== $repo ===" git remote -v git branch | head -5 done # Verify no secrets in repos echo "Checking for potential secrets in history..." cd /mnt/Source-Codes/Igny8/igny8-app git log --all -p | grep -E "password|SECRET|api_key|token" | head -5 || echo "No obvious secrets detected" ``` ### 6.4 Manual Steps Required (Cannot be Automated) The following steps require manual interaction: 1. **GitHub Secrets Configuration** - Must be done via GitHub Web UI for security - Visit: Settings → Secrets and variables → Actions - Add: DB_PASSWORD, DJANGO_SECRET_KEY, API keys, etc. 2. **Branch Protection Rules** - Configure via GitHub Web UI: Settings → Branches → Add rule - Set protection on `main` and `staging` branches - Require PR reviews, status checks 3. **GitHub Team/Org Setup** (if using) - Create organization if needed - Add team members - Configure permissions 4. **Gitea Decommissioning** - See 00E-legacy-cleanup.md - Create backup before decommissioning - Remove from production infrastructure ### 6.5 Rollback Procedures If issues occur during migration: ```bash # Rollback: Reset remote to point back to Gitea (if needed) cd /mnt/Source-Codes/Igny8/igny8-stack git remote set-url origin https://gitea.oldvps.com/igny8/igny8-stack.git git fetch origin # Verify Gitea repos still exist curl https://gitea.oldvps.com/api/v1/repos/igny8/igny8-stack # If GitHub repos were accidentally deleted, recreate and re-push git push --mirror https://github.com/[username]/igny8-stack.git ``` --- ## 7. Related Documentation **Other Phase 0 Documents:** - `00B-environment-standardization.md` - Environment variable management - `00C-ecosystem-structure.md` - EcoSystem folder and file organization - `00D-docker-compose-upgrade.md` - Updating Docker Compose files for consistency - `00E-legacy-cleanup.md` - Decommissioning Gitea instance - `00F-ci-cd-setup.md` - Advanced GitHub Actions configuration (Phase 1) **References:** - GitHub Documentation: https://docs.github.com/en/repositories - Git Migration Guide: https://docs.github.com/en/repositories/creating-and-managing-repositories/importing-a-repository-with-github-importer - BFG Repo-Cleaner: https://rtyley.github.io/bfg-repo-cleaner/ (for secret removal) - GitHub CLI: https://cli.github.com/ (automation tool) --- ## 8. Appendix: Quick Reference ### GitHub Repo URLs (Template) ``` igny8-stack: https://github.com/[username]/igny8-stack igny8-app: https://github.com/[username]/igny8-app igny8-wordpress-plugin: https://github.com/[username]/igny8-wordpress-plugin ``` ### Local Development Paths ``` /mnt/Source-Codes/Igny8/igny8-stack/ /mnt/Source-Codes/Igny8/igny8-app/ /mnt/Source-Codes/Igny8/igny8-wordpress-plugin/ ``` ### Essential Git Commands ```bash # Clone with HTTPS git clone https://github.com/[username]/igny8-app.git # Configure local git git config user.name "Your Name" git config user.email "your.email@domain.com" # Create feature branch git checkout -b feature/your-feature-name # Push changes git push -u origin feature/your-feature-name # Pull latest git pull origin develop # Check remote git remote -v ``` ### Branch Strategy Summary ``` feature/xyz → develop → staging → main ↓ ↓ ↓ ↓ (local) (dev) (qa) (production) ``` --- **Document End** **Status:** ✅ READY FOR EXECUTION **Maintainer:** IGNY8 DevOps Team **Last Review:** 2026-03-23 **Next Review:** Post-migration completion