---
name: efcore
description: EF Core Commands - Migration and database management
argument-hint: "<command> [options]"
disable-model-invocation: true
---

## Current state (auto-injected)
- Preflight: !`if [ -f .git ] && grep -q '^gitdir: [A-Za-z]:' .git 2>/dev/null && grep -qi microsoft /proc/version 2>/dev/null; then p=$(sed 's/^gitdir: //' .git | tr -d '\r\n'); d=$(echo "${p:0:1}" | tr A-Z a-z); r="${p:2}"; r="${r//\\//}"; printf 'gitdir: %s\n' "$(realpath -m --relative-to="$(pwd)" "/mnt/$d$r")" > .git && echo "repaired"; else echo "ok"; fi`
- Branch: !`git branch --show-current 2>/dev/null || echo "UNAVAILABLE"`

<routing>

Parse `$ARGUMENTS` to determine the command:

| Command | Execution | Model |
|---------|-----------|-------|
| `db-status` | **Inline** `<command-db-status>` | — |
| `db-deploy` | **Inline** `<command-db-deploy>` | — |
| `db-reset` | **Inline** `<command-db-reset>` | — |
| `db-seed` | **Inline** `<command-db-seed>` | — |
| `scan` | **Inline** `<command-scan>` | — |
| `conflicts` | **Inline** `<command-conflicts>` | — |
| `migration` | **Agent** `efcore-migration` | sonnet |
| `squash` | **Agent** `efcore-squash` | sonnet |
| `rebase-snapshot` | **Agent** `efcore-rebase-snapshot` | sonnet |
| (none) | **Inline** `<command-help>` | — |

**Inline commands:** Execute directly following the matching `<command-*>` section below.
**Agent commands:** Delegate via Agent tool:
```
Agent(
  subagent_type: "{agent_name}",
  model: "sonnet",
  prompt: "Execute /efcore {command}.
    Working directory: {cwd}
    Branch: {branch}
    Context: {--context value if provided, else 'auto-detect'}
    Force: {true if --force flag, else false}
    Description: {user description if provided}
  "
)
```

**Flags:**
- `--context <name>` — Force DbContext (`CoreDbContext` or `ExtensionsDbContext`), skip auto-detection
- `--force` — Skip all confirmations (backup still created)

</routing>

<shared>

### WSL Preflight (MANDATORY before any git command)

```bash
if [ -f .git ] && grep -q '^gitdir: [A-Za-z]:' .git 2>/dev/null && grep -qi microsoft /proc/version 2>/dev/null; then
  p=$(sed 's/^gitdir: //' .git | tr -d '\r\n'); d=$(echo "${p:0:1}" | tr A-Z a-z); r="${p:2}"; r="${r//\\//}"
  printf 'gitdir: %s\n' "$(realpath -m --relative-to="$(pwd)" "/mnt/$d$r")" > .git
fi
```

### dotnet-ef PATH fix (MANDATORY before any dotnet ef command)

```bash
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. Install: dotnet tool install --global dotnet-ef"; exit 1; }
fi
```

### Dual DbContext Architecture

| Context | DbContext | Schema | History Table |
|---------|-----------|--------|---------------|
| `core` | `CoreDbContext` | `core` | `core.__EFMigrationsHistory` |
| `extensions` | `ExtensionsDbContext` | `extensions` | `extensions.__EFMigrationsHistory` |

**Deploy order:** Core FIRST, then Extensions (FK dependency).
Both contexts share the same physical database but use different schemas.

### Safety Rules

1. **Production BLOCKED** — Never run on production
2. **Backup MANDATORY** for destructive operations (db-reset, squash)
3. **1 migration per feature** — Recreate, don't accumulate
4. **MCP for naming** — Never hardcode migration names

### Migration Naming (MCP MANDATORY)

Pattern: `{context}_v{version}_{sequence}_{Description}`
**FORBIDDEN:** Manual name calculation. Always use `mcp__smartstack__suggest_migration`.

</shared>

<command-db-status>

## db-status — Fast migration state check

**READ-ONLY: Never modify database or migrations.**

> **Troubleshooting:** See `references/troubleshooting.md` for common errors.

1. Call MCP `mcp__smartstack__check_migrations` with `branch: {current_branch}`
2. If MCP unavailable, fallback: `dotnet ef migrations list --no-build --context {Context}` per context
3. Display compact summary

```
EF CORE — DATABASE STATUS
──────────────────────────
CORE (CoreDbContext)
  Migrations: {applied}/{total} | {pending} pending

EXTENSIONS (ExtensionsDbContext)
  Migrations: {applied}/{total} | {pending} pending

BRANCH: {branch}
  Naming: {ok|warnings}
  1-migration rule: {ok|warning}
```

</command-db-status>

<command-db-deploy>

## db-deploy — Apply pending migrations

**ONLY runs `dotnet ef database update`. Never creates/deletes migrations.**

> **Reference:** See `references/database-operations.md` for connection test and migration count utilities.

1. Detect projects: `INFRA_PROJECT=$(find src -name "*Infrastructure.csproj" | head -1)` and `STARTUP_PROJECT=$(find src -name "*.Api.csproj" | head -1)`
2. Verify `appsettings.Local.json` exists in the API project
3. Apply Core: `dotnet ef database update --context CoreDbContext --project "$INFRA_PROJECT" --startup-project "$STARTUP_PROJECT" --verbose`
4. Apply Extensions: `dotnet ef database update --context ExtensionsDbContext --project "$INFRA_PROJECT" --startup-project "$STARTUP_PROJECT" --verbose`

If connection fails: suggest verifying SQL Server, appsettings.Local.json, or `/efcore db-reset`. See `references/troubleshooting.md`.

```
DB DEPLOY
  Config: appsettings.Local.json
  CORE: {n} migration(s) applied — {success|error}
  EXTENSIONS: {n} migration(s) applied — {success|error|skipped}
```

</command-db-deploy>

<command-db-reset>

## db-reset — Drop + recreate database (DESTRUCTIVE)

**ONLY operates on database. Never creates/deletes migration files.**

> **Reference:** See `references/reset-operations.md` for drop/recreate commands.

1. Detect projects: `INFRA_PROJECT=$(find src -name "*Infrastructure.csproj" | head -1)` and `STARTUP_PROJECT=$(find src -name "*.Api.csproj" | head -1)`
2. **Confirm** (MANDATORY unless `--force`):
   ```
   AskUserQuestion({ question: "DELETE the database? All data will be lost.", options: ["Yes, delete", "No, cancel"] })
   ```
3. **Backup** (optional): `sqlcmd -S "$SERVER" -E -Q "BACKUP DATABASE [$DB] TO DISK='$FILE' WITH FORMAT, INIT, COMPRESSION"`
4. **Drop**: `dotnet ef database drop --force --project "$INFRA_PROJECT" --startup-project "$STARTUP_PROJECT"`
5. **Recreate Core**: `dotnet ef database update --context CoreDbContext --project "$INFRA_PROJECT" --startup-project "$STARTUP_PROJECT"`
6. **Recreate Extensions**: `dotnet ef database update --context ExtensionsDbContext --project "$INFRA_PROJECT" --startup-project "$STARTUP_PROJECT"`
7. **Ask** if user wants `/efcore db-seed`

Block if ASPNETCORE_ENVIRONMENT=Production.

```
DB RESET
  Backup: {path|none}
  CORE: {n} migrations applied — {success|error}
  EXTENSIONS: {n} migrations applied — {success|error}

Next: /efcore db-status, /efcore db-seed
```

</command-db-reset>

<command-db-seed>

## db-seed — Populate test data

**Never drop or recreate database.**

> **Reference:** See `references/seed-methods.md` for detection and execution details.

1. **Detect** seeding method:
   - `HasData()` in EF configs → apply via `dotnet ef database update --context {Context}`
   - `IDataSeeder` / `--seed` CLI arg → `dotnet run --project {startup} -- --seed`
   - SQL script `scripts/seed.sql` → **WARNING**: forbidden by conventions, suggest HasData migration
2. **Execute** the detected method
3. **Verify** insertion

```
DB SEED
  Method: {hasdata|cli-seed|seeder-class}
  Status: {success|error}
  Records: {n} inserted (if available)
```

</command-db-seed>

<command-scan>

## scan — Cross-branch migration scanner

**READ-ONLY. Uses MCP to detect conflicts across branches.**

1. List active worktrees: `git worktree list`
2. For each branch, determine base:
   - `feature/*` → `develop`
   - `release/*` / `hotfix/*` / `develop` → `main`
3. Call MCP `mcp__smartstack__check_migrations` with `branch` + `compareBranch` for each
4. Aggregate risks and recommend merge order

| MCP Type | Level | Action |
|----------|-------|--------|
| (none) | NONE | Merge OK |
| `naming` | LOW | Merge OK |
| `order` | MEDIUM | Attention |
| `dependency` | HIGH | Rebase required |
| `snapshot` | CRITICAL | Manual intervention |

Fallback (MCP unavailable): `git worktree list` + `md5sum Migrations/*ModelSnapshot.cs`

```
EF CORE CROSS-BRANCH SCAN
──────────────────────────
BRANCHES ({n})
  {branch} | {count} migrations | Risk: {level}

RECOMMENDED MERGE ORDER
  1. {branch} (reason)
```

</command-scan>

<command-conflicts>

## conflicts — Migration conflict analyzer (BLOCKING)

**READ-ONLY. Blocks on HIGH/CRITICAL conflicts.**

1. Determine base branch: `feature/*` → `develop`, others → `main`
2. Call MCP `mcp__smartstack__check_migrations` with `branch` + `compareBranch`
3. Display results. **EXIT CODE 1** if HIGH or CRITICAL.

| Type | Level | Exit |
|------|-------|------|
| (none) | NONE | 0 |
| `naming` | LOW | 0 |
| `order` | MEDIUM | 0 (warning) |
| `dependency` | HIGH | 1 (BLOCK) |
| `snapshot` | CRITICAL | 1 (BLOCK) |

Fallback (MCP unavailable): `diff` on ModelSnapshot files.

```
EF CORE CONFLICT ANALYSIS
─────────────────────────
STATUS: {OK|WARNING|CONFLICT}
EXIT CODE: {0|1}

If conflict:
  /efcore rebase-snapshot  (recommended)
  /efcore squash           (alternative)
```

</command-conflicts>

<command-help>

## (no command) — Show available commands

Display the list of available `/efcore` commands:

```
EF CORE COMMANDS
────────────────
  db-status         Migration state check
  db-deploy         Apply pending migrations
  db-reset          Drop + recreate database
  db-seed           Populate test data
  scan              Cross-branch migration scanner
  conflicts         Migration conflict analyzer
  migration         Create/recreate migration
  squash            Consolidate migrations
  rebase-snapshot   Resync ModelSnapshot with parent

Usage: /efcore <command> [--context <name>] [--force]
```

</command-help>
