diff --git a/README.md b/README.md index 86b3f7b..58c64fa 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ OCR-driven receipting. Includes an LLM chat ("Ask") with a read-only tool layer over the same data, and a read-only MCP server. > **Default login PIN is `2468`.** Change `NEXT_PUBLIC_APP_PIN` in -> production. Append `?demo=1` to any URL to bypass the PIN during -> development. +> production. There is no PIN bypass — the old `?demo=1` shortcut was +> removed on 2026-09-26. --- diff --git a/docs/architecture.md b/docs/architecture.md index e2b29be..bc8feae 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -127,8 +127,8 @@ held in `sessionStorage` after a client-side string compare. - `AuthGate` (`src/components/auth-gate.tsx`) redirects to `/login` whenever the flag is missing, but does so client-side — every server component below it still runs on the server. -- Append `?demo=1` to any dashboard URL to bypass the PIN entirely - (`src/hooks/use-auth.tsx:27-30`). +- The `?demo=1` PIN bypass was removed on 2026-09-26 — the PIN is the + only way in. - There is **no per-user identity anywhere in the application**. Every user who knows the PIN sees every site's contract values, payroll rates, and margins. diff --git a/docs/operations.md b/docs/operations.md index 086ba94..2bd2651 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -173,7 +173,8 @@ The dev server runs on **port 6004** (not 3000 — the user runs other apps on 3000; do not change this back to 3000). The `--webpack` flag is required because `@ducanh2912/next-pwa` is webpack-only. -Append `?demo=1` to any URL to skip the PIN gate. +Enter the PIN (`NEXT_PUBLIC_APP_PIN`, default `2468`) on `/login`. The +old `?demo=1` bypass was removed on 2026-09-26. ### 5.2 Production build @@ -221,7 +222,6 @@ breaks. This is left in-tree for context, not as a reference. | Flag | Default | Effect when on | Effect when off | | --- | --- | --- | --- | | `ENABLE_CHAT` | unset (= `false`) | `/api/chat` and `/dashboard/chat` work | Both return 404 / `notFound()` | -| `?demo=1` query string | n/a | Skips the PIN gate on the current URL | Normal auth flow | | `NEXT_PUBLIC_DEFAULT_THEME` | `light` | Initial theme before user preference loads | " | | `CHAT_PROVIDER` | `anthropic` | `anthropic` if `ANTHROPIC_API_KEY` is set (or `ant auth login` profile); `minimax` / `openai` if `MINIMAX_API_KEY` is set | diff --git a/docs/superpowers/plans/2026-09-25-pocketbase-login.md b/docs/superpowers/plans/2026-09-25-pocketbase-login.md index 9ee87e8..486bba3 100644 --- a/docs/superpowers/plans/2026-09-25-pocketbase-login.md +++ b/docs/superpowers/plans/2026-09-25-pocketbase-login.md @@ -42,6 +42,8 @@ ### Cutover timeline +> **Update 2026-09-26:** the app is still in on-site testing and production is months away, so there is **no fixed cutover date**. Testers keep the shared PIN (shown on the login page on purpose). Build this when it's needed, keep `AUTH_MODE=pin` until testing is done, and use the dates below only as the shape of the rollout. + | When | What | Who | | --- | --- | --- | | Sat 26 Sep – Sun 27 Sep | Tasks 1–11 built and merged; deployed with `AUTH_MODE=pin` (no visible change) | Dev | @@ -819,7 +821,7 @@ export const PATCH = withUser(async (_req, { params }: { params: Promise<{ id: s - [ ] **Step 1: Mode reaches the client.** `src/app/layout.tsx` (server) reads `authMode()` and passes `mode` into ``. `NEXT_PUBLIC_*` must **not** be used for the mode — a runtime env flip must not need a rebuild. - [ ] **Step 2: Login page.** `mode === "pin"` → today's keypad, unchanged. `mode === "users"` → email + password form posting to `/api/auth/login`; on 200 `router.replace(resolveRedirectTarget(location.search))`; show the server's error text; disable the button while submitting; `autoComplete="username"` / `"current-password"` so phones offer to save it. -- [ ] **Step 3: Gate.** In users mode `AuthGate` renders children directly (the proxy already redirected), and the `?demo=1` bypass is **ignored** (only honoured in pin mode). +- [ ] **Step 3: Gate.** In users mode `AuthGate` renders children directly (the proxy already redirected). (The old `?demo=1` bypass was removed on 2026-09-26 — do not reintroduce it.) - [ ] **Step 4: Sidebar footer.** Users mode: "Signed in as {name} · {ROLE_LABELS[role]}" + **Sign out** (POST `/api/auth/logout`, then `location.href = "/login"`). Pin mode: today's "Lock screen". - [ ] **Step 5: Nav by permission.** Hide groups the role lacks (`workforce.view`, `plant.view`, `financial.view`; `chat.use` for Ask). In Phase 1 a site manager sees everything except Ask and Users. - [ ] **Step 6:** Browser check both modes. Commit — `git commit -m "feat(auth): email login page and sign-out"` diff --git a/src/hooks/use-auth.tsx b/src/hooks/use-auth.tsx index 74a35cd..1ebde16 100644 --- a/src/hooks/use-auth.tsx +++ b/src/hooks/use-auth.tsx @@ -23,11 +23,6 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { React.useEffect(() => { try { if (sessionStorage.getItem(PIN_VERIFIED_KEY) === "1") setAuthenticated(true); - // Demo bypass: append ?demo=1 to any dashboard URL to skip the PIN screen. - if (typeof window !== "undefined" && new URLSearchParams(window.location.search).get("demo") === "1") { - setAuthenticated(true); - sessionStorage.setItem(PIN_VERIFIED_KEY, "1"); - } } catch { // ignore }