# Test and debug

Before you ship, you exercise the app without infrastructure and validate the structure with a tool. Three things make that possible: the `mock` backend, the simulated auth adapter and `fayz doctor`.

## Mock mode runs everything without a database

A freshly created app is born with `"backend": { "provider": "mock" }`. That means in-memory sample data — the whole app works without Supabase, without `.env`, without a network. Every plugin (and every plugin of yours, via `createSafeDataProvider`) ships a mock provider, so you can develop and demo the full experience before connecting anything. Flipping the switch to real data means changing `provider` in the manifest — see [Supabase](/en/docs/data/supabase).

## Simulated auth

In the same spirit, `createMockAuthAdapter` from `@fayz-ai/auth` gives you a session signed in as a demo user, persisted in the browser — no login screen, no provider. On the manifest-first path, the auth adapter follows `backend.provider`: in `mock`, auth is simulated automatically. That way you can test screens that depend on "being signed in" without setting up real auth. The details are in [Auth — overview](/en/docs/auth/overview).

## `fayz doctor`: the safety net

`doctor` validates the app at rest — without starting anything. Run it after any change:

```bash
npx @fayz-ai/cli doctor
```

It checks three things:

- **Manifest structure and architectural boundaries** — `manifestVersion`, required fields and surface with `scaffold`. A structural problem makes doctor **exit with an error** (exit 1). Today doctor validates the **shape** of the manifest and the boundaries, not the *values* of enums like `theme.brand` or `backend.provider` — validation of those values is on the way (there's an SDK fix in PR).
- **Architecture boundaries** — direct provider SDK imports (`provider-import`), imports outside the supported surface (`off-surface-import`), off-surface dependencies. Reported as **warnings** (soft enforcement — they don't fail the build).
- **Referenced plugins** — every id in the manifest has to resolve to an installed `@fayz-ai/plugin-*` factory wired into the generated code, plus locale coverage.

Typical output for a healthy mock app:

```
⚠ manifest references plugin(s) [dashboard] — each id must resolve to an installed @fayz-ai/plugin-* factory wired in src/plugins.generated.ts or src/config/app.tsx

0 error(s), 1 warning(s)
```

{% callout type="tip" %}
Read the final summary: `N error(s), M warning(s)`. **Errors** you fix before moving on; **warnings** are visibility — the referenced-plugins warning is expected in mock mode (`dashboard` is resolved by the platform bundle) and isn't a problem. A code-first app (with no `app.manifest.json`) runs only the boundary checks and passes.
{% /callout %}

## Plan migrations without touching the database

To debug the data layer, `db apply --dry-run` prints the ordered plan with no network calls and without reading your PAT — always safe to run:

```bash
npx @fayz-ai/cli db apply --dry-run
```

It's how you check *what* would be applied (and in what order: spine → drizzle → seed → plugins → incubator) before applying for real.

---

Next: put the app live with [Static deploy](/en/docs/deploy/static).
