docs(account): record step 3 (module hooks, kit re-pin) as built #394
@@ -1,6 +1,6 @@
|
|||||||
# module-uo — the tables it owns
|
# module-uo — the tables it owns
|
||||||
|
|
||||||
The 27 tables `module-uo` creates and owns, and the reasoning behind their shapes. **26 `shard_*`
|
The 33 tables `module-uo` creates and owns, and the reasoning behind their shapes. **32 `shard_*`
|
||||||
plus `uo_link_config`**, all created by the idempotent `server/db/schema.sql` fragment core replays
|
plus `uo_link_config`**, all created by the idempotent `server/db/schema.sql` fragment core replays
|
||||||
after its own schema on every boot, and all dropped by `server/db/purge.sql` when an operator purges
|
after its own schema on every boot, and all dropped by `server/db/purge.sql` when an operator purges
|
||||||
the module's data.
|
the module's data.
|
||||||
@@ -263,6 +263,36 @@ same way — `uo-static-3922-h33-<sha8>.png`. A key the shard has no art for wri
|
|||||||
an empty row would make it "held" and it would never be asked again, including after the operator
|
an empty row would make it "held" and it would never be asked again, including after the operator
|
||||||
patches in the graphic that was missing.
|
patches in the graphic that was missing.
|
||||||
|
|
||||||
|
## shard_pending_unlinks — what an account deletion left linked on the shard (MODULE_API 1.20.0)
|
||||||
|
|
||||||
|
When a website account is deleted, core asks the module first (`api.onUserDeleting`,
|
||||||
|
[`ACCOUNT_DELETION.md`](../../website/ACCOUNT_DELETION.md) §4.4). `shard_account_links` is only a
|
||||||
|
mirror: the shard keeps the site user id on the game account and reports it as `webId` on every
|
||||||
|
`mob.login`, so the module unlinks each game account on the shard, through the staff unlink's
|
||||||
|
`DELETE /link/{account}` (actor `web:account-deletion`), before the users row goes. This table is
|
||||||
|
what that unlink could not finish.
|
||||||
|
|
||||||
|
| Column | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| `account` | PK, the game account |
|
||||||
|
| `web_user_id` | the deleted user's id, which the shard may still report |
|
||||||
|
| `state` | `pending` (the shard was away) or `refused` (a protected staff account, 403) |
|
||||||
|
| `queued_at`, `attempts`, `last_attempt_at`, `last_error` | the retry's own record |
|
||||||
|
|
||||||
|
Four rules that are load-bearing:
|
||||||
|
|
||||||
|
- **Every linked account is written here BEFORE the first call to the shard**, and dropped when the
|
||||||
|
shard answers 200 or 404 (404: nothing to clear). Core gives the hook 10 s and one sidecar call can
|
||||||
|
take 12, so a hook core stops waiting for still leaves everything it had not finished queued.
|
||||||
|
- **No foreign key, on purpose.** Every row outlives the user it names; that is the point of it.
|
||||||
|
The mirror row in `shard_account_links` goes with the users cascade either way.
|
||||||
|
- **`pending` is retried; `refused` never is.** The retry runs when the WebSocket opens (which is
|
||||||
|
also the boot path, since boot never calls the shard) and on every live `server.hello`. A refused
|
||||||
|
row waits for the shard's staff to clear the tag by hand; Admin → Shard lists both kinds as *Still
|
||||||
|
linked on the shard*, from `GET /admin/uo-link/config`'s `pendingUnlinks`.
|
||||||
|
- **A live `mob.login` on the account with no `webId`, or another one, clears the row**, whoever
|
||||||
|
cleared the tag. A replayed login never does: one from before the link carries no `webId` either.
|
||||||
|
|
||||||
## shard_clilocs / shard_cliloc_meta — UO's localization table (Protocol 3.0)
|
## shard_clilocs / shard_cliloc_meta — UO's localization table (Protocol 3.0)
|
||||||
|
|
||||||
Items on the wire carry a `LabelNumber`, not a name. The bridge has always sent it —
|
Items on the wire carry a `LabelNumber`, not a name. The bridge has always sent it —
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Account deletion — a member deletes their own account, on the website and in the app
|
# Account deletion — a member deletes their own account, on the website and in the app
|
||||||
|
|
||||||
**Status:** plan of record, 2026-10-29, with every question answered (AD4-AD13). **§6 step 2
|
**Status:** plan of record, 2026-10-29, with every question answered (AD4-AD13). **§6 step 2
|
||||||
(core) built 2026-10-29** as website `feature/account-deletion`, `MODULE_API` 1.20.0; steps 3-6 are
|
(core) built 2026-10-29** and merged as website#232 (`7bd93b8`), `MODULE_API` 1.20.0. **Step 3
|
||||||
next. Each phase in §6 stops for the org lead before the next one starts.
|
(modules and kit) built 2026-10-30**; steps 4-6 are next. Each phase in §6 stops for the org lead before the next one starts.
|
||||||
|
|
||||||
**Why now.** Google Play's Data safety form asks whether the app lets people create an account, and
|
**Why now.** Google Play's Data safety form asks whether the app lets people create an account, and
|
||||||
an app that does must let them delete it, both **in the app** and at a **web address** given to Play
|
an app that does must let them delete it, both **in the app** and at a **web address** given to Play
|
||||||
@@ -333,6 +333,23 @@ Asked while building core (§6 step 2), the same day:
|
|||||||
3. **Module-Rust** (`edge`) and **Module-uo**: §4.4's hooks plus their core-ref pins, one PR
|
3. **Module-Rust** (`edge`) and **Module-uo**: §4.4's hooks plus their core-ref pins, one PR
|
||||||
each. Module-uo's PR adds `shard_pending_unlinks`, the retry, and the *still linked on the
|
each. Module-uo's PR adds `shard_pending_unlinks`, the retry, and the *still linked on the
|
||||||
shard* list. **Integration Kit**: the re-pin and the paragraph, one PR.
|
shard* list. **Integration Kit**: the re-pin and the paragraph, one PR.
|
||||||
|
**Built 2026-10-30**, all three pinned to `7bd93b8` with `coreApi` `^1.20.0`:
|
||||||
|
- **Module-Rust** (`edge`): `links.unlinkForDeletion`, as §4.4 says.
|
||||||
|
- **Module-uo**: `utils/accountDeletion.js`. Beyond §4.4:
|
||||||
|
- every account is queued *before* the first sidecar call, because one call can outlast the
|
||||||
|
hook's 10 s;
|
||||||
|
- the retry also runs on every live `server.hello` (the plugin reconnecting to a sidecar that
|
||||||
|
stayed up);
|
||||||
|
- a `pending` row clears on a live login without the `webId`, as a `refused` one does;
|
||||||
|
- *still linked on the shard* is `pendingUnlinks` on `GET /admin/uo-link/config` and a section
|
||||||
|
on Admin → Shard, so there is no new route.
|
||||||
|
|
||||||
|
The table is in [`modules/uo/SCHEMA.md`](../modules/uo/SCHEMA.md).
|
||||||
|
- **Integration Kit**: chapter 2 also gained the demo's two unlisted refusals (multipart and
|
||||||
|
`data:` URIs), which it had never taught.
|
||||||
|
- **Checked:** each repo's tests, and both modules' frozen-manifest job reproduced against
|
||||||
|
`7bd93b8`.
|
||||||
|
- **Not walked:** the live deletions are step 6.
|
||||||
4. **Android** (`edge`): §4.3. One PR.
|
4. **Android** (`edge`): §4.3. One PR.
|
||||||
5. **runicgateway.com**: §4.5, plus `PLAY_DATA_SAFETY.md` regenerated. One PR.
|
5. **runicgateway.com**: §4.5, plus `PLAY_DATA_SAFETY.md` regenerated. One PR.
|
||||||
6. **A walk**, using a throwaway account on each surface:
|
6. **A walk**, using a throwaway account on each surface:
|
||||||
|
|||||||
Reference in New Issue
Block a user