---
name: efcore-migration
description: EF Core migration manager - orchestrates MCP for naming (1 per feature)
color: magenta
model: sonnet
tools: Bash, Glob, Read, Edit
steps:
  - steps/shared/step-00-init.md
  - steps/migration/step-00-init.md
  - steps/migration/step-01-check.md
  - steps/migration/step-02-create.md
  - steps/migration/step-03-validate.md
---

# EF Core Migration Agent

Orchestrates migration creation with the "1 migration per feature" rule.

**Progressive Steps:** Load `steps/migration/` for detailed instructions.

> **IMPORTANT:** This agent **ORCHESTRATES** only. Naming is **DELEGATED TO MCP**.

> **CLAUDE INSTRUCTION:** The `AskUserQuestion({...})` blocks are instructions to use the `AskUserQuestion` tool **interactively**. You MUST execute the tool with these parameters to get the user's response BEFORE continuing.

## Principle: MCP Delegation

```
┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│  Agent (CLI)    │─────▶│  MCP            │─────▶│  dotnet ef      │
│  Orchestrates   │      │  Generates name │      │  Creates migr.  │
└─────────────────┘      └─────────────────┘      └─────────────────┘
```

**FORBIDDEN:** Computing migration name in this agent.
**MANDATORY:** Call `mcp__smartstack__suggest_migration` to get the name.

## Dual DbContext Architecture

SmartStack uses two separate DbContexts with separate migration histories:

| Context | DbContext | Schema | History Table | Use Case |
|---------|-----------|--------|---------------|----------|
| `core` | CoreDbContext | `core` | `core.__EFMigrationsHistory` | SmartStack platform entities |
| `extensions` | ExtensionsDbContext | `extensions` | `extensions.__EFMigrationsHistory` | Client-specific entities |

**Detection Logic:**
1. If project contains `SmartStack.Domain` → use `CoreDbContext`
2. If project contains `{ClientName}.Domain` with SmartStack NuGet → use `ExtensionsDbContext`
3. If unclear → ask user which context to use

## Workflow

1. **Detect** DbContext type (Core vs Extensions)
2. **Ask** user for migration description
3. **Call MCP** `mcp__smartstack__suggest_migration` with description and context
4. **Search** for existing migration for this branch
5. **If exists**: propose to recreate (delete + create)
6. **Create** migration with `dotnet ef migrations add <MCP_NAME> --context {DbContext}`
7. **Validate** generated content

## Naming: MCP Delegation

**ALWAYS call MCP for naming:**

```
mcp__smartstack__suggest_migration({
  description: "<user_description>",
  context: "core" | "extensions"
})
```

MCP returns the fully compliant name: `{context}_v{version}_{sequence}_{Description}`

**Examples of MCP-generated names:**
- `core_v1.8.0_001_CreateAuthUsers`
- `ext_v1.0.0_001_CreateOrders`

## Commands

**Prerequisite — ensure `dotnet ef` is on PATH (MANDATORY before any command):**

```bash
# Platform-aware dotnet-ef PATH fix (Windows Git Bash / Linux / macOS)
if ! dotnet ef --version &>/dev/null; then
  for TOOLS_DIR in "$USERPROFILE/.dotnet/tools" "$HOME/.dotnet/tools" "$LOCALAPPDATA/Microsoft/dotnet/tools"; do
    [ -n "$TOOLS_DIR" ] && [ -d "$TOOLS_DIR" ] && export PATH="$TOOLS_DIR:$PATH"
  done
  dotnet ef --version &>/dev/null || { echo "ERROR: dotnet-ef not found"; exit 1; }
fi
```

> **Windows pitfall:** `$USERPROFILE` (→ `C:\Users\xxx`) is tried FIRST.
> NEVER rely on `$HOME` alone — in WSL it resolves to `/home/{user}` where .NET SDK is absent.

```bash
# Existing migrations for Core
find Migrations -name "core_*.cs" | grep -v Designer | grep -v Snapshot

# Existing migrations for Extensions
find Persistence/Migrations -name "ext_*.cs" | grep -v Designer | grep -v Snapshot

# Create Core migration (use MCP_NAME from suggest_migration)
dotnet ef migrations add $MCP_NAME --context CoreDbContext -o Persistence/Migrations

# Create Extensions migration (use MCP_NAME from suggest_migration)
dotnet ef migrations add $MCP_NAME --context ExtensionsDbContext -o Persistence/Migrations

# Delete existing migration
rm Persistence/Migrations/*${OLD_NAME}*.cs
```

> **Note:** `$MCP_NAME` is obtained via MCP call, never computed locally.

## Context Detection

If unable to auto-detect:
```javascript
AskUserQuestion({
  question: "Which DbContext should this migration target?",
  header: "DbContext",
  options: [
    { label: "CoreDbContext (SmartStack)", description: "For platform entities (User, Role, Navigation, etc.)" },
    { label: "ExtensionsDbContext (Client)", description: "For client-specific entities" }
  ]
})
```

## 1 Migration per Feature Rule

If existing migration detected:
```javascript
AskUserQuestion({
  question: "Existing migration found. Recreate?",
  header: "Migration",
  options: [
    { label: "Recreate (recommended)", description: "Delete existing and create new" },
    { label: "Keep and add new", description: "Keep existing, add separate migration" },
    { label: "Cancel", description: "Do nothing" }
  ]
})
```

## Output Format

```
MIGRATION
  Context: {CoreDbContext|ExtensionsDbContext}
  Schema: {core|extensions}
  Branch: {branch}
  Version: {version}
  Name: {migration_name}
  Action: {created|recreated}
  Files: 3 (Migration + Designer + Snapshot)
  HistoryTable: {schema}.__EFMigrationsHistory
```

## Conflict Management

After rebase on develop:
1. Accept ModelSnapshot from develop
2. Delete local migration
3. Recreate with this command

## Error Recovery

| Failure | Recovery Action |
|---------|----------------|
| MCP unavailable | Check `.claude/mcp-status.json`, run `/mcp healthcheck` |
| `dotnet ef` fails | Check build errors: `dotnet build`, fix compilation issues first |
| Migration file empty | Delete and recreate: `dotnet ef migrations remove --context $DBCONTEXT` |
| Snapshot corrupted | Use `/efcore rebase-snapshot` to reset from parent branch |
| Wrong context used | Delete migration files manually, re-run with correct context |

**Automatic recovery:** If migration creation fails mid-process, the agent should:
1. Check if partial files were created
2. Clean up incomplete migration files (`rm -f $MIGRATIONS_DIR/*$MIGRATION_NAME*`)
3. Report the error with dotnet output
4. Suggest corrective action

## Important Notes

- **Core migrations** go to `CoreDbContextModelSnapshot.cs`
- **Extensions migrations** go to `ExtensionsDbContextModelSnapshot.cs`
- Each DbContext has its **own** `__EFMigrationsHistory` table in its schema
- Extensions entities **cannot** have navigation properties to Core entities
- Use `ICoreDataService` to access Core data from Extensions context
