Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.aspfox.com/llms.txt

Use this file to discover all available pages before exploring further.

Work through every item before announcing your application publicly.

Security

1

Generate new JWT RSA key pair

Do not use the keys from local development. Generate a fresh pair specifically for production.
openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -pubout -out public.pem
base64 -w 0 private.pem    # copy to JWT_PRIVATE_KEY
base64 -w 0 public.pem     # copy to JWT_PUBLIC_KEY
rm private.pem public.pem
2

Change default admin credentials

Log in to the production admin account and change the password from Admin123! to something secure. Do not skip this — the default password is the same for every scaffolded project.
3

Verify ENVIRONMENT=Production

In production, this setting: disables Swagger (do not expose Swagger publicly), suppresses detailed error messages in API responses, causes missing Stripe configuration to throw on startup rather than warn.
ASPNETCORE_ENVIRONMENT=Production
4

Confirm Swagger is not accessible

Navigate to https://api.yourdomain.com/swagger — it should return 404, not the Swagger UI.
5

Verify HTTPS is configured

  • HTTP requests should redirect to HTTPS
  • SSL certificate is valid (not self-signed in production)
  • HSTS header is present: Strict-Transport-Security: max-age=31536000
6

Verify no secrets are in code or config files

Run this from the project root before deploying:
git log --all --full-history -- '*.env'
git grep -i "sk_live_"
git grep -i "whsec_"
Any results indicate secrets are committed to git. Rotate those keys immediately.

Stripe

1

Switch to live Stripe keys

STRIPE_SECRET_KEY must start with sk_live_, not sk_test_. Check in your environment variables.
2

Webhook endpoint is registered in Stripe Dashboard

Dashboard → Developers → Webhooks. Verify an endpoint exists for your production API URL.
3

All five required events are selected

The endpoint must be subscribed to exactly these events:
  • checkout.session.completed
  • customer.subscription.updated
  • customer.subscription.deleted
  • invoice.payment_failed
  • invoice.payment_succeeded
4

Webhook signing secret is the live endpoint secret

STRIPE_WEBHOOK_SECRET must start with whsec_ and come from the live endpoint, not from the Stripe CLI. The CLI secret and the Dashboard endpoint secret are different values.
5

Complete a real test checkout

Use a real card (not a test card) to complete a Pro checkout. Verify the subscription appears in the Stripe Dashboard and the Billing page in your application shows the updated plan.

Email

1

Sending domain is verified in Resend

Resend Dashboard → Domains. Status must be Verified, not Pending.
2

EMAIL_FROM_ADDRESS uses your verified domain

Must be noreply@yourdomain.com or similar. Not onboarding@resend.dev.
3

Send a test email and check deliverability

Register a new account from the public-facing sign-up page. The verification email should arrive within 30 seconds. Check the spam folder — if it lands there, check your SPF/DKIM/DMARC records.

Database

1

Migrations applied to production database

dotnet ef database update \
  --project src/Acme.Infrastructure \
  --startup-project src/Acme.Api
The command should print No pending migrations. when complete.
2

Seed data applied

The admin user must exist. Run make seed or the equivalent command against the production database once.
3

Database backups are configured

If using a managed database (Railway, Render, RDS), enable automatic backups in the provider dashboard. If self-hosting PostgreSQL, configure pg_dump via cron.

OAuth

1

Production redirect URIs configured in Google Cloud Console

The authorized redirect URI must be https://api.yourdomain.com/api/v1/auth/google/callback. Not localhost.
2

Production callback URL configured in GitHub OAuth App

The authorization callback URL must be https://api.yourdomain.com/api/v1/auth/github/callback. Not localhost.

Frontend

1

VITE_API_URL points to production API URL

Must be https://api.yourdomain.com, not http://localhost:5000.
2

Frontend build uses production environment variables

If using Vite’s build command directly: VITE_API_URL=https://api.yourdomain.com npm run build. Verify the built JavaScript files do not contain localhost.
grep -r "localhost" dist/    # should return no results

Notifications and Redis

1

Redis is running and accessible

The API must be able to connect to Redis. Verify:
curl https://api.yourdomain.com/api/v1/notifications/unread-count \
  -H "Authorization: Bearer <admin-token>"
# Should return {"success":true,"data":{"count":0}}
# A Redis connection failure causes this to return 500