Unauthenticated requests to /login were hitting the auth gate and
redirecting back to /login?callbackUrl=/login, causing a loop.
Let the login page render for unauthenticated users; only redirect
away from /login when the user is already logged in.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
req.url resolves to the internal hostname in Docker standalone mode.
Read the Host header directly so redirects and CSRF origin checks use
whatever host the browser actually used (IP, hostname, or domain).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
req.nextUrl.origin resolves to localhost inside the container.
Using req.url preserves the Host header the browser sent, so
redirects work when accessing via IP or any external hostname.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
127.0.0.1:3000 only accepted connections from localhost.
DB port intentionally stays on 127.0.0.1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NextAuth's Credentials provider pulls in Prisma -> pg -> Node.js crypto,
which crashes in the Edge runtime. Extract an auth.config.ts with only
JWT/session callbacks (no DB, no bcrypt) and use NextAuth(authConfig) in
middleware. auth.ts spreads the config and adds the Credentials provider.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The production runner image has no node_modules, so prisma CLI and tsx
are unavailable. Add a Compose 'setup' profile service that uses the
builder stage (which has all dev tools) to run db push and db seed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>