Deployment, configuration, and administration reference for AI Reality Check.
AI Reality Check is deployed on Railway with a Next.js web service and a PostgreSQL database. The app is built with `npm run build` and started with `npm start`.
Since Railway auto-deploy from GitHub can silently stop working, always deploy manually: `cd ai-reality-check && railway up`. This builds and deploys in one step.
The production domain is airealitycheck.ai, configured in Railway's custom domain settings. SSL is handled automatically via Let's Encrypt (TLS 1.3).
DATABASE_URL — PostgreSQL connection string (provided by Railway). ENCRYPTION_KEY — 32-byte hex key for AES-256-GCM encryption. ANTHROPIC_API_KEY — API key for Claude (Trust Check + Chatbot). NEXT_PUBLIC_APP_URL — https://airealitycheck.ai. RESEND_API_KEY — API key for magic link emails.
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET — Google OAuth credentials. GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET — GitHub OAuth credentials. All OAuth redirect URIs must point to /api/auth/callback/google and /api/auth/callback/github respectively.
Never commit environment variables to git. All secrets are managed via Railway's environment variable settings. The ENCRYPTION_KEY must be exactly 64 hex characters (32 bytes). Generate one with: openssl rand -hex 32
Prisma 6 is used for database access. Schema is at prisma/schema.prisma. Run `npx prisma db push` to sync schema changes (no migrations needed for development).
User, AuthToken, Session, Result, AuditLog, WaitlistEntry, ChatConversation, ChatMessage. All user-facing data is encrypted at rest using AES-256-GCM before storage.
Use Docker for local PostgreSQL: `docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=airealitycheck postgres:16`. Set DATABASE_URL=postgresql://postgres:postgres@localhost:5432/airealitycheck in .env.
All result data and chat messages are encrypted with AES-256-GCM before database storage. Keys are managed via environment variables and never exposed to the client. Original trust check text is never stored.
Security headers are applied via middleware: CSP, X-Frame-Options DENY, HSTS, X-Content-Type-Options nosniff, Referrer-Policy, Permissions-Policy. CSP allows 'self' for scripts, styles, images, fonts, and connections.
All state-changing API routes validate a CSRF token. The token is generated server-side and refreshed automatically via the CsrfRefresh component. Tokens expire after 24 hours.
In-memory rate limiter with per-endpoint limits: Trust Check 10/hr, Readiness/Spend Check 20/hr, Magic Link 5/15min, Chatbot 30/hr. Suitable for single-instance deployment.
Email-based authentication via Resend. User enters email, receives a magic link, clicks to verify. Token is bcrypt-hashed and expires in 15 minutes. Session cookie is set on verification.
Google and GitHub OAuth are supported. Session cookies use SameSite=Lax (required for cross-origin OAuth redirects). Cookies are set directly on response objects for redirect responses.
Sessions last 24 hours. Cookie settings: HttpOnly, Secure (production), SameSite=Lax, Path=/. Session records are stored in the database with userId and expiration.
Navigate to /admin/marketing (requires ADMIN_EMAIL env var + auth). Select a platform (X, LinkedIn, Facebook) and topic, then Claude generates ready-to-post social media content with hooks, hashtags, and CTAs.
POST to /api/marketing/waitlist-blast sends launch emails to all waitlist subscribers who haven't been notified. Sends in batches of 50, tracks notifiedAt to prevent double-sends. Protected by admin auth + CSRF.
Set the ADMIN_EMAIL environment variable on Railway to your email address. Only authenticated users matching this email can access marketing tools. All actions are CSRF-protected and audit-logged.
Create a new .ts file in src/data/blog-content/ with title, slug, description, content, and relatedCheck fields. Add the import to the index.ts file. The sitemap and RSS feed auto-update.
Articles use static TypeScript data (no CMS, no database). Each article links to a related check via CTA. Content supports headings, paragraphs, lists, and bold text. Articles are English-only (not translated).
The sitemap at /sitemap.xml and RSS feed at /feed.xml automatically include new articles. No manual update needed — both read from the blog content array at build time.
Four email templates in src/lib/emails.ts: welcome email (on signup), results summary (after check), re-engagement (for incomplete users), and waitlist blast (launch announcement). All use branded HTML with the app's dark theme.
Trigger via /api/marketing/waitlist-blast. Sends to all WaitlistEntry records where notifiedAt is null. Batches of 50 with delays to avoid rate limits. Each successful send updates notifiedAt to prevent re-sending.
Without RESEND_API_KEY set, all emails log to the console instead of sending. Use this for local development to verify email content and triggers without actually sending messages.
FAQ, Breadcrumb, and Product JSON-LD schemas are applied on check pages and pricing. Test with Google's Rich Results Test (search.google.com/test/rich-results) to verify structured data renders correctly.
Dynamic OG images generated via /api/og/result?type={check}&score={score}. File-based OG images in layout directories for static pages. Test with social media debuggers (Twitter Card Validator, LinkedIn Post Inspector).
Add airealitycheck.ai to Google Search Console, verify via DNS, and submit sitemap. Monitor indexing status, coverage errors, and search performance. Check for structured data issues in the Enhancements tab.
All significant actions are logged to the audit_logs table: login, check submissions, result views, chatbot usage. Each log includes userId, action, endpoint, IP hash, and metadata.
View application logs with `railway logs -n 50`. Check Railway dashboard for deployment status, resource usage, and error tracking.
Verify the app is running by accessing the homepage. Check /sitemap.xml and /robots.txt to verify static generation is working.
Check that SameSite is set to Lax (not Strict). Verify OAuth redirect URIs match exactly. Check CSP form-action includes OAuth provider domains. See docs/issues/google-oauth-login-broken.md for the full writeup.
Railway auto-deploy from GitHub can silently stop working. Always use `railway up` from the ai-reality-check directory as a reliable fallback. Check `railway logs` to confirm the new version is running.
Verify DATABASE_URL is set correctly in Railway environment. For local dev, ensure Docker PostgreSQL container is running. Run `npx prisma db push` to sync schema.
Verify ANTHROPIC_API_KEY is set and valid. Check rate limits (10/hour per user). Ensure input text is under 5,000 characters. Check Railway logs for specific API errors.