From 985f53efa2d34849f35c8e0f4129f861be762e76 Mon Sep 17 00:00:00 2001 From: Konstantinos Arvanitakis Date: Fri, 25 Sep 2026 15:58:41 +0300 Subject: [PATCH] Bump Version to 0.22.0 --- CHANGELOG.md | 41 +++++++++++++++++++++++++++++++++++++++++ composer.json | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27419eb..a74812f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,47 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## [0.22.0] - 2026-09-25 + +### Added +- `Modules\Core\Customer\Services\CustomerEmailChangeService` — changing an account's login + email (core's login is passwordless, so the email IS the login): `request()` validates the new + address is free and throttled (3 codes/10min), `confirm()` allows 5 wrong guesses per code, + re-checks the address is still free, switches it, notifies the old address (masked new + address), and claims guest orders for the new email. The pending change lives on the user's + own row (`pending_email`/`pending_email_code_hash`/`pending_email_expires_at`/ + `pending_email_attempts` — new migration), the same convention as the existing OTP login + columns, rather than the session — a code arrives by email and is often opened on a different + device/session than the one that requested it. New core-owned mailables + (`Auth\Mail\EmailChangeCodeMail`/`EmailChangedNoticeMail`) with default views, overridable + per-app the same way `UserOtpMail`'s already is. Dispatches a new `Auth\Events\ + UserEmailChanged` event. +- `Modules\Core\Customer\Services\CustomerAccountService::setRecoveryConsent()` — the account's + standing "email me a reminder if I don't finish my order" opt-in, written to the customer's + meta in the same shape `Checkout\Services\CheckoutService::setRecoveryConsent()` already writes + on the cart. Skips the write when nothing changed; dispatches a new `Customer\Events\ + CustomerRecoveryConsentSet` event (also wired into the existing account-activity audit log). + 3dealer's own duplicated implementations in `CheckoutController`/`AccountController` now call + this instead. +- `terms_accepted_at`/`terms_version`/`privacy_policy_version` columns on `users` — recorded once, + by a new `Auth\Listeners\RecordLegalAcceptanceForNewUser` (listening on `UserCreated`), the + moment a genuinely new signup requests their first OTP code; never touched again for an + existing user. Included in the User-scope privacy export (`CustomerDataProvider:: + exportForUser()`). +- ~90 previously-unseeded `storefront.*` translation keys (login/OTP copy, account profile and + email-change flow, order history, contact form, product custom-fields and stock-error + messages, reviews, wishlist) added to `Localization\Services\StorefrontLabels` — these were + already called via `__()`/`trans_choice()` across a consuming app's views with no seeded + value at all, silently rendering the raw translation key in production. + +### Fixed +- `CustomerAccountService::WRITABLE_PROFILE_FIELDS` listed `vat_no`, but Lunar's `customers` + column has been `tax_identifier` since a 2025 Lunar migration — passing `vat_no` was silently + dropped by the allowlist, and `tax_identifier` couldn't be written through `updateProfile()` at + all. Consuming code was working around this with a separate direct `$customer->update(...)` + call that bypassed `CustomerProfileUpdated`'s audit trail entirely; that workaround is no + longer needed now that the field is correctly allowlisted. + ## [0.21.1] - 2026-09-25 ### Changed diff --git a/composer.json b/composer.json index b96d1a0..1d3bf23 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "boboko/core", "description": "Core module — authentication and shared panel behaviour", "type": "library", - "version": "0.21.1", + "version": "0.22.0", "autoload": { "psr-4": { "Modules\\Core\\": "src/"