# Production Readiness Checklist

This checklist is the release gate for the API and the frontend applications that depend on it. Use it before deploying the backend, before handing the API to frontend engineers, and again before publishing the web app or mobile app.

Current repository status:

- The backend API lives in `apps/api`.
- Shared TypeScript contracts live in `packages/contracts`.
- The current WebApp workspace is `..\Company Documents\Estate Security Platform Strategy\FE\WebApp`.
- The current MobileApp workspace is `..\Company Documents\Estate Security Platform Strategy\FE\MobileApp\gatewise_ng`.

## Workspace Check Commands

Backend API:

```powershell
Push-Location "C:\Users\User\Documents\New project"
npm.cmd --workspace apps/api run db:generate
npm.cmd --workspace apps/api exec prisma migrate status
npm.cmd --workspace apps/api run lint
npm.cmd --workspace apps/api run test
npm.cmd --workspace apps/api run build
Pop-Location
```

WebApp:

```powershell
Push-Location "C:\Users\User\Documents\Company Documents\Estate Security Platform Strategy\FE\WebApp"
npm.cmd run check
npm.cmd run deploy:check
npm.cmd run deploy:check -- --strict
Pop-Location
```

MobileApp:

```powershell
Push-Location "C:\Users\User\Documents\Company Documents\Estate Security Platform Strategy\FE\MobileApp\gatewise_ng"
flutter pub get
flutter analyze --no-pub
flutter test --no-pub
Pop-Location
```

Latest local verification on 2026-05-19:

| Area | Command | Result |
| --- | --- | --- |
| Backend API | `db:generate`, `lint`, `test`, `build` | Passed |
| Backend schema | `prisma validate` | Passed |
| Backend migration status | `prisma migrate status` | Blocked locally because Docker/PostgreSQL is not running; run `db:deploy` on Namecheap after database creation |
| Backend audit | `npm audit --omit=dev` | Passed with 0 vulnerabilities |
| WebApp | `npm.cmd run check` | Passed |
| WebApp | `npm.cmd run deploy:check` | Passed with local-development config warning |
| WebApp | `npm.cmd run deploy:check -- --strict` | Failed as expected on local config; replace localhost with HTTPS production API before deployment |
| MobileApp | `flutter test --no-pub` | Passed |
| MobileApp | `flutter analyze --no-pub` | Failed with 41 info/lint issues; fix or intentionally relax lint severity before production |

## Backend API Gates

Run these from the repository root before every deployment:

```powershell
npm.cmd --workspace apps/api run db:generate
npm.cmd --workspace apps/api exec prisma migrate status
npm.cmd --workspace apps/api run lint
npm.cmd --workspace apps/api run test
npm.cmd --workspace apps/api run build
```

For production deployment, apply migrations with:

```powershell
npm.cmd --workspace apps/api run db:deploy
```

Required backend acceptance checks:

- [ ] Prisma client generates successfully.
- [ ] Prisma migration status reports the database is up to date.
- [ ] Lint passes.
- [ ] Unit tests pass.
- [ ] API build passes.
- [ ] `npm audit --omit=dev` completes successfully or any registry failure is rerun before go-live.
- [ ] `.env` contains production JWT secrets, production database URL, real CORS origins, and live OTP settings.
- [ ] `API_PREFIX=""` for the GateWise API subdomain so production routes are under `https://api.gatewise.ng/v1`.
- [ ] `INTEGRATION_CONFIG_SECRET` is set and backed up securely before super admins store live API keys.
- [ ] `OTP_EXPOSE_DEV_CODE=false` in production.
- [ ] `DEV` is not enabled in `OTP_ENABLED_PROVIDERS` in production.
- [ ] `PAYMENT_GATEWAY_MODE=live` only after live payment credentials and callback URLs are verified.
- [ ] Swagger UI and API sandbox require super-admin console login or a super-admin bearer token.
- [ ] Initial super admin exists by running `npm.cmd --workspace apps/api run db:seed:superadmin`.
- [ ] `SALES_ADMIN` is tested as a platform role with no `estateId`, multi-estate visibility, and no payment access unless enabled by super admin.
- [ ] Sales partner profile, commission percentage, assigned estates, and earnings endpoints are tested with super-admin and sales-admin tokens.
- [ ] Feature access endpoints `/features/catalog`, `/features/me`, and `/features/role-settings/:role` work with super-admin tokens.
- [ ] Estate admins can update only supported resident/guard feature settings for their own estate.
- [ ] Estate-admin feature toggles are blocked when `planEnabled=false` for the estate subscription plan.
- [ ] WebApp and MobileApp checks pass against the deployed API, not only against localhost.
- [ ] Namecheap Stellar Plus cPanel confirms Node.js App, PostgreSQL, SSL, Terminal or SSH, and backup access before launch.
- [ ] PostgreSQL backup and restore has been tested from the live cPanel environment.
- [ ] Shared-hosting resource usage is monitored, with a VPS upgrade decision point documented.

## Shared Frontend Contract Checks

These checks apply to both WebApp and MobileApp.

Authentication:

- [ ] Login calls `POST /auth/login` with a registered phone number.
- [ ] OTP verification calls `POST /auth/verify-otp`.
- [ ] Access token is sent as `Authorization: Bearer <accessToken>`.
- [ ] App refreshes once on `401 Invalid bearer token` by calling `POST /auth/refresh`, then retries the original request.
- [ ] App logs the user out when refresh fails.
- [ ] App handles `429` from auth endpoints by disabling retry temporarily.
- [ ] App does not show the development OTP in production builds.

Role and estate scope:

- [ ] Client routing is based on decoded token role, but API responses remain the source of truth.
- [ ] Feature-level menus, tabs, buttons, and mobile screens are based on `GET /features/me`.
- [ ] MobileApp routes `SALES_ADMIN` to access blocked because partner/sales-admin workspaces are WebApp-only.
- [ ] `403 Feature ... is not enabled` shows a permission message, not a broken screen.
- [ ] Estate-scoped users use their token `estateId` and do not manually switch estates.
- [ ] Super admin screens require explicit estate selection for estate-scoped tables.
- [ ] UI handles `403 Cross-estate access is not allowed`.
- [ ] UI blocks normal app access for `PENDING`, `SUSPENDED`, `REJECTED`, and inactive estates.

Error handling:

- [ ] `400` shows form or business-rule error.
- [ ] `401` refreshes token or returns to login.
- [ ] `403` shows permission or estate access messaging.
- [ ] `404` shows not-found or empty state.
- [ ] `409` highlights duplicate phone, duplicate device, or duplicate reference conflicts.
- [ ] `429` shows throttling feedback.
- [ ] `502/503` shows provider unavailable or retry guidance.

Production connectivity:

- [ ] WebApp origin is present in `CORS_ORIGINS`.
- [ ] MobileApp uses the production `API_BASE_URL` and does not depend on browser CORS.
- [ ] Payment callback URL points to the deployed API domain.
- [ ] Frontend production API base is `https://api.gatewise.ng/v1` for both WebApp and MobileApp.
- [ ] Public UI never links to `https://api.gatewise.ng/docs` or `https://api.gatewise.ng/v1/sandbox`.
- [ ] Admin-only UI links to docs or sandbox only for active `SUPER_ADMIN` users.

## WebApp Checks

Public WebApp:

- [ ] Pricing screen loads `GET /onboarding/subscription-plans`.
- [ ] Estate signup submits `POST /onboarding/estate-admin-signup`.
- [ ] Duplicate admin phone returns a visible `409` message.
- [ ] Signup success shows pending super-admin review.
- [ ] Plan selector loads approved estate data and active plans.
- [ ] Payment provider selector calls `GET /onboarding/payment-providers?estateId=...`.
- [ ] Hosted checkout uses `POST /onboarding/estates/:estateId/payments/initialize`.
- [ ] Browser opens `checkout.checkoutUrl` and shows pending activation after callback.
- [ ] `config/runtime-config.js` uses the deployed HTTPS API base before production.
- [ ] `npm.cmd run deploy:check -- --strict` passes before production.

Super Admin WebApp:

- [ ] Dashboard loads `GET /admin/dashboard`.
- [ ] Feature catalog loads `GET /features/catalog`.
- [ ] Effective feature settings load with `GET /features/me`.
- [ ] Role feature settings update through `PATCH /features/role-settings/:role`.
- [ ] Super admin can enable or disable sales-admin access to individual features.
- [ ] Estate signups list loads `GET /admin/estate-signups`.
- [ ] Review actions call `PATCH /admin/estate-signups/:estateId/review`.
- [ ] Payment confirmation calls `PATCH /admin/estate-signups/:estateId/confirm-payment`.
- [ ] Global payment providers load and update through `/admin/payment-providers`.
- [ ] Per-estate provider overrides update through `/admin/estates/:estateId/payment-providers/:provider`.
- [ ] OTP provider settings load and update through `/admin/otp/config`.
- [ ] Third-party API keys load and update through `/admin/integrations/config`; secret values are never rendered in full.
- [ ] Subscription plan settings load and update through `/admin/subscription-plans`.
- [ ] Super admin can create a custom plan with explicit feature keys and custom pricing.
- [ ] Super admin can enable or pause a sales partner profile and set commission percentage.
- [ ] Super admin can assign or clear a sales admin as the responsible partner for an estate.
- [ ] Global tables can list and update residents, guards, visitors, passes, incidents, visit sessions, and audit logs.
- [ ] Super admin can suspend or reactivate users and estates without direct database access.
- [ ] Docs and sandbox are visible only after super-admin console login.

Sales Admin WebApp:

- [ ] Sales admin login works with a platform-scoped user and no `estateId`.
- [ ] Sales admin can list multiple estates when `ESTATES_VIEW` is enabled.
- [ ] Sales admin can create/update estates when `ESTATES_MANAGE` is enabled.
- [ ] Sales admin can see operational estate data only for enabled feature keys.
- [ ] Sales admin profile shows `Partner` only after super admin enables partner earnings.
- [ ] Sales admin partner earnings use `/admin/sales-partners/me/earnings` only when `SALES_PARTNER_EARNINGS_VIEW` is enabled.
- [ ] Sales admin can contact assigned estate admins only when `SALES_PARTNER_ADMIN_CONTACT` is enabled.
- [ ] Payment confirmation, payment provider settings, OTP settings, and integration keys are hidden and API-blocked by default.
- [ ] Enabling `PAYMENTS_VIEW` or another sales-admin payment feature as super admin immediately unlocks the matching UI after refresh/reload.

Estate Admin WebApp:

- [ ] Estate dashboard blocks access until estate status is `ACTIVE`.
- [ ] Resident list and create flows use `/residents`.
- [ ] Resident phone uniqueness shows `409 A resident with this phone number already exists`.
- [ ] Guard list and create flows use `/guards`.
- [ ] Guard creation makes clear that guards do not self-register.
- [ ] Optional guard `deviceId` assignment is supported.
- [ ] Visitors, visitor passes, incidents, and notifications use the documented endpoints.
- [ ] Cross-estate attempts show a permission message rather than an empty success state.

Security Supervisor WebApp:

- [ ] Supervisor can create guards and residents only inside their estate.
- [ ] Supervisor cannot access super-admin routes.
- [ ] Supervisor incident and offline operation screens use estate-scoped data only.

## MobileApp Checks

Shared Mobile:

- [ ] Secure storage keeps refresh token and guard `deviceId`.
- [ ] Access token is not stored in plain text if the mobile platform provides secure storage.
- [ ] API base URL is supplied through environment/flavor configuration instead of hardcoded localhost values.
- [ ] Feature flags from `GET /features/me` are stored in app state and used for screen/action availability.
- [ ] App survives token expiry while online by refreshing once after `401 Invalid bearer token`.
- [ ] App shows an offline state when network requests fail.
- [ ] App retries idempotent reads safely after network recovery.
- [ ] App does not cache another user's data after logout.
- [ ] `flutter analyze --no-pub` passes.
- [ ] `flutter test --no-pub` passes.

Resident MobileApp:

- [ ] Resident login uses phone OTP.
- [ ] Resident can create visitors through `POST /visitors`.
- [ ] Resident can create passes through `POST /visitors/passes`.
- [ ] Pass list loads through `GET /visitors/passes`.
- [ ] QR token and manual `visitorCode` are both visible for a pass.
- [ ] Expired, revoked, exhausted, or used-up passes display blocked status.
- [ ] Resident app does not show pass revoke unless the API role support is added.

Guard MobileApp:

- [ ] Guards are created by estate admin or supervisor, not by self-signup.
- [ ] Guard app generates one stable device ID on first install and reuses it.
- [ ] Guard app sends `deviceId` on scan, manual check-in, checkout, and offline sync.
- [ ] First scan binds the device when the guard has no assigned device.
- [ ] A different device shows `403 Guard account is assigned to a different device`.
- [ ] Guard app has an admin-assisted rebind flow for lost or replaced devices.
- [ ] Offline bootstrap calls `GET /offline/bootstrap`.
- [ ] QR scan check-in calls `POST /checkin/scan`.
- [ ] Manual code check-in calls `POST /checkin/manual`.
- [ ] Checkout calls `POST /checkin/checkout`.
- [ ] Incident report calls `POST /incidents`.
- [ ] Offline sync calls `POST /offline/sync` with stable client event IDs.
- [ ] The app prevents duplicate local submission of the same offline event.
- [ ] Scanner UI handles invalid QR, expired pass, max-use exhausted, wrong estate, and already checked-out states.

MobileApp API compatibility checks:

- [ ] `lib/core/api/api_client.dart` does not send the literal path `/onboarding/estates/:estateId/payments/initialize`; it must interpolate the selected estate ID.
- [ ] Mobile payment UI only calls hosted checkout after estate signup approval and plan/provider selection.
- [ ] Mobile supervisor UI uses existing backend routes or backend adds matching supervisor routes. Current backend has no `/supervisor/dashboard` or `/supervisor/incidents`.
- [ ] Mobile documentation does not reference removed or unsupported routes such as `GET /auth/me` or `/visitor-passes`; current backend routes use `/visitors/passes`.
- [ ] Resident pass revoke UI is hidden unless the logged-in role is allowed by the backend.
- [ ] Guard check-in, checkout, and offline sync always include the stable stored `deviceId`.

## End-to-End Scenario Tests

Run these complete flows before go-live:

- [ ] Super admin logs into console, opens Swagger, and opens sandbox.
- [ ] Public web signup creates estate in `PENDING` with signup status `PENDING_APPROVAL`.
- [ ] Super admin approves signup.
- [ ] Estate admin selects Starter, Growth, or Enterprise plan.
- [ ] Estate admin initializes payment with an enabled provider.
- [ ] Payment checkout completes in sandbox or live provider test mode.
- [ ] Super admin confirms payment and estate becomes `ACTIVE`.
- [ ] Estate admin logs in after activation.
- [ ] Estate admin creates resident.
- [ ] Estate admin creates guard.
- [ ] Resident logs into mobile app.
- [ ] Resident creates visitor and pass.
- [ ] Guard logs into mobile app.
- [ ] Guard scans QR and creates visit session.
- [ ] Guard checks out visitor.
- [ ] Super admin can see audit logs for onboarding, payment, user creation, check-in, and checkout.

## Negative Scenario Tests

These should fail with clear UI feedback:

- [ ] Duplicate resident phone.
- [ ] Duplicate guard phone.
- [ ] Duplicate estate admin signup phone.
- [ ] Non-super-admin tries `/admin/*`.
- [ ] Estate admin tries another estate's `estateId`.
- [ ] Guard tries to check in with a different `guardId`.
- [ ] Guard checks in from a different bound device.
- [ ] Resident creates pass for another estate.
- [ ] Expired visitor pass scan.
- [ ] Revoked visitor pass scan.
- [ ] Pass max uses exhausted.
- [ ] Inactive account login.
- [ ] Pending estate user login.
- [ ] OTP provider disabled or unavailable.
- [ ] Payment provider disabled globally.
- [ ] Payment provider disabled for selected estate.
- [ ] Docs or sandbox opened without super-admin console login.

## API Change Review Triggers

Any backend change in these areas must trigger WebApp and MobileApp review:

- Auth token payload, token expiry, refresh behavior, or OTP response.
- Role names, account statuses, estate statuses, or signup statuses.
- DTO request fields or response shape for onboarding, residents, guards, visitors, passes, check-in, offline sync, admin, OTP, or payments.
- Error messages used by frontend form handling.
- CORS policy, API prefix, versioning, or deployment domain.
- Payment provider mode, callback behavior, checkout response, or confirmation flow.
- Guard device-binding behavior.
- Offline bootstrap or offline sync behavior.

## Go-Live Signoff

Do not mark the API production-ready for frontend launch until:

- [ ] Backend API gates pass.
- [ ] WebApp checks pass in staging.
- [ ] MobileApp checks pass in staging on at least one Android device and one iOS device or simulator.
- [ ] End-to-end scenario tests pass.
- [ ] Negative scenario tests pass.
- [ ] Live OTP delivery is verified with at least two providers or one provider plus configured fallback.
- [ ] Live payment provider test transactions are verified.
- [ ] Database backup and restore process is documented.
- [ ] Monitoring and error log access are available to the maintainer.
- [ ] Public legal documents are reviewed and published without internal deployment, secret, sandbox, or private API details.
- [ ] Privacy, data protection, deletion/anonymization, cookie/cache, terms, and DPA pages are linked from the WebApp.
- [ ] Legal policy changes are made in `docs/legal` and synced to the WebApp with `npm.cmd run legal:sync`.
- [ ] MobileApp legal/privacy screens link to `https://gatewise.ng/legal` and related WebApp policy URLs instead of embedding separate policy copies.
- [ ] Data deletion/anonymization request workflow has been tested with resident, visitor, guard, and estate admin records.
