Project Migration (Tech Stack)

Inheriting a codebase your team cannot maintain is a common outsourcing scenario. A client’s maintenance team shifts, and suddenly a Django monolith needs to become a Laravel application — same behavior, different stack. The risk is not the rewrite itself; it is the business logic that goes undocumented in someone’s head and disappears in transit. Sun Agent Kit solves this with a scout-first discipline: map everything before moving anything, then migrate module by module with parity tests verifying behavior at every checkpoint.

Overview

Goal: Migrate a project from one tech stack to another with zero lost business logic
Time: 1–3 days for a medium project (vs 2–4 weeks manual)
Agents used: scout, planner, implementer, tester, reviewer
Commands: /sk:scout, /sk:brainstorm, /sk:research, /sk:plan, /sk:cook, /sk:test, /sk:code-review, /sk:security-scan, /sk:git

Prerequisites

  • Sun Agent Kit installed (installation guide)
  • Source codebase checked out and accessible locally
  • Target stack runtime available (e.g., PHP 8.2 + Composer for Laravel)
  • Git initialized in both source and target directories
  • Access to any third-party service credentials used in the source project (Stripe keys, API tokens, etc.)
  • Existing test suite or API contract documentation for the source project (even partial coverage helps)

Step-by-Step Workflow

Step 1: Scout the Source Codebase

/sk:scout "map everything in this Django project: models with fields and relationships, views and API endpoints with request/response shapes, middleware, Celery tasks, Stripe integration, custom authentication logic — generate a complete source inventory"

What happens: The agent:

  1. Traverses the entire source codebase, reading every model, view, serializer, and task file
  2. Extracts model schemas including field types, constraints, and foreign key relationships
  3. Maps each endpoint: URL, HTTP method, request body shape, response shape, status codes
  4. Identifies all background jobs, scheduled tasks, and async processing logic
  5. Saves a complete source inventory to plans/reports/scout-report.md

Step 2: Decide Migration Strategy

/sk:brainstorm "given the scout inventory of 15 models and 40+ endpoints with Celery tasks and Stripe: what is the optimal migration strategy? Compare big-bang rewrite vs module-by-module migration. Which modules carry the most risk? What is the optimal migration order?"

What happens: The agent:

  1. Reads the scout inventory and groups models and endpoints into logical modules
  2. Analyzes dependency relationships between modules to determine safe migration order
  3. Scores each module for risk — complexity, external integrations, and test coverage gaps
  4. Recommends big-bang vs incremental approach with explicit trade-off rationale
  5. Outputs a risk-ranked module list and proposed migration sequence

Step 3: Research Framework Mapping

/sk:research "Django ORM to Eloquent migration patterns, Celery to Laravel Queues equivalents, Django REST Framework to Laravel API Resources, Stripe SDK differences between Python and PHP, Django middleware to Laravel middleware mapping"

What happens: The agent:

  1. Fetches current documentation for both source and target frameworks
  2. Identifies direct equivalents (e.g., Django signals → Laravel Events)
  3. Flags areas with no clean mapping that require custom implementation
  4. Documents Stripe SDK behavioral differences between Python and PHP clients
  5. Saves a framework mapping reference to plans/research/ for use during implementation

Step 4: Plan the Migration Module by Module

/sk:plan "module-by-module migration: Module 1 user management (4 models, 8 endpoints). Module 2 product catalog (5 models, 12 endpoints). Module 3 order processing (4 models, 14 endpoints). Module 4 Stripe integration and background jobs"

What happens: The agent:

  1. Creates a phase file for each module under plans/{timestamp}-django-to-laravel/
  2. Maps source files to target files for each module with explicit ownership
  3. Lists every business rule that must be preserved, drawn from the scout inventory
  4. Defines the parity test acceptance criteria for each module before implementation begins
  5. Identifies cross-module dependencies so migration order is enforced

Step 5: Implement One Module at a Time

/sk:cook plans/{timestamp}-django-to-laravel/phase-01-user-management.md

Repeat for each module. Do not start the next module until the current one passes parity tests.

What happens: The agent:

  1. Reads the phase plan and the scout inventory section for the current module
  2. Generates Eloquent models with identical field definitions and relationships
  3. Implements API Resource classes that produce identical response shapes to the Django serializers
  4. Preserves all business rules, validation logic, and error response formats exactly
  5. Flags any Django patterns that have no direct Laravel equivalent and proposes alternatives

Step 6: Write and Run Parity Tests

/sk:test "write parity tests for the user management module — verify identical behavior: same endpoints, same response shapes, same status codes, same error messages as the Django version"

What happens: The agent:

  1. Reads both the scout inventory and the newly implemented Laravel module
  2. Generates integration tests that hit every endpoint with representative payloads
  3. Asserts response shapes, HTTP status codes, and error message formats match the Django version
  4. Tests edge cases captured in the scout inventory (e.g., validation failure responses)
  5. Reports any behavioral divergence as a failing test with the expected vs actual diff

Step 7: Review Each Migrated Module

/sk:code-review --pending

What happens: The agent:

  1. Reads the phase plan’s business rule checklist against the implemented code
  2. Flags missing validations, incorrect error handling, or Django patterns that didn’t translate
  3. Checks that no endpoint silently changed its response shape during implementation
  4. Reviews Eloquent relationships for correctness against the original Django model graph
  5. Produces a review report with blocking findings before the next module begins

Step 8: Security Scan the Complete Codebase

/sk:security-scan

Run once after all modules are complete, not per module.

What happens: The agent:

  1. Runs an OWASP-aligned scan across the entire migrated Laravel codebase
  2. Checks authentication middleware coverage on all protected endpoints
  3. Scans for injection vulnerabilities, mass assignment exposure, and unsafe query construction
  4. Validates that Stripe webhook signature verification is correctly implemented in PHP
  5. Outputs a security report distinguishing framework defaults from real vulnerabilities

Step 9: Commit Throughout the Migration

/sk:git cm

What happens: The agent:

  1. Stages only the files belonging to the current module
  2. Writes a conventional commit message that identifies the module and migration phase
  3. Keeps each module’s migration as an atomic, reviewable commit
  4. Maintains a clean history the client can audit to verify migration completeness

Complete Example: Django Monolith to Laravel for a PHP Team

A client’s maintenance team is PHP-based but they inherited a 3-year-old Django monolith. The monolith has 15 models, 40+ API endpoints, Celery background tasks for order processing and email, a Stripe integration for subscriptions, and partial test coverage. The contract includes a 6-week migration timeline and requires identical API behavior so the existing mobile app does not need changes.

The migration plays out like this:

# Monday — map the full source before touching anything
/sk:scout "map everything in this Django project: models with fields and relationships, views and API endpoints with request/response shapes, middleware, Celery tasks, Stripe integration, custom authentication logic — generate a complete source inventory"

# Tuesday morning — decide the migration approach
/sk:brainstorm "given the scout inventory of 15 models and 40+ endpoints with Celery tasks and Stripe: what is the optimal migration strategy? Compare big-bang rewrite vs module-by-module migration. Which modules carry the most risk? What is the optimal migration order?"

# Tuesday afternoon — research the framework gaps
/sk:research "Django ORM to Eloquent migration patterns, Celery to Laravel Queues equivalents, Django REST Framework to Laravel API Resources, Stripe SDK differences between Python and PHP, Django middleware to Laravel middleware mapping"

# Wednesday — produce per-module plans
/sk:plan "module-by-module migration: Module 1 user management (4 models, 8 endpoints). Module 2 product catalog (5 models, 12 endpoints). Module 3 order processing (4 models, 14 endpoints). Module 4 Stripe integration and background jobs"

# Week 1–2: Module 1 — implement, test, review, commit
/sk:cook plans/{timestamp}-django-to-laravel/phase-01-user-management.md
/sk:test "parity tests for user management: same endpoints, same response shapes, same status codes, same error messages as Django"
/sk:code-review --pending
/sk:git cm

# Week 2–3: Module 2 — product catalog
/sk:cook plans/{timestamp}-django-to-laravel/phase-02-product-catalog.md
/sk:test "parity tests for product catalog module"
/sk:code-review --pending
/sk:git cm

# Week 3–4: Module 3 — order processing
/sk:cook plans/{timestamp}-django-to-laravel/phase-03-order-processing.md
/sk:test "parity tests for order processing module"
/sk:code-review --pending
/sk:git cm

# Week 4–5: Module 4 — Stripe + background jobs
/sk:cook plans/{timestamp}-django-to-laravel/phase-04-stripe-and-jobs.md
/sk:test "parity tests for Stripe integration and queue jobs"
/sk:code-review --pending
/sk:git cm

# Final week — security scan on the complete codebase
/sk:security-scan

Result: The client receives a Laravel codebase with identical API behavior, parity tests proving behavioral equivalence module by module, and a clean security report — all within the 6-week contract window. The mobile app consuming the API requires zero changes.

Time Comparison

TaskManualWith Sun Agent Kit
Source codebase inventory1–2 daysminutes
Migration strategy + planning1–2 daysminutes
Framework research + mapping2–3 daysminutes
Implementation (4 modules)1–2 weeks1–2 days
Parity testing per module2–3 dayshours
Code review + security scan1–2 daysminutes
Total2–4 weeks1–3 days

Best Practices

1. Scout the source completely before touching the target ✅

You cannot plan what you do not know. The scout inventory is the single source of truth for every business rule that must survive the migration. Running /sk:cook before /sk:scout is a guaranteed way to miss logic.

2. Migrate module by module, not file by file ✅

Modules have clear boundaries and independently testable outputs. File-by-file migration produces partially working states that are impossible to verify. Module boundaries keep each migration chunk bounded and reviewable.

3. Write parity tests, not just unit tests ✅

The success metric for a migration is behavioral equivalence — does the Laravel endpoint respond identically to the Django endpoint? Unit tests verify internals; parity tests verify what the client’s mobile app actually receives.

4. Keep API response shapes identical during migration ✅

Resist the temptation to “improve” response shapes mid-migration. Any change to response structure breaks the API contract and requires coordinated client updates. Clean up in a separate pass after the migration is verified.

5. Trying to migrate everything in one /sk:cook run ❌

Four modules with 40+ endpoints cannot be reliably implemented in one pass. Module boundaries exist because they reduce the blast radius of mistakes. A failed cook run on the entire codebase is far harder to diagnose than a failed module.

6. Skipping /sk:test between modules ❌

Logic gaps compound. A missing validation in Module 1 that gets built upon in Module 3 becomes a debugging session across 300 lines of code. Catching it in Module 1 takes minutes. Catching it after Module 4 is done takes hours.

Troubleshooting

Problem: Scout inventory is incomplete — background tasks were missed

Solution: Run a focused follow-up scout: /sk:scout "list all Celery task files, scheduled jobs in settings.py, and any management commands used in production". The initial scout covers the main application tree; a targeted scout captures peripheral processing logic.

Problem: Cook misses a business rule from the Django version

Solution: Cross-reference the scout inventory against the implemented code. If the rule is in the scout report but not in the implementation, re-run cook with the specific rule described explicitly: /sk:cook "implement rate limiting on the login endpoint: 5 attempts per 15 minutes, returns 429 with Retry-After header — matches Django behavior in scout report".

Problem: Parity tests fail on edge cases

Solution: These are real migration bugs, not test issues. The parity tests are working correctly — they found divergence between the Django and Laravel behavior. Fix the Laravel code to match the Django behavior before moving to the next module. Do not adjust the parity tests to pass around the divergence.

Problem: Security scan flags framework-default patterns (e.g., Laravel’s CSRF handling)

Solution: Review the scan report and separate framework defaults from real vulnerabilities. Laravel’s built-in CSRF middleware, Eloquent’s parameterized queries, and default session handling are not security issues — they are correct. Focus the remediation pass on findings outside framework defaults.

Next Steps

  • Rapid Prototyping — when the migrated project needs new features prototyped on the new stack
  • Client Upsale Proposal — propose additional work (test coverage uplift, performance optimization) after the migration is delivered
  • Refactor Legacy Code — clean up the migrated code if it carried over legacy patterns from the source codebase
  • Security Audit & Scan — run a deeper security audit post-migration for clients with compliance requirements

Key takeaway: A migration without a source inventory is a rewrite with uncertainty — /sk:scout maps every model, endpoint, and background task before a single line moves, and per-module /sk:plan + /sk:cook + /sk:test cycles keep each chunk verifiable before the next begins.