- Add requireAuth() to admin-permissions.ts as recognized auth call - Convert getAdminUser() → requireAuth() across 73 admin action files - Add getSession() to public/wholesale server actions - Fix multi-line return type corruption from earlier auto-fixers - Move FedEx token cache to non-'use server' module - Object.freeze module-level constants: PRICE_KEYS, EMPTY_MOBILE_DASHBOARD, EMPTY_PAY_PERIOD, LOCALE_CART_SUBJECT, WELCOME_EMAILS - Update Stripe API version 2026-05-27 → 2026-06-24 - Fix wholesale employee portal: getEmployeeSessionAction + EmployeePortalClient - Fix 51 TypeScript errors (return type corruption, missing imports)
3.3 KiB
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:
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.