---
name: step-deploy
description: Deploy pending migrations to database
next_step: null
---

# Database Deploy

## YOUR TASK:

Apply pending EF Core migrations to the local database.

**Requires:** `steps/shared/step-00-init.md` completed

---

## EXECUTION SEQUENCE:

### 1. Environment Check

```bash
# Validate required variables from step-00-init
for VAR_NAME in DBCONTEXT DBCONTEXT_TYPE INFRA_PROJECT STARTUP_PROJECT SELECTED_ENV; do
  eval VAR_VALUE=\$$VAR_NAME
  if [ -z "$VAR_VALUE" ]; then
    echo "ERROR: Required variable $VAR_NAME is not set"
    echo "Run step-00-init first"
    exit 1
  fi
done

echo "Deploy Configuration"
echo "===================="
echo ""
echo "DbContext:   $DBCONTEXT ($DBCONTEXT_TYPE)"
echo "Environment: $SELECTED_ENV"
echo "Database:    $DATABASE_NAME"
echo "Server:      $SERVER_NAME"

# Block production
block_production
```

### 2. Check Pending Migrations

```bash
echo ""
echo "Checking pending migrations..."

EF_STDERR=$(mktemp)
PENDING=$(dotnet ef migrations list \
  --context "$DBCONTEXT" \
  --project "$INFRA_PROJECT" \
  --startup-project "$STARTUP_PROJECT" 2>"$EF_STDERR" | \
  grep -c "(Pending)" || echo "0")

# Check for real errors (not just build output)
if grep -qi "error\|exception\|failed" "$EF_STDERR" 2>/dev/null; then
  echo "WARNING: EF Core reported errors:"
  grep -i "error\|exception\|failed" "$EF_STDERR" | head -5
fi
rm -f "$EF_STDERR"

echo "Pending: $PENDING migration(s)"

if [ "$PENDING" -eq 0 ]; then
  echo ""
  echo "No pending migrations. Database is up to date."
  echo ""
  echo "Next steps:"
  echo "  /efcore migration    # Create new migration"
  echo "  /efcore db-status    # Check status"
  exit 0
fi
```

### 3. List Pending Migrations

```bash
echo ""
echo "Migrations to apply:"

dotnet ef migrations list \
  --context "$DBCONTEXT" \
  --project "$INFRA_PROJECT" \
  --startup-project "$STARTUP_PROJECT" 2>/dev/null | \
  grep "(Pending)" | while read line; do
    echo "  - $line"
  done
```

### 4. Confirmation (if not auto mode)

```yaml
AskUserQuestion:
  header: "Deploy"
  question: "Apply {PENDING} migration(s) to {DATABASE_NAME}?"
  options:
    - label: "Yes, apply"
      description: "Deploy to {SELECTED_ENV} environment"
    - label: "Cancel"
      description: "Do not apply"
  multiSelect: false
```

### 5. Apply Migrations

```bash
echo ""
echo "Applying migrations..."
echo ""

dotnet ef database update \
  --context "$DBCONTEXT" \
  --project "$INFRA_PROJECT" \
  --startup-project "$STARTUP_PROJECT" \
  --verbose
EXIT_CODE=$?

if [ $EXIT_CODE -ne 0 ]; then
  echo ""
  echo "ERROR: Migration failed (exit code: $EXIT_CODE)"
  echo ""
  echo "Troubleshooting:"
  echo "  - Check database connection"
  echo "  - Review migration content"
  echo "  - Try: /efcore db-reset"
  exit 1
fi
```

### 6. Verify

```bash
echo ""
echo "Verifying..."

NEW_PENDING=$(dotnet ef migrations list \
  --context "$DBCONTEXT" \
  --project "$INFRA_PROJECT" \
  --startup-project "$STARTUP_PROJECT" 2>/dev/null | \
  grep -c "(Pending)" || echo "0")

if [ "$NEW_PENDING" -eq 0 ]; then
  echo "All migrations applied successfully."
else
  echo "WARNING: $NEW_PENDING migrations still pending"
fi
```

### 7. Summary

```bash
echo ""
echo "==========================================="
echo "DEPLOY COMPLETE"
echo "==========================================="
echo ""
echo "Database:    $DATABASE_NAME"
echo "Environment: $SELECTED_ENV"
echo "DbContext:   $DBCONTEXT"
echo "Applied:     $PENDING migration(s)"
echo ""
echo "==========================================="
echo ""
echo "Next steps:"
echo "  /efcore db-status    # Verify status"
echo "  /efcore db-seed      # Add test data"
echo ""
```

---

## OUTPUT FORMAT:

```
DEPLOY COMPLETE
===============
Database:    {database_name}
Environment: {env}
DbContext:   {dbcontext}
Applied:     {N} migration(s)

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

---

## ERROR HANDLING:

| Error | Resolution |
|-------|------------|
| Connection failed | Check SQL Server, credentials |
| Migration error | Review migration, consider reset |
| Constraint violation | Check data, may need seed |

---

## OPTIONS:

| Option | Description |
|--------|-------------|
| `--env {name}` | Use appsettings.{name}.json |
| `--verbose` | Show SQL statements |
| `--context {name}` | Specify DbContext |

---

## BOTH CONTEXTS:

**If `RUN_BOTH=true` (auto-detected for client projects with SmartStack NuGet):**

Run the full deploy sequence (steps 2-6) TWICE, in order:

```bash
# 1. Deploy CoreDbContext first (system tables: Users, Roles, Tenants...)
echo "=== Deploying CoreDbContext (core schema) ==="
DBCONTEXT="CoreDbContext"
SCHEMA="core"
# Run steps 2-6 with CoreDbContext...

dotnet ef database update \
  --context "CoreDbContext" \
  --project "$INFRA_PROJECT" \
  --startup-project "$STARTUP_PROJECT" \
  --verbose

# 2. Then ExtensionsDbContext (client tables)
echo ""
echo "=== Deploying ExtensionsDbContext (extensions schema) ==="
DBCONTEXT="ExtensionsDbContext"
SCHEMA="extensions"
# Run steps 2-6 with ExtensionsDbContext...

dotnet ef database update \
  --context "ExtensionsDbContext" \
  --project "$INFRA_PROJECT" \
  --startup-project "$STARTUP_PROJECT" \
  --verbose
```

**Order matters:** Core MUST be deployed first (Extensions may have foreign keys to Core tables).

---

## COMPLETION:

Migrations applied. Use `/efcore db-status` to verify.
