# Artisan-Migrate — Contracts

> Produced by the Reversa **Writer** (phase: generation) · doc_level: `complete`
> Generated on 2026-09-21

**Confidence scale:** 🟢 CONFIRMED · 🟡 INFERRED · 🔴 GAP

External HTTP contract exposed by the `artisan-migrate` unit — a single **inline closure route** `GET /artisan` (no controller, no route name) under the admin group (`['web','admin']`, empty admin prefix). It runs `Artisan::call('migrate', ['--force' => true])` and returns a static HTML string. It requires an authenticated admin session; it is a **side-effecting `GET`** (schema mutation on a verb clients treat as safe). 🟢 (`routes/web.php:31-37`, `config/admin.php:24-30`)

---

## GET `/artisan` — run pending database migrations 🟢 (`routes/web.php:31-37`)

- **Auth:** required; anonymous → `302 auth/login`. 🟢 (`routes/web.php:20,23-29`)
- **CSRF:** not applicable — it is a `GET`, so no CSRF token is required or checked. This is itself a risk (a safe verb performs a side effect). 🔴 (`routes/web.php:31`)
- **Request:**

  | Field | In | Type | Required | Notes |
  |-------|----|------|----------|-------|
  | — | — | — | — | No path, query, or body parameters are read. 🟢 (`routes/web.php:31-37`) |

- **Response — success:** `200 OK`, `Content-Type: text/html`, body exactly `Migrating completed<br>`. Returned after `Artisan::call` returns, **regardless of the exit code**. 🟢 (`routes/web.php:36`)
- **Response — unauthenticated:** `302` redirect to `auth/login`; the closure does not execute. 🟢 (`routes/web.php:20,23-29`)
- **Response — a migration throws:** no try/catch here → the exception propagates as `500` (framework default). 🟡 (`routes/web.php:32-36`)
- **Status codes:** `200` (call returned — success **or** masked non-zero exit) · `302` (→ `auth/login` when unauthenticated) · `500` (a migration throws). 🟢
- **Side effect:** applies every pending migration in `database/migrations/` and records them in the `migrations` ledger table; `--force` runs it without the production confirmation prompt. Not wrapped in a transaction by this route → partial-migration risk on failure. 🟢 (`routes/web.php:32-34`)
- **Idempotence:** re-running with no pending migrations applies nothing but still returns the same body. 🟢

---

## Consumed contracts (owned by other units)

`artisan-migrate` calls no other unit's HTTP endpoint and no external service. It depends on the framework migrator and the database. 🟢

| Reads / writes | Owner | Purpose |
|----------------|-------|---------|
| `Artisan` `migrate` command | Laravel framework | applies migrations non-interactively (`--force`) |
| `migrations` ledger table + `database/migrations/` | database / framework | records and drives which migrations run |
| admin auth guard (`['web','admin']`, `auth/login`) | `auth` unit | authenticates the session before the closure runs |

---

## Producer/consumer relationships

| This unit is… | Counterparty | Contract |
|---------------|--------------|----------|
| **Consumer** | `auth` | relies on the admin middleware / `auth/login` gate for its only access control. 🟢 (`routes/web.php:20,23-29`) |
| **Producer** | operators (human) | the sole caller is an operator hitting the URL to apply migrations; there is no programmatic client in the codebase. 🟡 |

---

## Cross-cutting contract notes

- **Method surface:** a single `GET`; no other verbs on `/artisan`. 🟢 (`routes/web.php:31`)
- **Content type:** no request body; response is `text/html` (a raw `echo`, not a view or JSON). 🟢 (`routes/web.php:36`)
- **Outcome not reported:** the exit code is captured then discarded (`//dd($exitCode);` commented out); the body is static, so a non-zero exit is indistinguishable from success. Reviewed 2026-09-21 — accepted as-is, no change scheduled. 🟢 (`routes/web.php:32,35`)
- **Authorization:** authentication only; any admin may run migrations (ADR-0009). 🟡 (`config/admin.php:29`)
- **Side-effecting GET:** schema mutation over a safe/prefetchable verb, no CSRF barrier and no confirmation. Reviewed with the project owner 2026-09-21 — accepted as a known risk, kept as legacy behaviour. 🟢 (`routes/web.php:31`)
- **No observability:** no log/metric/audit of who triggered the migration or its result. 🔴 (`routes/web.php:32-36`, absence)
