# Dev Login And Local Test Setup This note tracks the development-only work added to make the app easy to run and test without a live Authentik/OIDC setup. ## What Was Added - `.env` was created locally with: - `NEXT_PUBLIC_APP_URL=http://127.0.0.1:3000` - `DATABASE_URL=postgres://famapp:famapp@localhost:5432/famapp` - `ENABLE_DEV_LOGIN=true` - placeholder OIDC values for local-only development - `.env.example` now documents the dev-login variables: - `ENABLE_DEV_LOGIN` - `DEV_LOGIN_EMAIL` - `DEV_LOGIN_NAME` - `DEV_HOUSEHOLD_NAME` - `src/lib/dev-login-config.ts` contains Edge-safe dev-login constants and feature-flag detection. - `src/lib/dev-login.ts` creates a database-backed Auth.js session for a local dev user. - `src/app/login/page.tsx` shows a **Dev login** button only when: - `NODE_ENV !== "production"` - `ENABLE_DEV_LOGIN=true` - `src/middleware.ts` was changed to an Edge-safe cookie gate. It no longer imports Auth.js/Drizzle/Postgres into middleware. - `tests/.auth/` is ignored so generated Playwright session state is never committed. - Playwright Chromium was installed locally. - `tests/.auth/dev-user.json` was generated locally from the Dev login flow. ## Related Fixes Found While Enabling Testing - `drizzle/0005_auth_schema_repair.sql` was added to repair local databases that missed the Auth.js schema migration. - `scripts/seed.ts` now exits cleanly after seeding because imported module default helpers use the shared app database client. - `src/modules/calendar/server/actions.ts` no longer calls `.partial()` on a refined Zod schema. - Calendar/list E2E locators were tightened so the suite runs against the current UI. - Calendar/list create buttons no longer depend on `useTransition` pending state for basic enablement. ## Current Local Run Procedure One command starts the database, runs migrations, seeds, and launches the dev server: ```powershell pnpm dev:local ``` The script prints three URLs at startup: | URL | Use for | | ---------------------------- | ---------------------------------------------------------- | | `http://localhost:3000` | Browser on this machine | | `http://192.168.x.y:3000` | Phone on the same WiFi (general UI testing) | | `https://dev.yourdomain.com` | Push notifications + PWA install (needs Caddy — see below) | Then open `/login` and click **Dev login**. ### HMR and restarts `next dev` has hot module replacement — most `.ts`/`.tsx` changes apply instantly without a restart. A full restart (`Ctrl+C` → `pnpm dev:local`) is needed for: - `.env` changes - `next.config.ts` changes ### Clean slate To delete all local data and start fresh (e.g. after a destructive schema change): ```powershell pnpm dev:reset ``` ### HTTPS for push notification and PWA testing (one-time setup) Service workers and Web Push require HTTPS. The plain LAN address won't work for these. Route through the existing Caddy server on the home server instead — no extra tooling needed. **Step 1 — DHCP reservation** Set a reservation on the router so the dev machine always gets `192.168.x.y`. **Step 2 — DNS record** Add a `dev.yourdomain.com` A record pointing to the same public IP as `fam.yourdomain.com`. **Step 3 — Windows Firewall** Allow inbound TCP 3000 on the dev machine (run once in an elevated PowerShell): ```powershell New-NetFirewallRule -DisplayName "famapp dev" -Direction Inbound ` -Protocol TCP -LocalPort 3000 -Action Allow ``` **Step 4 — Caddy snippet** Paste `deploy/Caddyfile.dev.snippet` into the home server Caddyfile and reload: ```bash caddy reload --config /path/to/Caddyfile ``` After this, `https://dev.yourdomain.com` proxies to the dev machine with a real Let's Encrypt cert. ## Current Local E2E Procedure Generate auth state after starting the app: ```powershell New-Item -ItemType Directory -Force tests\.auth | Out-Null @' const { chromium } = require('@playwright/test'); (async () => { const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('http://127.0.0.1:3000/login'); await page.getByRole('button', { name: 'Dev login' }).click(); await page.waitForURL('http://127.0.0.1:3000/'); await page.context().storageState({ path: 'tests/.auth/dev-user.json' }); await browser.close(); })(); '@ | node - ``` Run tests: ```powershell $env:PLAYWRIGHT_STORAGE_STATE='tests/.auth/dev-user.json' pnpm test:e2e ``` After validation, tear down services started for the test run unless you are intentionally keeping the app open: ```powershell # Stop a manually started Next dev server if one is still running on port 3000. Get-NetTCPConnection -LocalPort 3000 -State Listen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess -Unique | ForEach-Object { Stop-Process -Id $_ } # Stop the local database container when the session is finished. docker compose -f docker-compose.dev.yaml down ``` ## Production Removal Plan Before production deployment, complete the checklist below. - Set `ENABLE_DEV_LOGIN=false` in production secrets. - Do not copy local `.env` to production. - Confirm `deploy/compose.yaml` or production env files do not define: - `ENABLE_DEV_LOGIN=true` - `DEV_LOGIN_EMAIL` - `DEV_LOGIN_NAME` - `DEV_HOUSEHOLD_NAME` - Verify `/login` does not render **Dev login** when built with production env. - Verify direct POSTs to the dev login action fail because `createDevSession()` checks `NODE_ENV !== "production"` and `ENABLE_DEV_LOGIN=true`. - Delete any dev users from the production database if they were accidentally created: - `dev@famapp.local` - any configured `DEV_LOGIN_EMAIL` - Keep `tests/.auth/` ignored and out of production artifacts. - Replace placeholder OIDC variables with real Authentik values: - `AUTH_OIDC_ISSUER` - `AUTH_OIDC_CLIENT_ID` - `AUTH_OIDC_CLIENT_SECRET` - Confirm Authentik login succeeds against the production domain. - Run `pnpm build` with production-like env before shipping. ## Decision For Now Keep the dev-login code in the repo while active module development is ongoing. It is explicitly gated by environment and avoids requiring Authentik for every local UI/E2E loop. Before first real production deployment, decide whether to: - remove the dev-login code entirely, or - keep it behind the existing production-safe gates for future local development. Removing it entirely is stricter. Keeping it gated is more convenient. The production blocker is not the presence of the code; it is any production environment that enables it.