---
name: migrate
description: Migrate an existing SmartStack client project from one platform version to another (currently v3.34 → v3.46). Detects the current version, applies declarative rules (renames, signature updates, layout consolidation, theme tokens), then runs validation checks. Designed for clients on older CLI versions who want to upgrade without redoing /apex from scratch.
argument-hint: "[--from=<version>] [--to=<version>] [--scope=backend|frontend|all] [--dry-run] [--apply]"
model: sonnet
allowed-tools: Read, Grep, Glob, Bash, Edit, Write
---

## Current state (auto-injected)

- Project root: !`pwd 2>/dev/null`
- Detected SmartStack package version: !`grep -oP '"@atlashub/smartstack":\s*"\K[^"]+' web/smartstack-web/package.json 2>/dev/null || cat src/SmartStack.Api/*.csproj 2>/dev/null | grep -oP 'SmartStack[A-Za-z.]*"\s*Version="\K[^"]+' | head -1 || echo "unknown"`
- Detected legacy patterns: !`grep -rl "ApplicationZone\|<\(AdminLayout\|BusinessLayout\|UserLayout\)" src/ web/ 2>/dev/null | head -5 || echo "none"`
- Last migration run: !`cat .claude/cache/migrate.json 2>/dev/null | head -3 || echo "no previous run"`

<objective>
Patch an existing client project (one already generated by an older CLI version) so that it conforms to the latest SmartStack platform version. Current rule set covers `v3.34 → v3.46` (the breaking changes shipped in iteration 1 of the v3.46 alignment work : `ApplicationZone` removal, layout consolidation 7→4, NavigationApplication.Create signature change, Tailwind tokenization).

This skill exists because :
- A client app generated on CLI v3.34 has `Zone = ApplicationZone.Business` hardcoded everywhere — **cannot compile** against v3.46 NuGet packages.
- Re-running `/apex` from scratch would lose the client's business logic.
- Manually patching is error-prone (40+ files to touch on a real project).

The rules are **declarative** (in `references/v3.34-to-v3.46.md`), so adding a new migration target later is just a new reference doc + a register entry.
</objective>

<quick_start>
```bash
/migrate                              # Detect version + dry-run report
/migrate --from=3.34 --to=3.46        # Explicit version pair
/migrate --dry-run                    # Print proposed changes without writing
/migrate --apply                      # Apply all rules (asks confirmation per category)
/migrate --scope=frontend --apply     # Only frontend rules
/migrate --scope=backend --apply      # Only backend rules
```
</quick_start>

<subcommands>

| Command | Effect |
|---|---|
| `/migrate` (no args) | Auto-detect from→to, run dry-run, print report |
| `/migrate --from=X --to=Y` | Force version pair (for testing) |
| `/migrate --dry-run` | Default — report only, no file edits |
| `/migrate --apply` | Apply rules. Asks confirmation per category (backend / frontend / seed / config) |
| `/migrate --scope=<s>` | Restrict to one layer |
| `/migrate --rules` | List all available migration paths and their rule files |

</subcommands>

<workflow>

## Step 0 — Detect from-version (if not provided)

```bash
# Look at @atlashub/smartstack version
PKG_VER=$(grep -oP '"@atlashub/smartstack":\s*"\K[^"]+' web/smartstack-web/package.json 2>/dev/null | sed 's/[\^~]//g' | cut -d. -f1-2)

# Look at SmartStack NuGet versions
NUGET_VER=$(grep -hPoR 'PackageReference\s+Include="SmartStack[^"]*"\s+Version="\K[^"]+' src/ 2>/dev/null | sort -u | head -1 | cut -d. -f1-2)

# Look at legacy patterns to confirm
HAS_ZONE=$(grep -rl "ApplicationZone\." src/ 2>/dev/null | wc -l)
HAS_LEGACY_LAYOUT=$(grep -rlE "<(AdminLayout|BusinessLayout|UserLayout|HRLayout|SalesLayout)\b" web/ src/ 2>/dev/null | wc -l)

# Decide source version
if [ "$HAS_ZONE" -gt 0 ] || [ "$HAS_LEGACY_LAYOUT" -gt 0 ]; then
  FROM_VERSION="3.34"   # Pre-v3.46 platform
else
  FROM_VERSION="${PKG_VER:-unknown}"
fi
```

## Step 1 — Pick the rule file

Map `(from, to)` to a rule file under `references/` :

| from → to | Rule file |
|---|---|
| `3.34 → 3.46` | [references/v3.34-to-v3.46.md](references/v3.34-to-v3.46.md) |
| (future) `3.46 → 3.47` | references/v3.46-to-v3.47.md |
| any unsupported pair | abort with explicit error + suggested manual path |

Load the rule file and parse the rule list (each rule has `id`, `category`, `description`, `detect_pattern`, `replace_pattern`, `glob`, `severity`, `requires_confirmation`).

## Step 2 — Detect applicable rules (dry-run)

For each rule in the file :

1. Run the `detect_pattern` (grep) over `glob` paths to find candidate files
2. Compute the matched count
3. If 0 matches : skip (already migrated)
4. If ≥ 1 match : add to "applicable rules" list

Build the dry-run report :

```
================================================================================
              MIGRATION DRY-RUN — {from} → {to}
================================================================================
Project root: {pwd}
Source version detected: {FROM_VERSION}  (via {package.json | NuGet | legacy patterns})
Rule file:  references/v{from}-to-v{to}.md  ({total_rules} rules)

[BACKEND]  ({applicable_be_count} of {total_be_count} rules applicable)

  R-BE-001  ApplicationZone enum removal
            severity: BLOCKING   files: 6
            sample:  src/SmartStack.Infrastructure/Persistence/Seeding/Data/NavigationApplicationSeedData.cs:23
                     Zone = ApplicationZone.Business

  R-BE-002  NavigationApplication.Create signature
            severity: BLOCKING   files: 2
            sample:  src/SmartStack.Infrastructure/.../SeedDataProvider.cs:46
                     NavigationApplication.Create(ApplicationZone.Business, code, label, ...)

  R-BE-003  AddDbContext alias rename (if applicable)
            severity: WARNING    files: 0    (no occurrence — skipped)

[FRONTEND]  ({applicable_fe_count} of {total_fe_count} rules applicable)

  R-FE-001  Legacy domain-specific layouts (AdminLayout, BusinessLayout, UserLayout, …)
            severity: BLOCKING   files: 4
            sample:  web/smartstack-web/src/App.tsx:127
                     <Route path="/sales" element={<SalesLayout />}>

  R-FE-002  Hardcoded Tailwind colors → CSS vars
            severity: WARNING    files: 12

  R-FE-003  mergeRoutes() → PageRegistry.register()
            severity: BLOCKING   files: 1

[SEED]  ({applicable_seed_count} of {total_seed_count} rules applicable)
  …

[CONFIG]  ({applicable_cfg_count} of {total_cfg_count} rules applicable)
  …

--------------------------------------------------------------------------------
SUMMARY : {total_applicable} rules applicable across {total_files} files
          {blocking} BLOCKING — must be fixed before the project compiles against v{to}
          {warning} WARNING — should be fixed soon
================================================================================
```

If `--dry-run` (default) → stop here, exit 0.

## Step 3 — Apply mode (`--apply`)

Group applicable rules by **category** (BACKEND / FRONTEND / SEED / CONFIG). For each category :

```yaml
AskUserQuestion:
  header: "Apply BACKEND rules?"
  question: "{N} BACKEND rules will modify {M} files (e.g. R-BE-001, R-BE-002). Apply?"
  options:
    - label: "Yes, apply all BACKEND rules"
      description: "Run all BLOCKING + WARNING rules in this category"
    - label: "Yes, BLOCKING only"
      description: "Apply only BLOCKING (safer for review)"
    - label: "Skip this category"
      description: "Don't touch BACKEND files"
    - label: "Review one by one"
      description: "Confirm before each rule"
```

For each rule the user accepts :
1. Read each candidate file
2. Apply the `replace_pattern` (often a regex substitution, sometimes a whole-block rewrite — see rule definition)
3. Save the file
4. Track the change in a per-rule changelog

After every rule in the batch is applied, build the post-apply report and run **post-validation** (Step 4).

## Step 4 — Post-validation

```bash
# Backend compilation (smoke test)
if [ "$SCOPE" != "frontend" ]; then
  cd src/SmartStack.Api 2>/dev/null && dotnet build --nologo 2>&1 | tail -20 | tee /tmp/migrate-build-be.log
fi

# Frontend compilation
if [ "$SCOPE" != "backend" ]; then
  cd web/smartstack-web 2>/dev/null && npx tsc -b --noEmit 2>&1 | tail -20 | tee /tmp/migrate-build-fe.log
fi

# Run apex post-checks if available
if [ -f templates/skills/apex/references/checks/seed-checks.sh ]; then
  bash templates/skills/apex/references/checks/seed-checks.sh 2>&1 | tail -30
fi
```

Print the validation report. If errors remain : explicit list of "manual fixes still needed" + suggested next action (`/debug` skill).

## Step 5 — Cache and summary

```bash
mkdir -p .claude/cache
cat > .claude/cache/migrate.json << EOF
{
  "lastRun": "$(date -Iseconds)",
  "from": "{from}",
  "to": "{to}",
  "scope": "{scope}",
  "rulesApplied": {N},
  "filesChanged": {M},
  "buildPassed": {true|false},
  "remainingIssues": {K}
}
EOF
```

Print a final summary :

```
================================================================================
              MIGRATION COMPLETE — {from} → {to}
================================================================================
Rules applied : {N} ({blocking} BLOCKING, {warning} WARNING)
Files changed : {M}
Build status  : {OK | FAILED}
Manual fixes  : {K} remaining (see /tmp/migrate-build-*.log)

Next steps :
  1. Review changes: git diff
  2. Run tests: dotnet test + npm test
  3. Commit migration: /gitflow commit
  4. If issues remain: /debug
================================================================================
```

## Step 6 — Exit code

- 0 if all rules applied and build passes
- 1 if any rule failed to apply (likely needs manual intervention)
- 2 if build doesn't pass after migration

</workflow>

<safety>

- **Always run dry-run first** : the default mode. Forces the user to see the diff before any file is touched.
- **Per-category confirmation** in `--apply` mode. No "yes to all" shortcut.
- **Backup is the user's responsibility** — recommend `git stash` or `git commit` before running `--apply`. The skill will print this as a banner.
- **Some rules cannot be safely automated** : signature changes that depend on context. Those rules have `requires_confirmation: true` in the rule file, and the skill walks through them one by one.
- **Never modify files outside the project root** (cwd). Defensive `pwd`-based path resolution.

</safety>

<rule_file_format>

Each `references/v{from}-to-v{to}.md` file contains a YAML-fenced rule list :

````markdown
# Migration rules: v{from} → v{to}

```yaml
rules:
  - id: R-BE-001
    category: backend
    description: ApplicationZone enum removed in v3.46
    detect_pattern: "ApplicationZone\\.\\w+"
    replace_pattern: |
      # Custom multi-line replacement (see "implementations" below)
    glob: "src/**/Seeding/Data/**/*.cs"
    severity: BLOCKING
    requires_confirmation: false
    references:
      - templates/skills/apex/references/core-seed-data.md
      - templates/skills/application/references/provider-template.md

  - id: R-BE-002
    category: backend
    …
```

## Implementations

Some rules are too complex for a single regex. The "implementation" section
provides a step-by-step Bash/sed/Edit recipe per rule.

### R-BE-001 — ApplicationZone removal

For each file matching the glob :
1. Remove the line `Zone = ApplicationZone.Business,`
2. Insert two lines :  `IsPersonal = false,` and `IsOpen = false,`
3. … (full recipe)
````

The skill parses the YAML block, then for each rule with `requires_confirmation: true` it falls back to the implementation recipe (read + execute step by step).

</rule_file_format>

<known_limitations>

- **Single migration path supported today** : `v3.34 → v3.46`. Adding `v3.46 → v3.47` is a new rule file, not a code change.
- **No multi-hop chaining yet** : if a project is on `v3.20`, you can't go straight to `v3.46`. Manual intervention required.
- **Doesn't migrate database schema** — rules are code-only. Schema migration is `/efcore migration` territory.
- **Heuristic version detection** : if `package.json` lacks `@atlashub/smartstack`, the skill falls back to grepping legacy patterns. Always confirm the detected version before `--apply`.

</known_limitations>

<success_criteria>
- Detects current SmartStack version from project artifacts
- Picks the correct rule file based on (from, to)
- Dry-run report lists every applicable rule with file/line evidence
- Apply mode confirms per category before touching files
- Post-validation runs `dotnet build` and `tsc --noEmit` to catch new compile errors
- Cache record allows subsequent `/migrate` runs to skip already-applied rules
- Exit code reflects success/failure for CI scripting
</success_criteria>
