362 lines
23 KiB
Markdown
362 lines
23 KiB
Markdown
|
|
# 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 `/settings` page that follows the repo's existing server-page plus client-component auth pattern.
|
||
|
|
> **Deliverables**:
|
||
|
|
> - Dashboard entry affordance to account security settings
|
||
|
|
> - Protected `/settings` page with localized password-change UI
|
||
|
|
> - Better Auth `changePassword` integration 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 `/settings` explicitly instead of assuming auth.
|
||
|
|
- Keep scope to password/security only; do not expand into general settings architecture.
|
||
|
|
- Use Better Auth's existing `changePassword` flow 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.tsx` to `/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 lint` completes successfully
|
||
|
|
- `pnpm build` completes successfully
|
||
|
|
- Visiting `/settings` while 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 `/settings` route with explicit redirect behavior
|
||
|
|
- Dashboard affordance linking to `/settings`
|
||
|
|
- Fields for `currentPassword`, `newPassword`, and `confirmPassword`
|
||
|
|
- 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.json` and `messages/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 `/settings` page scaffold
|
||
|
|
|
||
|
|
**What to do**: Read the relevant Next.js App Router docs under `node_modules/next/dist/docs/` before coding, then create `src/app/settings/page.tsx` as a server page that checks authentication with the existing server auth helpers from `src/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 in `src/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` - `/settings` already 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.tsx` exists and remains a server page wrapper rather than a client-heavy file
|
||
|
|
- [ ] Unauthenticated access to `/settings` redirects to `/sign-in?callbackURL=/settings`
|
||
|
|
- [ ] Authenticated access to `/settings` renders the dedicated password settings component
|
||
|
|
- [ ] `pnpm lint` passes 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.png
|
||
|
|
```
|
||
|
|
|
||
|
|
**Commit**: 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
|
||
|
|
|
||
|
|
- [ ] 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 `/settings` via 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):
|
||
|
|
- [ ] `/dashboard` contains 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 lint` passes 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.png
|
||
|
|
```
|
||
|
|
|
||
|
|
**Commit**: YES | Message: `add protected settings page scaffold and dashboard entry` | Files: `src/app/dashboard/page.tsx`
|
||
|
|
|
||
|
|
- [ ] 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 into `src/app/settings/page.tsx`. Use the same card, field, button, spinner, and password input-group patterns already used in `src/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 reuse `AuthForm` directly 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/`
|
||
|
|
- [ ] `/settings` renders a single password/security card with localized heading, description, and button text
|
||
|
|
- [ ] Both `messages/en.json` and `messages/pl.json` contain 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.png
|
||
|
|
```
|
||
|
|
|
||
|
|
**Commit**: 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`
|
||
|
|
|
||
|
|
- [ ] 4. Implement client-side validation and field UX
|
||
|
|
|
||
|
|
**What to do**: Define a dedicated Zod schema for the password-change form that requires `currentPassword`, reuses `defaultPasswordValidator()` for `newPassword`, enforces `confirmPassword === newPassword`, and rejects `newPassword === 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 for `newPassword`
|
||
|
|
- Pattern: `src/components/auth/AuthForm.tsx` - React Hook Form + Zod resolver usage and inline `FieldError` handling
|
||
|
|
- 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 `newPassword` and `confirmPassword` surfaces 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.png
|
||
|
|
```
|
||
|
|
|
||
|
|
**Commit**: YES | Message: `add password change form UI and localization` | Files: `src/components/settings/PasswordChangeCard.tsx`, related validation helpers only if needed
|
||
|
|
|
||
|
|
- [ ] 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`, and `revokeOtherSessions: 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 build` passes 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.png
|
||
|
|
```
|
||
|
|
|
||
|
|
**Commit**: 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
|
||
|
|
|
||
|
|
- [ ] 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: true` is 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 existing `pnpm dev`, `pnpm lint`, and `pnpm build`
|
||
|
|
|
||
|
|
**Acceptance Criteria** (agent-executable only):
|
||
|
|
- [ ] After password change, signing in with `OldPass123!` fails and signing in with `NewPass123!` 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 lint` and `pnpm build` both 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.png
|
||
|
|
```
|
||
|
|
|
||
|
|
**Commit**: YES | Message: `wire password change flow and verify session behavior` | Files: no net-new feature files expected beyond minimal polish; evidence output only
|
||
|
|
|
||
|
|
## 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
|
||
|
|
- `/dashboard` clearly leads users into account security settings
|
||
|
|
- `/settings` is 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
|