Add CookieBanner component with useCookieConsent hook, translations in EN/PL, and integration into root layout Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
23 KiB
Dashboard Password Reset Flow
TL;DR
Summary: Add an authenticated password-change flow reachable from the dashboard, with the actual form hosted on a protected
/settingspage that follows the repo's existing server-page plus client-component auth pattern. Deliverables:
- Dashboard entry affordance to account security settings
- Protected
/settingspage with localized password-change UI- Better Auth
changePasswordintegration with explicit success/error handling- Agent-executable manual QA evidence for auth protection, validation, and credential rotation Effort: Medium Parallel: YES - 2 waves Critical Path: 1 -> 3 -> 4 -> 5 -> 6
Context
Original Request
Implement a user-facing password reset flow from src/app/dashboard/page.tsx.
Interview Summary
- User selected the authenticated in-session flow, not forgot-password by email.
- Dashboard is the entry point, but the actual form should live on
/settings. - Manual QA only for now; no test infrastructure setup in this slice.
Metis Review (gaps addressed)
- Protect
/settingsexplicitly instead of assuming auth. - Keep scope to password/security only; do not expand into general settings architecture.
- Use Better Auth's existing
changePasswordflow instead of inventing custom backend plumbing. - Define concrete browser QA with fixed credentials and explicit redirect/session assertions.
Work Objectives
Core Objective
Provide a secure, authenticated password-change experience that users can reach from the dashboard and complete on a dedicated settings page.
Deliverables
- Auth-protected
src/app/settings/page.tsx - Dashboard entry UI from
src/app/dashboard/page.tsxto/settings - Localized client password-change component under
src/components/ - Better Auth client submission flow with
revokeOtherSessions: true - Updated translation files for all new strings
- QA evidence captured for happy path and failure cases
Definition of Done (verifiable conditions with commands)
pnpm lintcompletes successfullypnpm buildcompletes successfully- Visiting
/settingswhile unauthenticated redirects to sign-in with a callback back to/settings - A signed-in user can open
/settings, submit a valid current/new password pair, and subsequently sign in with only the new password - Wrong current password and mismatched confirmation both fail with clear user feedback
Must Have
- Protected
/settingsroute with explicit redirect behavior - Dashboard affordance linking to
/settings - Fields for
currentPassword,newPassword, andconfirmPassword - Client validation for required fields, confirmation match, and rejecting
newPassword === currentPassword - Backend-driven password validation through Better Auth's configured policies, including HIBP plugin
- Success/error feedback and loading state consistent with existing auth UI
- New strings added to both
messages/en.jsonandmessages/pl.json
Must NOT Have (guardrails, AI slop patterns, scope boundaries)
- No forgot-password email flow, token flow, reset page, or mail templates
- No full settings IA, profile editor, preferences, or navigation redesign
- No new test framework, Playwright project, or CI setup in this slice
- No custom Convex mutation/server action for password change unless Better Auth client API proves unusable during execution
- No route-protection behavior left implicit or undocumented
Verification Strategy
ZERO HUMAN INTERVENTION - all verification is agent-executed.
- Test decision: none + existing repo has no test framework; use browser-driven QA and build/lint verification
- QA policy: Every task includes agent-executed scenarios with exact credentials, selectors, and expected outcomes
- Evidence:
.sisyphus/evidence/task-{N}-{slug}.{ext}
Execution Strategy
Parallel Execution Waves
Target: 5-8 tasks per wave. <3 per wave (except final) = under-splitting. Extract shared dependencies as Wave-1 tasks for max parallelism.
Wave 1: 1) route protection and settings page scaffold, 2) dashboard entry affordance, 3) settings UI shell + translations Wave 2: 4) client validation and field UX, 5) Better Auth submission + session behavior, 6) polish and end-to-end manual QA capture
Dependency Matrix (full, all tasks)
- 1 blocks 4, 5, 6
- 2 is independent after route constants are confirmed; feeds 6 QA coverage
- 3 blocks 4 and 5
- 4 blocks 5 and 6
- 5 blocks 6
- 6 blocks final verification wave
Agent Dispatch Summary (wave -> task count -> categories)
- Wave 1 -> 3 tasks -> unspecified-high, visual-engineering, visual-engineering
- Wave 2 -> 3 tasks -> quick, unspecified-high, unspecified-high
TODOs
Implementation + Test = ONE task. Never separate. EVERY task MUST have: Agent Profile + Parallelization + QA Scenarios.
-
1. Add protected
/settingspage scaffoldWhat to do: Read the relevant Next.js App Router docs under
node_modules/next/dist/docs/before coding, then createsrc/app/settings/page.tsxas a server page that checks authentication with the existing server auth helpers fromsrc/lib/auth-server.ts. If unauthenticated, redirect to/sign-in?callbackURL=/settings. If authenticated, render a dedicated client settings/password component and keep the page focused on security only. Must NOT do: Do not implement forgot-password here. Do not place the full form directly insrc/app/settings/page.tsx. Do not create middleware or a broader settings layout in this slice.Recommended Agent Profile:
- Category:
unspecified-high- Reason: auth-aware App Router work with redirect behavior and server/client boundary decisions - Skills:
[]- No special skill required beyond repo pattern matching - Omitted:
playwright- UI automation belongs in QA, not scaffolding
Parallelization: Can Parallel: YES | Wave 1 | Blocks: 4, 5, 6 | Blocked By: none
References (executor has NO interview context - be exhaustive):
- Pattern:
src/app/sign-in/page.tsx- thin server page wrapper pattern already used for auth routes - Pattern:
src/app/sign-up/page.tsx- same page composition pattern for route-level wrappers - Auth helper:
src/lib/auth-server.ts- server-side auth utilities available for checking session/auth state - Route contract:
src/lib/routes.ts-/settingsalready exists as a private route constant - Existing target:
src/app/dashboard/page.tsx- current dashboard stub that will link into this route - External:
node_modules/next/dist/docs/- project instruction requires reading relevant Next.js docs before implementation
Acceptance Criteria (agent-executable only):
src/app/settings/page.tsxexists and remains a server page wrapper rather than a client-heavy file- Unauthenticated access to
/settingsredirects to/sign-in?callbackURL=/settings - Authenticated access to
/settingsrenders the dedicated password settings component pnpm lintpasses after the page scaffold is added
QA Scenarios (MANDATORY - task incomplete without these):
Scenario: Unauthenticated redirect from settings Tool: Playwright Steps: Open a fresh browser context; visit http://localhost:3000/settings directly. Expected: Browser lands on `/sign-in` and preserves a callback URL containing `/settings`. Evidence: .sisyphus/evidence/task-1-settings-redirect.png Scenario: Authenticated settings page render Tool: Playwright Steps: Sign up `changeflow@example.com` with password `OldPass123!`; sign in; visit http://localhost:3000/settings. Expected: The page renders a password/security card instead of redirecting away. Evidence: .sisyphus/evidence/task-1-settings-render.pngCommit: YES | Message:
add protected settings page scaffold and dashboard entry| Files:src/app/settings/page.tsx,src/lib/routes.ts(only if needed), related imports - Category:
-
2. Add dashboard entry to account security
What to do: Replace the dashboard stub with a minimal, intentional dashboard card or section that exposes a single clear affordance to account security settings. Link to
/settingsvia existing route constants. Keep the page intentionally narrow: one CTA, one short description, no full settings UI embedded here. Must NOT do: Do not turn dashboard into a general settings page. Do not add unrelated profile, billing, or preferences UI.Recommended Agent Profile:
- Category:
visual-engineering- Reason: small UI composition task that must feel deliberate, not boilerplate - Skills:
[]- Existing component library provides all primitives needed - Omitted:
playwright- verification happens via QA scenario, not implementation
Parallelization: Can Parallel: YES | Wave 1 | Blocks: 6 QA coverage only | Blocked By: none
References (executor has NO interview context - be exhaustive):
- Target page:
src/app/dashboard/page.tsx- currently only a stub and should become the entry point - Route contract:
src/lib/routes.ts- use the existing private route constant for settings - UI pattern:
src/components/ui/card.tsx- use existing card primitives for a compact dashboard section - UI pattern:
src/components/ui/button.tsx- use existing button variants for the CTA
Acceptance Criteria (agent-executable only):
/dashboardcontains a visible CTA linking to/settings- The CTA uses route constants rather than a duplicated hard-coded path
- The dashboard change stays focused on password/security entry only
pnpm lintpasses after the dashboard update
QA Scenarios (MANDATORY - task incomplete without these):
Scenario: Dashboard exposes security entry Tool: Playwright Steps: Sign in as `changeflow@example.com` with `OldPass123!`; open http://localhost:3000/dashboard; inspect the visible security/settings CTA. Expected: Clicking the CTA navigates to `/settings`. Evidence: .sisyphus/evidence/task-2-dashboard-entry.png Scenario: Dashboard does not embed the password form Tool: Playwright Steps: Load http://localhost:3000/dashboard while signed in. Expected: No `currentPassword`, `newPassword`, or `confirmPassword` input fields are present on the dashboard page itself. Evidence: .sisyphus/evidence/task-2-dashboard-no-form.pngCommit: YES | Message:
add protected settings page scaffold and dashboard entry| Files:src/app/dashboard/page.tsx - Category:
-
3. Create the localized password settings component shell
What to do: Create a dedicated client component for password change under
src/components/settings/and wire it intosrc/app/settings/page.tsx. Use the same card, field, button, spinner, and password input-group patterns already used insrc/components/auth/AuthForm.tsx. Add all new translation keys to both locale files up front so no hard-coded strings remain. Must NOT do: Do not reuseAuthFormdirectly for password change. Do not leave untranslated labels, helper text, button copy, or toast messages.Recommended Agent Profile:
- Category:
visual-engineering- Reason: new client UI should blend with existing auth UI while staying scoped - Skills:
[]- Existing component system is sufficient - Omitted:
writing- copy additions are straightforward translation entries, not long-form docs
Parallelization: Can Parallel: YES | Wave 1 | Blocks: 4, 5, 6 | Blocked By: 1
References (executor has NO interview context - be exhaustive):
- Pattern:
src/components/auth/AuthForm.tsx- existing client auth form conventions for card layout, field composition, spinner, toast, and password visibility controls - UI primitives:
src/components/ui/field.tsx,src/components/ui/input-group.tsx,src/components/ui/button.tsx,src/components/ui/spinner.tsx - Translation files:
messages/en.json,messages/pl.json- extend with a dedicated settings/security namespace or equivalent flat keys - Existing i18n usage:
src/components/auth/AuthForm.tsx-useTranslations(...)pattern
Acceptance Criteria (agent-executable only):
- A dedicated client component exists under
src/components/settings/ /settingsrenders a single password/security card with localized heading, description, and button text- Both
messages/en.jsonandmessages/pl.jsoncontain all strings needed for the new UI - No new hard-coded user-facing strings remain in the component
QA Scenarios (MANDATORY - task incomplete without these):
Scenario: Password settings shell renders expected fields Tool: Playwright Steps: Sign in; visit http://localhost:3000/settings; inspect the form. Expected: Inputs named `currentPassword`, `newPassword`, and `confirmPassword` are visible, plus a submit button. Evidence: .sisyphus/evidence/task-3-settings-shell.png Scenario: Localized shell does not regress rendering Tool: Playwright Steps: Load the page in the default locale; inspect heading, field labels, and submit button. Expected: All visible strings are rendered from translation data with no raw key names or empty labels. Evidence: .sisyphus/evidence/task-3-settings-i18n.pngCommit: YES | Message:
add password change form UI and localization| Files:src/components/settings/PasswordChangeCard.tsx,src/app/settings/page.tsx,messages/en.json,messages/pl.json - Category:
-
4. Implement client-side validation and field UX
What to do: Define a dedicated Zod schema for the password-change form that requires
currentPassword, reusesdefaultPasswordValidator()fornewPassword, enforcesconfirmPassword === newPassword, and rejectsnewPassword === currentPassword. Provide inline field errors and disable duplicate submissions with a loading state. Keep password visibility UX consistent with the existing auth form pattern. Must NOT do: Do not add uppercase/number/special-character composition rules back into the client. Do not rely only on toasts for validation errors that belong inline.Recommended Agent Profile:
- Category:
quick- Reason: bounded form-schema and field-state work inside one component - Skills:
[]- Existing validation patterns are enough - Omitted:
ultrabrain- no deep algorithmic work needed
Parallelization: Can Parallel: NO | Wave 2 | Blocks: 5, 6 | Blocked By: 1, 3
References (executor has NO interview context - be exhaustive):
- Validation helper:
src/constants.ts- current shared minimum-length validator to reuse fornewPassword - Pattern:
src/components/auth/AuthForm.tsx- React Hook Form + Zod resolver usage and inlineFieldErrorhandling - UI primitives:
src/components/ui/field.tsx,src/components/ui/input-group.tsx,src/components/ui/spinner.tsx
Acceptance Criteria (agent-executable only):
- Submitting mismatched
newPasswordandconfirmPasswordsurfaces an inline error on the confirmation field - Submitting the same value for current and new password surfaces an inline error before any network request
- Submitting an empty required field surfaces inline validation without a success toast
- Submit button disables while the request is pending
QA Scenarios (MANDATORY - task incomplete without these):
Scenario: Mismatched confirmation is blocked locally Tool: Playwright Steps: Sign in; open `/settings`; fill `currentPassword=OldPass123!`, `newPassword=NewPass123!`, `confirmPassword=Mismatch123!`; submit. Expected: Inline error appears for `confirmPassword`; no network-driven success state is shown. Evidence: .sisyphus/evidence/task-4-confirm-mismatch.png Scenario: Reusing the same password is blocked locally Tool: Playwright Steps: Fill `currentPassword=OldPass123!`, `newPassword=OldPass123!`, `confirmPassword=OldPass123!`; submit. Expected: Inline error indicates the new password must differ from the current password. Evidence: .sisyphus/evidence/task-4-same-password.pngCommit: YES | Message:
add password change form UI and localization| Files:src/components/settings/PasswordChangeCard.tsx, related validation helpers only if needed - Category:
-
5. Wire Better Auth password change submission
What to do: Connect the settings form to Better Auth's client password-change API using the authenticated session. Submit
currentPassword,newPassword, andrevokeOtherSessions: true. On success, stay on/settings, clear sensitive fields, and show a localized success toast. On failure, surface the returned error cleanly without clearing the current user session. Must NOT do: Do not create a custom Convex mutation for password change unless the Better Auth client call is proven unusable. Do not redirect away from settings after success. Do not silently swallow backend errors.Recommended Agent Profile:
- Category:
unspecified-high- Reason: auth-sensitive submission flow with session behavior and backend error handling - Skills:
[]- Existing Better Auth client is already configured in repo - Omitted:
writing- this is behavior wiring, not docs work
Parallelization: Can Parallel: NO | Wave 2 | Blocks: 6 | Blocked By: 1, 3, 4
References (executor has NO interview context - be exhaustive):
- Client auth entry:
src/lib/auth-client.ts- Better Auth client already configured with Convex plugin - Existing auth pattern:
src/components/auth/AuthForm.tsx- request pending state, toast handling, Better Auth client invocation patterns - Backend policy:
convex/auth.ts- Better Auth email/password configuration with HIBP plugin and min/max length - Settings component:
src/components/settings/PasswordChangeCard.tsx- task 3/4 output
Acceptance Criteria (agent-executable only):
- Valid submission calls Better Auth password-change API and succeeds for the signed-in user
- Wrong current password yields a visible error state without logging the user out of the current session
- Successful submission clears all password inputs and leaves the user on
/settings pnpm buildpasses after the integration is complete
QA Scenarios (MANDATORY - task incomplete without these):
Scenario: Wrong current password is rejected Tool: Playwright Steps: Sign in; open `/settings`; fill `currentPassword=WrongPass123!`, `newPassword=NewPass123!`, `confirmPassword=NewPass123!`; submit. Expected: Error feedback appears; the current session remains usable; revisiting `/dashboard` still works in the same tab. Evidence: .sisyphus/evidence/task-5-wrong-current-password.png Scenario: Valid password change succeeds Tool: Playwright Steps: Fill `currentPassword=OldPass123!`, `newPassword=NewPass123!`, `confirmPassword=NewPass123!`; submit. Expected: Success toast/message appears; fields clear; page remains on `/settings`. Evidence: .sisyphus/evidence/task-5-successful-change.pngCommit: YES | Message:
wire password change flow and verify session behavior| Files:src/components/settings/PasswordChangeCard.tsx, any minimal auth client touch-ups only if required - Category:
-
6. Finalize credential-rotation behavior and capture manual QA evidence
What to do: Validate the full user journey end to end: dashboard -> settings -> change password -> sign out -> sign back in with the new credential. Because
revokeOtherSessions: trueis the default for this slice, also verify in a second browser context that another active session becomes unauthorized after the password change. Capture screenshots/logs into the evidence paths referenced below. Must NOT do: Do not add automated test infrastructure or CI in order to satisfy this task. Do not leave QA as a vague manual checklist.Recommended Agent Profile:
- Category:
unspecified-high- Reason: auth/stateful browser verification across two sessions - Skills: [
playwright] - Use browser automation to validate auth and session transitions precisely - Omitted:
frontend-ui-ux- this task is verification-focused, not design-focused
Parallelization: Can Parallel: NO | Wave 2 | Blocks: Final verification wave | Blocked By: 1, 2, 3, 4, 5
References (executor has NO interview context - be exhaustive):
- Entry page:
src/app/dashboard/page.tsx - Protected page:
src/app/settings/page.tsx - Form component:
src/components/settings/PasswordChangeCard.tsx - Auth UI precedent:
src/components/auth/AuthForm.tsx - Command surface:
package.json- use existingpnpm dev,pnpm lint, andpnpm build
Acceptance Criteria (agent-executable only):
- After password change, signing in with
OldPass123!fails and signing in withNewPass123!succeeds - A second active browser context is no longer authorized after the password change
- Evidence files exist for redirect, validation failure, success state, old-password rejection, and second-session invalidation
pnpm lintandpnpm buildboth pass on the final implementation
QA Scenarios (MANDATORY - task incomplete without these):
Scenario: Old password fails and new password succeeds Tool: Playwright Steps: Complete the password change; sign out; attempt sign-in with `OldPass123!`; then attempt sign-in with `NewPass123!`. Expected: Old password sign-in fails; new password sign-in succeeds and returns to an authenticated page. Evidence: .sisyphus/evidence/task-6-old-vs-new-credential.png Scenario: Other sessions are revoked Tool: Playwright Steps: Open session A and session B signed in as the same user; change the password in session A; in session B navigate to `/dashboard` or refresh. Expected: Session B is redirected to sign-in or otherwise loses authenticated access. Evidence: .sisyphus/evidence/task-6-revoke-other-sessions.pngCommit: YES | Message:
wire password change flow and verify session behavior| Files: no net-new feature files expected beyond minimal polish; evidence output only - Category:
Final Verification Wave (MANDATORY - after ALL implementation tasks)
4 review agents run in PARALLEL. ALL must APPROVE. Present consolidated results to user and get explicit "okay" before completing. Do NOT auto-proceed after verification. Wait for user's explicit approval before marking work complete. Never mark F1-F4 as checked before getting user's okay. Rejection or user feedback -> fix -> re-run -> present again -> wait for okay.
- F1. Plan Compliance Audit - oracle
- F2. Code Quality Review - unspecified-high
- F3. Real Manual QA - unspecified-high (+ playwright if UI)
- F4. Scope Fidelity Check - deep
Commit Strategy
- Commit 1:
add protected settings page scaffold and dashboard entry - Commit 2:
add password change form UI and localization - Commit 3:
wire password change flow and verify session behavior
Success Criteria
- The feature remains scoped to authenticated password change only
/dashboardclearly leads users into account security settings/settingsis inaccessible without authentication- Password change succeeds only with the correct current password and valid new password
- QA evidence proves redirect, validation failure, success path, and new-credential sign-in behavior