docs(07-03): complete the account management plan
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -285,7 +285,7 @@ Plans:
|
|||||||
|
|
||||||
**Wave 3** *(blocked on 07-02)*
|
**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
|
- [ ] 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)*
|
**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 |
|
| 4. CLI scaffolding, i18n and mail | 4/4 | Complete | 2026-09-18 |
|
||||||
| 5. Data layer full fidelity | 6/6 | 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 |
|
| 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 | - |
|
| 8. OAuth2.1 authorization server | 0/TBD | Not started | - |
|
||||||
| 9. Backend admin authentication and schema pipeline | 0/TBD | Not started | - |
|
| 9. Backend admin authentication and schema pipeline | 0/TBD | Not started | - |
|
||||||
| 10. Admin Vue SPA | 0/TBD | Not started | - |
|
| 10. Admin Vue SPA | 0/TBD | Not started | - |
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ gsd_state_version: 1.0
|
|||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
status: executing
|
status: executing
|
||||||
stopped_at: Completed 07-01-PLAN.md
|
stopped_at: Completed 07-03-PLAN.md
|
||||||
last_updated: "2026-09-22T13:14:46.649Z"
|
last_updated: "2026-09-22T14:47:05.901Z"
|
||||||
last_activity: 2026-09-22
|
last_activity: 2026-09-22
|
||||||
progress:
|
progress:
|
||||||
total_phases: 15
|
total_phases: 15
|
||||||
completed_phases: 6
|
completed_phases: 6
|
||||||
total_plans: 43
|
total_plans: 43
|
||||||
completed_plans: 39
|
completed_plans: 40
|
||||||
percent: 40
|
percent: 40
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -26,11 +26,11 @@ See: .planning/PROJECT.md (updated 2026-09-16)
|
|||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 07 (user-plugin-and-authentication) — EXECUTING
|
Phase: 07 (user-plugin-and-authentication) — EXECUTING
|
||||||
Plan: 3 of 6
|
Plan: 4 of 6
|
||||||
Status: Ready to execute
|
Status: Ready to execute
|
||||||
Last activity: 2026-09-22
|
Last activity: 2026-09-22
|
||||||
|
|
||||||
Progress: [█████████░] 91%
|
Progress: [█████████░] 93%
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -83,6 +83,7 @@ Progress: [█████████░] 91%
|
|||||||
| Phase 06 P11 | 12h 30m | 1 tasks | 1 files |
|
| Phase 06 P11 | 12h 30m | 1 tasks | 1 files |
|
||||||
| Phase 07 P01 | 12 min | 3 tasks | 20 files |
|
| Phase 07 P01 | 12 min | 3 tasks | 20 files |
|
||||||
| Phase 07 P02 | 83m | 3 tasks | 22 files |
|
| Phase 07 P02 | 83m | 3 tasks | 22 files |
|
||||||
|
| Phase 07 P03 | 95m | 3 tasks | 28 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -215,6 +216,6 @@ Items acknowledged and carried forward from previous milestone close:
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-09-22T11:42:50.114Z
|
Last session: 2026-09-22T14:47:05.870Z
|
||||||
Stopped at: Completed 07-01-PLAN.md
|
Stopped at: Completed 07-03-PLAN.md
|
||||||
Resume file: None
|
Resume file: 07-04-PLAN.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`.
|
||||||
Reference in New Issue
Block a user