feat(account): self-service account deletion, MODULE_API 1.20.0
ACCOUNT_DELETION.md phase 2 (core): a member deletes their own account on
the website, and the admin route runs the same procedure.
- DELETE /api/v1/auth/me/account: typed username, password always (AD7),
and a 2FA or recovery code when 2FA is on. A wrong password or code is
400, not 401 (AD12), so the app's refresh-on-401 never replays it.
409 password_required and last_admin; the demo's shared logins are
locked.
- auth/accountDeletion.js: module hooks first, then one transaction that
reserves a staff username (reserved_usernames, AD9) and deletes the row,
then a Teams reconcile, the audit entry (no username) and a notice to
the old address (new protected template auth.account-deleted).
- MODULE_API 1.20.0: api.onUserDeleting({ userId, deletedBy }), before the
delete, 10 s limit, cannot veto (AD10, AD11).
- utils/displayAuthor.js: a deleted account's username snapshots read
"[deleted player]" to members and the stored name, marked, to staff
(AD5, AD6). Used by the forum, the Reports queue, the guest list and
the Team digest. A deleted account drops off Forum guests (AD13).
- Reserved names refuse at every username write, answered as "taken".
- Web: Delete my account on the player and staff Account pages; staff
views mark "(deleted account)".
- OpenAPI regenerated; route manifest and engagement manifest regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -157,6 +157,36 @@ const SEEDS = [
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
// ACCOUNT_DELETION.md §4.1 step 3: the one notice a person gets if somebody
|
||||
// else used their unlocked phone. It goes to the address the account HAD,
|
||||
// read before the row went, and there is no link in it because there is no
|
||||
// account left for a link to reach.
|
||||
key: 'auth.account-deleted',
|
||||
name: 'Account deleted',
|
||||
channel: 'email',
|
||||
protected: true,
|
||||
seedVersion: 1,
|
||||
subject: 'Your {{siteName}} account was deleted',
|
||||
variables: [
|
||||
{ name: 'username', type: 'string', required: true, example: 'Darrow' },
|
||||
{ name: 'deletedOn', type: 'string', required: true, example: '29 October 2026' },
|
||||
{ name: 'byWhom', type: 'string', required: false, example: ' at your request' },
|
||||
],
|
||||
blocks: [
|
||||
text('p1', 'The {{siteName}} account “{{username}}” was deleted on {{deletedOn}}{{byWhom}}.'),
|
||||
text(
|
||||
'p2',
|
||||
'Its sign-in, email address, two-factor settings, linked sign-ins and game links are gone. ' +
|
||||
'What it wrote where others read it stays, and other members see it as written by “[deleted player]”.',
|
||||
),
|
||||
text(
|
||||
'p3',
|
||||
'If you did not ask for this, contact the {{siteName}} staff at {{siteUrl}}. ' +
|
||||
'A deleted account cannot be restored, but they can find out what happened.',
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'admin.contact-message',
|
||||
name: 'Contact form message',
|
||||
|
||||
Reference in New Issue
Block a user