Files
summercms/.planning/phases/07-user-plugin-and-authentication/07-03-SUMMARY.md
2026-09-22 16:48:10 +02:00

5.4 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
07-user-plugin-and-authentication 03 auth
user
password-reset
activation
avatar
mail
console
phase provides
07-user-plugin-and-authentication login, register, MailTemplate, ResolveMailLocale, postcard Mailer
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
07-04
07-05
07-06
added patterns
constant-time code compare
two-phase avatar blob delete
postcard memory driver for mail assertions
created modified
../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
../fonoteka.go/plugins/golem15/user/controllers/api_controller.go
../fonoteka.go/plugins/golem15/user/plugin.go
../fonoteka.go/plugins/golem15/user/routes.go
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
Pattern: reset and activation links are {id}!{code} query values
Pattern: mail vars expose both lowercase and Go-template capital keys
95min 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.