# Environment Differences from Production

This audit runs against a local Dockerized Postgres + dev server, not production. Below are the differences an auditor should know about before trusting any finding.

## 1. Neon Auth is stubbed

Production uses Neon Auth (Better Auth) to manage `neon_auth.user`. In this audit, that schema/table is a minimal local stub created by `db/migrations/0000_qa_neon_auth_stub.sql`:

```sql
CREATE SCHEMA IF NOT EXISTS neon_auth;
CREATE TABLE IF NOT EXISTS neon_auth.user (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email TEXT UNIQUE NOT NULL,
  name TEXT,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
```

Authentication is **not exercised via the real sign-in flow**. Instead, the `dev_session` cookie impersonates roles:

| Cookie value | Impersonates |
|---|---|
| `dev_session=platform_admin` | Cross-brand admin (`role='platform_admin'`, `brand_id=null`) |
| `dev_session=brand_admin` | Single-brand admin |
| `dev_session=store_employee` | Limited-scope employee |

This is gated by `process.env.NODE_ENV !== "production"`. Any bug found in the real Neon Auth flow (sign-in, password reset, MFA, OAuth) **cannot** be reproduced here.

## 2. Migration 0002 (`0002_admin_password.sql`) is marked applied but does not run

The migration references a legacy `users` table that no longer exists in the current schema (the codebase migrated from Auth.js Credentials to Neon Auth). The migration is recorded in `_migrations` so the runner skips it, and the column it would have added (`users.password_hash`) is absent. **This is a separate latent issue** worth a follow-up PR: 0002 should be removed from the migrations directory or rewritten as a no-op.

## 3. New migration `0000_qa_neon_auth_stub.sql` (audit-only)

Added to make migrations runnable without Neon Auth. Should not be applied to production (it would conflict with the real `neon_auth.user` table). Move to a dev-only seed if reused.

## 4. Seed file `db/seeds/2026-qa-audit-scale.sql` (audit-only)

Replaces the broken `db/seed.ts`, which references removed columns (`brand_settings.brand_name`). Idempotent on a clean DB; re-runs without reset will duplicate rows in tables lacking unique constraints on natural keys (orders, order_items).

## 5. Stripe / Resend / Square credentials are placeholders

```
STRIPE_SECRET_KEY=sk_test_placeholder_for_qa_audit
RESEND_API_KEY=re_placeholder_for_qa_audit
SQUARE_ACCESS_TOKEN=square_placeholder_for_qa_audit
```

Real network calls to those services would fail. The audit tests UI navigation, server actions that don't depend on real third-party responses, and DB-backed flows. Stripe checkout, real Resend sends, Square inventory sync — these are out of scope for this audit run.

## 6. Database port

The audit Postgres runs on `:5433`, not `:5432`. `:5432` is occupied by `n8n-postgres-1`.

## 7. The "production-scale" data is sanitized

No real customer PII, no real payment tokens, no real email addresses. All customer emails are `@routecomm.example` (RFC 2606 reserved). Phone numbers follow the +1-555-01xx-xxxx range reserved for fictional use.

## 8. RBAC scope

This audit tests **only** the `platform_admin` role. The QA users `qa-tuxedo@routecomm.example` and `qa-ird@routecomm.example` are seeded for follow-up brand-scoped testing but not exercised here.