Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
6722e18
docs(scope): defer analytics & error tracking
kris1027 Oct 27, 2026
3ab81a9
docs(specs): remove admin 2FA (spec 0019)
kris1027 Oct 27, 2026
0b060e8
feat(admin-auth): replace the admin email reset with admin:reset-pass…
kris1027 Oct 27, 2026
2b46f82
feat(admin-auth): sign in with a password only and remove TOTP
kris1027 Oct 27, 2026
4761fff
chore(admin-auth): turn TOTP off and update the admin runbook
kris1027 Oct 27, 2026
f92211f
docs(scope): mark the remove admin 2FA build done
kris1027 Oct 27, 2026
90c5725
docs(specs): add the verify steps for spec 0019
kris1027 Oct 27, 2026
6716ca7
docs(specs): align spec 0019 with the reset that ends every session
kris1027 Oct 27, 2026
712b20b
test(admin-auth): cover the admin password prompt, reset refusals and…
kris1027 Oct 27, 2026
a2ebeec
fix(admin-auth): look the admin up once in admin:reset-password
kris1027 Oct 27, 2026
e81a396
docs(account): drop the admin reset email and TOTP from the account n…
kris1027 Oct 27, 2026
63fcfe7
docs(specs): record the verify, test and review of spec 0019
kris1027 Oct 27, 2026
e4179b2
refactor(admin-auth): import app code through @/ in the admin scripts…
kris1027 Oct 27, 2026
fe3bf21
refactor(admin-auth): answer an unknown admin as a value and run admi…
kris1027 Oct 27, 2026
4055153
refactor(email): name the store runner reset check and link by action…
kris1027 Oct 27, 2026
9523124
refactor(account): build the confirm failure path in one place
kris1027 Oct 27, 2026
1bedb29
fix(admin-auth): send an unreadable session token to a plain sign in,…
kris1027 Oct 27, 2026
56376ac
docs(specs): mark specs 0004 and 0012 partly superseded by spec 0019
kris1027 Oct 27, 2026
3ead446
docs: drop the admin reset email and admin page password notes
kris1027 Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ BeStore is a single-brand online store in one Next.js application: a storefront

## Current state

The application foundation, database model, shared design system, and admin sign-in with required TOTP are implemented. The storefront currently shows a coming-soon page. Product browsing and the core buy loop, card payment, shipping, catalog and order management, customer accounts, and launch work remain planned. The [scope](docs/scope/scope.md) is the source of truth for feature status and the [specifications](docs/specs/) explain completed decisions.
The application foundation, database model, shared design system, and admin sign-in (email and password) are implemented. The storefront currently shows a coming-soon page. Product browsing and the core buy loop, card payment, shipping, catalog and order management, customer accounts, and launch work remain planned. The [scope](docs/scope/scope.md) is the source of truth for feature status and the [specifications](docs/specs/) explain completed decisions.

### Interface previews

Expand Down
33 changes: 0 additions & 33 deletions app/admin/(auth)/forgot-password/page.tsx

This file was deleted.

80 changes: 0 additions & 80 deletions app/admin/(auth)/mfa/page.tsx

This file was deleted.

27 changes: 0 additions & 27 deletions app/admin/(auth)/reset-password/page.tsx

This file was deleted.

5 changes: 1 addition & 4 deletions app/admin/(auth)/sign-in/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ export default async function SignInPage({ searchParams }: PageProps<"/admin/sig
await redirectIfSignedIn(nextPath);

return (
<AuthCard
title="Sign in"
description="Use your admin email and password. You will need your authenticator app next."
>
<AuthCard title="Sign in" description="Use your admin email and password.">
<SignInForm next={nextPath} reason={signInReason(reason)} />
</AuthCard>
);
Expand Down
35 changes: 0 additions & 35 deletions app/auth/confirm/page.tsx

This file was deleted.

34 changes: 34 additions & 0 deletions docs/reviews/2026-10-27-feat-defer-analytics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Review, feat/defer-analytics, 2026-10-27

**Reviewed by**: Sonnet 5.5 (author on a different model)
**Scope**: 112 files, branch vs main (merge base 7e00d5b, plus uncommitted docs edits)
**Verdict**: Approve with nits

## Summary
Spec 0019 removes admin TOTP/MFA, the admin email reset and `/auth/confirm`, and replaces them with a password only guard that also requires a `password` entry in `amr`, plus `pnpm admin:reset-password`. The security model holds up: every admin page, layout, action and the one admin route (sign-out, deliberately open) is guarded, the proxy and `requireAdmin()` share `decideAdminAccess`, and an email link session is turned away both in the proxy (real redirect) and in the guard. The only findings are stale nested docs and small cleanups.

## Minor
### 🟡 Stale account AGENTS.md still describes the admin reset and TOTP, `src/features/account/AGENTS.md:15,28`
**Problem**: Line 15 says the hook "picks the template (admin reset first)"; line 28 says a store runner "always gets the admin reset email" and mentions a verified TOTP factor and `auth.mfa_factors` reads. After this change the hook skips store runners' recovery email and `runsTheStore` reads `admin_users` only.
**Why it matters**: This file is loaded as agent context; it now contradicts the code and spec 0019 AC-8, AC-10.
**Suggested fix**: Reword both lines (skip, `admin_users` only, no `auth.mfa_factors`). Likely /sync's job, but it should land with this branch.

### 🟡 Double admin lookup in the reset script, `scripts/admin/reset-password.ts:14-17`
**Problem**: `findAdminId` is called to fail early, then `resetAdminPassword` looks the admin up again.
**Why it matters**: Harmless, but two reads of the same row and a small chance of divergence; `resetAdminPassword` could accept an id or the script could just call it after prompting.
**Suggested fix**: Keep the early refusal but pass the found id into the reset step.

## Nits
- ⚪ `src/features/admin-auth/require-admin.ts:20`, if `getClaims()` fails after `getUser()` succeeded, `amr` is null and the user is sent to sign in with `reason=expired`; fail closed is right, the "expired" message is slightly misleading.
- ⚪ `src/features/admin-auth/proxy.ts:107`, gate lookup failure still fails open (pre-existing; page guard still refuses), worth keeping the comment current.
- ⚪ `src/features/admin-auth/sign-out.ts:6-8`, import order is inconsistent (`endLocalSession` import after local imports); cosmetic.
- ⚪ `tests/e2e/admin/denials.spec.ts:31`, `/admin/mfa` assertion is fine but duplicates `sign-in.spec.ts:105` removed paths check.

## Strengths
- Password only rule is pinned where it matters: `tests/stack/admin-amr.stack.test.ts` proves a password sign in has a `password` amr and a verified recovery link does not, and `admin-scripts.stack.test.ts` pins that the reset ends every session.
- `decideAdminAccess` is pure, fails closed on unreadable `amr`, handles both `amr` shapes; the proxy can only deny earlier, never grant, and gives a real 3xx for password-less sessions.
- Defense in depth for admin inbox takeover: hook skips recovery for store runners (200, same timing), `confirmEmail` signs out and refuses, `admin:create` overwrites a planted password and confirms email, 14 char admin password.
- Clean removal: no remaining MFA/TOTP/`otpauth`/`/auth/confirm` references in code, config, emails or runbooks beyond intentional removed-path tests; runbook updated with compromise procedure and Firewall rule widened to `/account/sign-in`.

## Test coverage
Good. Unit tests cover access verdicts, both `amr` shapes, proxy decisions and gate, `requireAdmin`, hook skip, confirm refusal, password schema, CLI helpers and script cores. Stack tests pin Supabase behaviors the design relies on; e2e covers sign in, removed paths, denials, a recovery-link admin session being refused, and a11y of the sign-in page. No gaps found in new logic.
Loading
Loading