From 4e56ff98b07369281a1b2cd0dd9d5a1781195922 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Tue, 22 Sep 2026 16:48:10 +0200 Subject: [PATCH] docs(07-03): complete the account management plan Co-authored-by: Cursor --- .planning/ROADMAP.md | 4 +- .planning/STATE.md | 17 +-- .../07-03-SUMMARY.md | 125 ++++++++++++++++++ 3 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 .planning/phases/07-user-plugin-and-authentication/07-03-SUMMARY.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index ddaaf8e..e86cd4f 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -285,7 +285,7 @@ Plans: **Wave 3** *(blocked on 07-02)* -- [ ] 07-03-PLAN.md — Account management: forgot/reset password, activation, update, change-password, avatar, mail +- [x] 07-03-PLAN.md — Account management: forgot/reset password, activation, update, change-password, avatar, mail - [ ] 07-04-PLAN.md — Personal API tokens (mint/list/revoke), me/locale, 423-exempt route-table proof **Wave 4** *(blocked on 07-03, 07-04)* @@ -448,7 +448,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → | 4. CLI scaffolding, i18n and mail | 4/4 | Complete | 2026-09-18 | | 5. Data layer full fidelity | 6/6 | Complete | 2026-09-18 | | 6. HTTP routing, auth groups and rate limiting | 14/14 | Complete | 2026-09-21 | -| 7. User plugin and authentication | 2/6 | In Progress| | +| 7. User plugin and authentication | 3/6 | In Progress| | | 8. OAuth2.1 authorization server | 0/TBD | Not started | - | | 9. Backend admin authentication and schema pipeline | 0/TBD | Not started | - | | 10. Admin Vue SPA | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 21fccdc..e4fe360 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: executing -stopped_at: Completed 07-01-PLAN.md -last_updated: "2026-09-22T13:14:46.649Z" +stopped_at: Completed 07-03-PLAN.md +last_updated: "2026-09-22T14:47:05.901Z" last_activity: 2026-09-22 progress: total_phases: 15 completed_phases: 6 total_plans: 43 - completed_plans: 39 + completed_plans: 40 percent: 40 --- @@ -26,11 +26,11 @@ See: .planning/PROJECT.md (updated 2026-09-16) ## Current Position Phase: 07 (user-plugin-and-authentication) — EXECUTING -Plan: 3 of 6 +Plan: 4 of 6 Status: Ready to execute Last activity: 2026-09-22 -Progress: [█████████░] 91% +Progress: [█████████░] 93% ## Performance Metrics @@ -83,6 +83,7 @@ Progress: [█████████░] 91% | Phase 06 P11 | 12h 30m | 1 tasks | 1 files | | Phase 07 P01 | 12 min | 3 tasks | 20 files | | Phase 07 P02 | 83m | 3 tasks | 22 files | +| Phase 07 P03 | 95m | 3 tasks | 28 files | ## Accumulated Context @@ -215,6 +216,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-09-22T11:42:50.114Z -Stopped at: Completed 07-01-PLAN.md -Resume file: None +Last session: 2026-09-22T14:47:05.870Z +Stopped at: Completed 07-03-PLAN.md +Resume file: 07-04-PLAN.md diff --git a/.planning/phases/07-user-plugin-and-authentication/07-03-SUMMARY.md b/.planning/phases/07-user-plugin-and-authentication/07-03-SUMMARY.md new file mode 100644 index 0000000..fa14177 --- /dev/null +++ b/.planning/phases/07-user-plugin-and-authentication/07-03-SUMMARY.md @@ -0,0 +1,125 @@ +--- +phase: 07-user-plugin-and-authentication +plan: 03 +subsystem: auth +tags: [user, password-reset, activation, avatar, mail, console] + +requires: + - phase: 07-user-plugin-and-authentication + provides: login, register, MailTemplate, ResolveMailLocale, postcard Mailer +provides: + - forgot-password, reset-password, activate, activate-by-code + - update, change-password, marketing-consent + - avatar upload and remove through system_files + - mail.activate, mail.restore, mail.reactivate (pl and -en) + - user:require-password-change +affects: [07-04, 07-05, 07-06] + +tech-stack: + added: [] + patterns: [constant-time code compare, two-phase avatar blob delete, postcard memory driver for mail assertions] + +key-files: + created: + - ../fonoteka.go/plugins/golem15/user/classes/codes.go + - ../fonoteka.go/plugins/golem15/user/console/require_password_change.go + - ../fonoteka.go/plugins/golem15/user/views/mail/activate.htm + modified: + - ../fonoteka.go/plugins/golem15/user/controllers/api_controller.go + - ../fonoteka.go/plugins/golem15/user/plugin.go + - ../fonoteka.go/plugins/golem15/user/routes.go + +key-decisions: + - "Forgot-password always returns the same 200 body" + - "Authenticated activate ignores a failed code and still returns the user" + - "Avatar blobs are deleted only after the system_files transaction commits" + +patterns-established: + - "Pattern: reset and activation links are {id}!{code} query values" + - "Pattern: mail vars expose both lowercase and Go-template capital keys" + +requirements-completed: [] + +duration: 95min +completed: 2026-09-22 +--- + +# Phase 7 Plan 03: Account management Summary + +**Password reset, activation, profile update, avatar upload, the six user mail templates, and `user:require-password-change`.** + +## Performance + +- **Duration:** 95 min +- **Started:** 2026-09-22T13:15:00Z +- **Completed:** 2026-09-22T14:50:00Z +- **Tasks:** 3 +- **Files modified:** 28 + +## Accomplishments + +- Forgot-password always answers `{"message":"If that email exists, a reset link has been sent."}`. Reset consumes `{id}!{code}`, stores the new hash, and sets `tokens_valid_after` so older tokens fail. +- Public activate-by-code restores a soft-deleted user and returns a token. The authenticated activate route returns the user payload even when the code does not match. +- Profile update, change-password, and marketing consent write the signed-in row directly. A password change keeps the presenting token and invalidates older ones. +- Avatar upload sniffs the first bytes, stores an `attach.File` with morph `Golem15\User\Models\User`, and fills `has_avatar` plus a 128px `avatar_url`. +- Polish and English mail templates render through the postcard memory driver. `user:require-password-change` sets `must_change_password`. + +## Task Commits + +1. **Task 1: Password reset and activation** — `9b80aa7` in `fonoteka.go` +2. **Task 2: Profile, change-password, marketing consent** — `aba832a` in `fonoteka.go` +3. **Task 3: Avatar, mail templates, require-password-change** — `5c6a735` in `fonoteka.go` + +## Files Created/Modified + +- `plugins/golem15/user/classes/codes.go` — issue and verify reset and activation codes +- `plugins/golem15/user/controllers/api_controller.go` — account, profile, and avatar handlers +- `plugins/golem15/user/views/mail/` — activate, restore, reactivate, and the user layout +- `plugins/golem15/user/console/require_password_change.go` — console command +- `plugins/golem15/user/plugin.go` — `HasMailTemplates` and `HasCommands` + +## Decisions Made + +NULL `reset_password_code_issued_at` is treated as `time.Now()` at check time, so a cutover code does not expire through the TTL until it is consumed. + +`has_self_set_password` is set true before `Create` on register. GORM would otherwise insert the zero value and override the column default, and change-password would then fail closed. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] `required` rejects JSON false** +- **Found during:** Task 2 +- **Issue:** go-playground's `required` treats `false` as empty, so marketing consent `false` returned 422. +- **Fix:** The handler checks that the key is present and that the value is a bool. +- **Files modified:** `controllers/api_controller.go` +- **Committed in:** `aba832a` + +**2. [Rule 2 - Missing] User-mode register did not issue an activation code** +- **Found during:** Task 3 +- **Issue:** The activation mail had to carry `link` and `code`. The user-mode branch only named the template. +- **Fix:** `IssueActivationCode` runs before the send. Vars include `name`/`Name`, `link`/`Link`, and `code`/`Code` so the Go templates render and the test can read `Vars["link"]`. +- **Files modified:** `controllers/api_controller.go` +- **Committed in:** `5c6a735` + +--- + +**Total deviations:** 2 auto-fixed +**Impact on plan:** Consent false is a successful update. Activation mail now contains the code the public activate route consumes. + +## Issues Encountered + +None + +## User Setup Required + +None - no external service configuration required. + +## Next Phase Readiness + +Ready for 07-04 (personal API tokens and me/locale). AUTH-01 stays open until the phase requirement is signed off. AUTH-02's payload seam is unchanged. + +## Self-Check: PASSED + +- Handlers for reset, activation, profile, avatar, and the console command are on `fonoteka.go` master (`9b80aa7`, `aba832a`, `5c6a735`). +- `go test ./plugins/golem15/user/...` passed, including `TestUploadAvatar`, `TestRemoveAvatar`, `TestMail`, and `TestRequirePasswordChange`.