---
name: debug-backend
description: Diagnose and auto-fix SmartStack .NET backend failures
group: DEBUG
allowed-tools: [Read, Edit, Write, Glob, Grep, Bash]  # Bash: diagnostic commands
---

# Skill: Debug Backend — .NET + EF Core + Kestrel

## Context

You operate inside the worktree of a SmartStack client project. The backend is a
.NET 10 project with a Clean 4-layer structure (Domain / Application / Infrastructure / Api).
The Studio dev-runner spawns `dotnet run --no-build --no-launch-profile --urls http://localhost:{port}`.

## Execution plan

### Step 1 — Build

```bash
cd src/{AppCode}.Api
dotnet build --nologo --verbosity normal
```

**Analyze the output**:
- **Exit 0 + "Build succeeded"** → go to step 2
- **Exit ≠ 0 + "Build FAILED"** → parse the MSBuild errors (`error CS####` lines), identify the file+line, fix, re-run

**Common build errors**:
| Error | Cause | Fix |
|--------|-------|-----|
| `CS0246: The type or namespace name 'X' could not be found` | Missing using / missing project reference | Add `using` or `<ProjectReference>` in the .csproj |
| `CS0117: 'X' does not contain a definition for 'Y'` | Renamed property / different lib version | Check the package API, adapt the call |
| `MSB3026: Could not copy ... locked by ...` | Orphaned .Api.exe process | `Get-Process | Where-Object Name -like '*{AppCode}.Api*' | Stop-Process -Force` |
| `NETSDK1045: .NET SDK 10 is required` | Wrong SDK | `dotnet --list-sdks` to check, install .NET 10 |

### Step 2 — Run + health check

```bash
dotnet run --no-build --no-launch-profile --urls http://localhost:5142 --project src/{AppCode}.Api
```

In parallel, in another terminal:
```bash
# Wait 10s then test
curl -fsS http://localhost:5142/health || curl -fsS http://localhost:5142/
```

**Common runtime errors**:

| Symptom in the logs | Cause | Fix |
|--------------------|-------|-----|
| `System.InvalidOperationException: The endpoint Http is missing the required 'Url' parameter` | `Kestrel:Endpoints:Http` without `Url` in appsettings.json | Add `"Url": "http://localhost:5142"` or **remove** the `Kestrel:Endpoints` section (the `--urls` CLI flag is enough) |
| `Microsoft.Data.SqlClient.SqlException: A network-related ... error` | SQL Server not running | `Get-Service MSSQL* | Where Status -eq Running` — start it via `Start-Service MSSQLSERVER` |
| `Microsoft.Data.SqlClient.SqlException: Login failed` | Invalid ConnectionString | Check `ConnectionStrings:DefaultConnection` in appsettings.Development.json |
| `System.InvalidOperationException: No migrations configuration ...` | EF Core migration missing | Sanctioned CLI (raw `migrations add` is blocked by `ef-guard`): `npx --prefer-offline tsx skills/efcore/cli/create/index.ts --spec '{"cwd":"<projectRoot>","description":"Initial"}'` |
| `The migration '...' has already been applied` | DB out of sync | **⚠ DESTRUCTIVE**: `dotnet ef database drop --force` destroys local data — USER-run only (`ef-guard` blocks it; suggest the `! ` prefix). Non-destructive alternative: `dotnet ef migrations list --startup-project src/{AppCode}.Api` (read-only) to see the state, then revert + re-apply via the sanctioned CLI: `npx --prefer-offline tsx skills/efcore/cli/apply/index.ts --spec '{"cwd":"<projectRoot>","targetMigration":"0"}'` (🟡 → show the user, re-run with `"confirm":true`), then the same CLI without `targetMigration` |
| `Unhandled exception. System.Reflection.TargetInvocationException` | DI container — missing service | Look for a missing `AddScoped`/`AddSingleton` in `Program.cs` or `DependencyInjection.cs` |
| `JwtBearer Authentication was not configured` | Empty Jwt.Secret | Check `Jwt:Secret` in appsettings.json |
| `Application started. Press Ctrl+C to shut down.` + `/health` returns ECONNREFUSED | Backend listening elsewhere | Look for `Now listening on:` to find the real port |

### Step 3 — Verify

**3a. Does the /health endpoint respond?**
```bash
curl -I http://localhost:5142/health
```

- HTTP 200 / 204 / 404 → go to 3b
- ECONNREFUSED → backend dead, loop back to step 2

**3b. Does the DB respond through the API?** (critical — port binding OK ≠ working app)
```bash
# The SmartStack /health endpoint must include a DB check. Check the body:
curl -fsS http://localhost:5142/health
# Expected: {"status":"Healthy", ...} or equivalent including a DB entry
```

If `/health` returns 200 but the `database`/`db`/`sqlServer` key is missing or `Unhealthy`:
- Wrong connection string → check `appsettings.Development.json`
- SQL Server down → `Get-Service MSSQL* | Where Status -eq Running`
- Missing DB permissions → the connection string user has no access to the DB

**3c. Does the navigation API respond?** (required for the frontend to load)
```bash
# Without a JWT token, expect 401. With a valid token, expect JSON.
curl -I http://localhost:5142/api/navigation/menu
# 401 → OK (endpoint exists, auth required)
# 404 → routing broken, controllers not mapped
# 500 → exception to investigate (seed not run? empty DB?)
```

## Key files to check

```
src/{AppCode}.Api/
├── Program.cs                     # 4 SmartStack calls: AddSmartStack, InitializeSmartStackAsync, UseSmartStack, MapSmartStack
├── appsettings.json               # ConnectionStrings, Jwt, Kestrel (⚠ no empty Endpoints:Url)
├── appsettings.Development.json   # Dev overrides
└── Properties/launchSettings.json # applicationUrl (ignored by --no-launch-profile but still a reference)

src/{AppCode}.Infrastructure/
└── Migrations/                    # Must contain at least one Initial migration
```

## Final validation

Before declaring "fixed":
1. `dotnet build --nologo` → exit 0, 0 errors
2. `dotnet run --no-build --no-launch-profile --urls http://localhost:5142` is running
3. `curl http://localhost:5142/health` → HTTP 2xx/4xx (not 0)
4. No stack trace in the last 50 lines of stdout

If a fix changes the DB schema, suggest that the user create an EF Core migration.
