# Production Deploy Checklist

This checklist tracks what remains before taking ELIT Gold/Silver Exchange from demo-ready local/sandbox mode to a live production launch.

Do not add real credentials, tokens, client secrets, webhook signature keys, access tokens, or private URLs to this document.

## Current Readiness Summary

- Storefront: ready for client demo.
- Product catalog/detail/cart/checkout: demo-ready.
- Square sandbox product checkout: implemented, hardened, and tested.
- PayPal sandbox product checkout: implemented and tested, including success and cancel flows.
- Successful payment behavior: clears cart after confirmed success.
- Failed or canceled payment behavior: keeps cart available for retry.
- Admin orders/payments/reports/products/service request pages: demo-ready after browser smoke.
- Reporting: counts `PAID` orders only for paid sales, supplier share, and platform markup.
- Public forms: working for support/contact, sell-back, and IRA/trust intake.
- Local demo database: cleaned to preserve one Square `PAID` proof order and one PayPal `PAID` proof order.
- Square webhook: deferred until stable production URL and endpoint implementation.
- Service-fee Square/PayPal flows: marked as coming soon.
- Product image upload: works locally through public uploads, but production storage needs a hosting decision.
- Email notifications, captcha, and rate limiting: production hardening items.

## Launch Blockers

- Choose production hosting and database.
- Configure production domain, DNS, SSL, and `NEXT_PUBLIC_APP_URL`.
- Replace sandbox payment credentials with live Square and PayPal credentials.
- Decide production-safe product image storage.
- Implement and validate Square webhook before relying on external payment state changes.
- Add production monitoring, backup, rate limiting, and anti-spam protections.
- Review legal pages, checkout terms, and sensitive intake wording with qualified counsel.

## Hosting And Infrastructure

- Choose hosting provider.
- Choose production database provider.
- Confirm whether the hosting environment supports persistent local disk.
- Configure production environment variables in the hosting provider dashboard.
- Configure production domain and DNS.
- Enable HTTPS/SSL for all public routes.
- Set `NEXT_PUBLIC_APP_URL` to the exact production domain, for example `https://PRODUCTION_DOMAIN`.
- Confirm build command: `npm run build`.
- Confirm migration command/process before launch.
- Decide seed/demo data policy for production.
- Remove local demo proof records before production unless explicitly retained for staging.
- Create a database backup plan before first migration and before each production migration.
- Create rollback plan for failed deploys.
- Verify uploaded image persistence after deploy.

## Production Environment Variables

Use placeholders only. Secrets must never use `NEXT_PUBLIC_`.

```env
DATABASE_URL="replace-with-production-database-url"
NEXT_PUBLIC_APP_URL="https://PRODUCTION_DOMAIN"

ADMIN_SEED_EMAIL="replace-with-production-admin-email"
ADMIN_SEED_PASSWORD="replace-with-strong-production-admin-password"

SQUARE_ENVIRONMENT="production"
SQUARE_ACCESS_TOKEN="replace-with-live-square-access-token"
SQUARE_LOCATION_ID="replace-with-live-square-location-id"
NEXT_PUBLIC_SQUARE_APPLICATION_ID="replace-with-live-square-application-id"
NEXT_PUBLIC_SQUARE_LOCATION_ID="replace-with-live-square-location-id"
SQUARE_WEBHOOK_SIGNATURE_KEY="replace-with-square-webhook-signature-key"
SQUARE_WEBHOOK_NOTIFICATION_URL="https://PRODUCTION_DOMAIN/api/webhooks/square"

PAYPAL_ENVIRONMENT="live"
PAYPAL_CLIENT_ID="replace-with-live-paypal-client-id"
PAYPAL_CLIENT_SECRET="replace-with-live-paypal-client-secret"
NEXT_PUBLIC_PAYPAL_CLIENT_ID="replace-with-live-paypal-client-id"

STORAGE_PROVIDER="local-or-selected-provider"
CLOUDINARY_CLOUD_NAME="replace-with-cloudinary-cloud-name"
CLOUDINARY_API_KEY="replace-with-cloudinary-api-key"
CLOUDINARY_API_SECRET="replace-with-cloudinary-api-secret"
S3_BUCKET="replace-with-s3-bucket"
S3_REGION="replace-with-s3-region"
S3_ACCESS_KEY_ID="replace-with-s3-access-key-id"
S3_SECRET_ACCESS_KEY="replace-with-s3-secret-access-key"

EMAIL_PROVIDER="disabled-or-selected-provider"
EMAIL_FROM="notifications@PRODUCTION_DOMAIN"
EMAIL_ADMIN_RECIPIENT="ops@PRODUCTION_DOMAIN"
SMTP_HOST="replace-with-smtp-host"
SMTP_PORT="587"
SMTP_USER="replace-with-smtp-user"
SMTP_PASSWORD="replace-with-smtp-password"
RESEND_API_KEY="replace-with-resend-api-key"
SENDGRID_API_KEY="replace-with-sendgrid-api-key"

NEXT_PUBLIC_SHOW_ADMIN_DEMO_LINK="false"
```

## Square Production Checklist

- Obtain live Square Application ID.
- Obtain live Square Access Token.
- Obtain live Square Location ID.
- Verify the live Square Location can take payments.
- Set `SQUARE_ENVIRONMENT=production`.
- Set `NEXT_PUBLIC_SQUARE_APPLICATION_ID` to the live browser-safe application ID.
- Set both Square location variables to the verified live location ID.
- Rotate any sandbox/live secrets that were shared insecurely during development.
- Configure webhook only after stable production or staging domain exists.
- Future Square webhook URL: `https://PRODUCTION_DOMAIN/api/webhooks/square`.
- Future Square webhook events: `payment.created` and `payment.updated`.
- Run a low-value live Square payment test only after launch approval.
- Verify successful live Square payment creates `PAID` order and payment log.
- Verify failed live Square payment keeps cart and does not decrement inventory.

## PayPal Production Checklist

- Obtain live PayPal Client ID.
- Obtain live PayPal Client Secret.
- Set `PAYPAL_ENVIRONMENT=live`.
- Set `PAYPAL_CLIENT_ID` to the live server-side client ID.
- Set `PAYPAL_CLIENT_SECRET` to the live server-side secret.
- Set `NEXT_PUBLIC_PAYPAL_CLIENT_ID` to the live browser-safe client ID.
- Keep PayPal secret server-side only.
- Verify PayPal return and cancel URLs use the production domain through `NEXT_PUBLIC_APP_URL`.
- Run a low-value live PayPal payment test only after launch approval.
- Verify approved live PayPal payment returns to `/payment-success`.
- Verify canceled live PayPal payment returns to `/payment-failed` and keeps cart.

## Webhook Checklist

- Square webhook is not enabled in development because Cloudflare tunnel URLs change.
- Enable webhook only with a stable production or staging URL.
- Implement `/api/webhooks/square` before enabling live webhook reconciliation.
- Verify Square webhook signature validation using `SQUARE_WEBHOOK_SIGNATURE_KEY`.
- Make webhook handling idempotent.
- Update existing `Order` and `PaymentLog` records only.
- Do not create duplicate orders from webhook events.
- Do not decrement inventory again for webhook events if checkout already decremented it.
- Handle `payment.created` and `payment.updated` first.
- Add refund/dispute handling in a later phase unless requested for launch.

## Product Image Storage Decision

Current local upload behavior writes product images under `public/uploads/products` and stores paths such as `/uploads/products/example.webp` in `Product.imageUrls` and `Product.images`. This works for local demo and traditional persistent-disk hosting, but may not persist on serverless hosting such as Vercel.

Current validation:

- Admin session is required.
- Max file size is 5 MB.
- Allowed types are JPG, PNG, and WEBP.
- The upload API returns a local public path.
- Product forms save the selected path into both image fields.
- Public/admin rendering accepts local paths, absolute HTTP(S) URLs, and existing fallback visuals.

Choose one production storage path before launch:

- Cloudinary.
- S3-compatible storage.
- Supabase Storage.
- UploadThing.
- Persistent VPS disk if the selected hosting provider supports it.

Future implementation plan:

- Choose provider based on hosting and client operations needs.
- Add provider credentials to production environment variables.
- Keep `STORAGE_PROVIDER=local` for local demo until the provider is implemented.
- Update the admin upload API to upload files to object storage.
- Return a stable public image URL or stable storage path from the upload API.
- Continue storing that URL/path in `Product.imageUrls` and `Product.images`.
- Keep ProductCard, ProductVisual, product detail, cart, and admin thumbnails reading from the existing product image fields.
- Migrate existing local demo uploads only if those images are needed in production.
- Back up the database before any image URL migration.
- Verify old records without images still fall back cleanly.

Before launch, verify:

- Product image upload works in production.
- Uploaded images survive deploy/restart.
- File type and size validation are enforced.
- Public image URLs render on product cards and product detail pages.
- Admin can replace or remove incorrect product images.
- No storage provider secrets appear in client bundles, public responses, admin pages, or logs.

## Security And Production Hardening

- Rotate admin password before launch.
- Remove or disable any demo credentials.
- Confirm `.env` is not committed.
- Rotate any credentials that were pasted into chats, screenshots, docs, or issue trackers.
- Use HTTPS only.
- Rate limit public forms.
- Rate limit checkout endpoints.
- Add captcha or anti-spam protection for public forms.
- Treat the current in-memory API limiter as a first local/demo layer only.
- Use durable distributed rate limiting for production multi-instance/serverless deployments.
- Consider Redis, Upstash, Cloudflare/WAF rules, hosting-provider rate limits, Cloudflare Turnstile, or reCAPTCHA when provider keys are available.
- Review sensitive form data masking in admin list and detail pages.
- Verify no secrets appear in logs, `PaymentLog.rawResponse`, admin pages, or public API responses.
- Back up the database before migrations.
- Confirm admin session cookie settings for production.
- Restrict access to deployment logs and hosting env variable dashboards.
- Review legal pages and checkout disclaimers before live transactions.

## Email And Notification Checklist

Current state:

- Email sending is disabled/no-op by default.
- A centralized email helper is prepared for optional notifications.
- Support, sell-back, IRA/trust, and service payment submissions can call the helper without breaking the customer flow.
- Missing or unimplemented email provider configuration must not block form submission, checkout, or admin workflows.
- Sensitive intake details must not be included in notification bodies.
- Resend and SendGrid can be enabled with server-only API keys.
- SMTP is documented as a future adapter and should be implemented only if the chosen provider requires it.

Before launch:

- Choose an email provider: SMTP, Resend, SendGrid, or another approved provider.
- Add provider credentials in the production environment dashboard only.
- Keep all email secrets server-side only. Do not use `NEXT_PUBLIC_` for SMTP passwords, API keys, or provider secrets.
- Verify sender domain, SPF, DKIM, and DMARC where applicable.
- Send test notifications for support, sell-back, and IRA/trust submissions.
- Confirm delivery, spam-folder behavior, and reply-to handling.
- Verify notification failures are logged safely and do not expose raw provider errors to customers.
- Avoid sending SSN, bank, payout, signature, payment token, or credential details by email.

Future notification items:

- Order confirmation email.
- Admin new order notification.
- Payment success notification.
- Payment failure/cancel notification if desired.
- Support ticket notification.
- Sell-back request notification.
- IRA/trust application notification.
- Service payment/request notification.
- Admin reply or status update notification if service workflows expand.

## Final Pre-Launch Smoke Test

Run this after production/staging env variables are configured and before public launch.

- Homepage loads.
- `/products` loads and shows physical bullion only.
- Product detail page loads for multiple products.
- Cart add/update/remove works.
- Checkout empty-cart state is safe.
- Square success flow works.
- Square failure flow works and keeps cart.
- PayPal success flow works.
- PayPal cancel flow works and keeps cart.
- Successful payments clear cart.
- Failed/canceled payments do not decrement inventory.
- Admin login works.
- Admin orders show latest Square and PayPal orders.
- Admin payments show provider/status/amount.
- Admin reports count paid revenue only.
- Support form submits and creates admin record.
- Sell-back form submits and creates admin record.
- IRA/trust form submits and creates admin record.
- Service-fees page copy clearly marks unavailable provider flows.
- Product image upload works in production storage.
- Mobile homepage has no major spacing/order issues.
- Mobile products page has usable filters.
- Mobile cart and checkout are usable.
- `npm.cmd run typecheck` passes.
- `npm.cmd run lint` passes.
- `npm.cmd run build` passes.

## Production Launch Hold Points

Do not launch live payments until:

- Production credentials are configured and rotated.
- Live low-value payment tests are approved.
- `NEXT_PUBLIC_APP_URL` matches the live domain.
- Webhook plan is accepted, or the team explicitly accepts temporary manual reconciliation risk.
- Product image storage decision is implemented and tested.
- Database backup and rollback plan are documented.
