1ee4b5d24ca8fb38da3261e2627d2e68ec4e272b
Three misconfigurations in a row were each diagnosed the same slow way: deploy, try to sign in, read a status code, guess, read a response body, guess again. That is a property of the design, not of bad luck. Every required variable is read lazily, on the first request that needs it, so a container missing its environment starts clean, serves the sign-in page, and passes a healthcheck while being completely unable to authenticate anybody. The lazy reads have to stay — reading at module scope fails `next build`, which collects page data with NODE_ENV=production and none of these variables set (that is the "Failed to collect page data for /api/assistant" failure already documented in apiClient). So the check goes in an instrumentation hook instead, which Next runs once per server start and NEVER during a build: it returns early when NEXT_PHASE is 'phase-production-build', in server/lib/router-utils/instrumentation-globals.external.js. Boot now either prints what it resolved: [loyaly] config ok — platform https://mcp.loyaly.ai, auth secret set, NODE_ENV=production or refuses to start, naming every problem at once rather than one per deploy: refusing to start — 2 configuration problem(s): 1. LOYALY_API_BASE is invalid: https://api.example.com is not a supported production API host... 2. AUTH_SECRET is required in production — it signs the session cookie... Verified against a real standalone build, booted four ways: unconfigured, fully configured, LOYALY_API_BASE pointed at the console, and both wrong at once. The platform origin and its validation move to shared/config/platformApi. This is load-bearing, not tidying: apiClient is `server-only`, and that package resolves to a module which THROWS ON IMPORT outside a react-server condition — which the instrumentation bundle is not. Importing apiClient from the boot check would have crashed every start, correctly configured or not. The extracted module imports nothing but ConfigError, so the boot check and the request path run the same function against the same allowlist. Also corrects a claim I made in the Dockerfile two commits ago. `next build` DOES copy .env into .next/standalone — writeStandaloneDirectory takes exactly .env and .env.production and nothing else — so the explicit COPY is redundant rather than required. It stays, with an accurate reason: it only happens when .env is in the build context, and .dockerignore excluded it until recently. Keeping the COPY makes that dependency fail the Docker build loudly instead of producing an unconfigured image. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This is a Next.js project bootstrapped with create-next-app.
Getting Started
First, run the development server:
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
Open http://localhost:3000 with your browser to see the result.
You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.
This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.
Learn More
To learn more about Next.js, take a look at the following resources:
- Next.js Documentation - learn about Next.js features and API.
- Learn Next.js - an interactive Next.js tutorial.
You can check out the Next.js GitHub repository - your feedback and contributions are welcome!
Deploy on Vercel
The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.
Check out our Next.js deployment documentation for more details.
Description
Languages
TypeScript
95.4%
CSS
2.9%
JavaScript
0.9%
Dockerfile
0.6%
Shell
0.2%