Retroactively author 15 grouped detail docs covering the backend functional (feat/fix) commits made before the change ledger was established (fad48ff), closing the ledger's detail-doc axis for the pre-convention history. Each doc groups a feature's constituent commits, lists their SHAs with subjects, and carries a backfill note stating it was reconstructed from git history on 2026-07-07 and not independently re-verified (current tree green at9911b8c). Add a Detail docs section to INDEX.md linking every detail doc (the 6 existing + 15 backfill) to the commit(s) it covers, so a doc is findable from the index without a column on the auto-generated ledger table. Catch the table up with the missing9911b8crow. Scope: backend (Go/Java/K8s) only, per the ledger's stated convention that frontend/panel commits are the collaborator's UI work; non-functional commits (docs/style/chore/refactor) keep their table row without a dedicated detail doc.
37 lines
2.6 KiB
Markdown
37 lines
2.6 KiB
Markdown
# Player onboarding data layer §B2: email-OTP, account-link, QR, Bind-Code (ledger backfill)
|
||
|
||
- **Type:** feature + fix — retroactive ledger entry
|
||
- **Date:** 2026-06-27 – 2026-07-03
|
||
- **Area:** `internal/api` (onboarding/auth-bind handlers), `internal/store` (migrations 0004–0006)
|
||
- **Commits:**
|
||
- `dbe34a1` feat(api): player email-OTP verification (§B2) — `POST /account/email/{start,verify}`; 6-digit code, SHA-256-at-rest, 10-min TTL, 5-attempt cap enforced in the repo
|
||
- `1f8b9bb` feat(api): record account-link auth source (`mojang|thirdparty`) for the dual-Yggdrasil split (§10)
|
||
- `116595f` feat(api): QR scan-login completion poll on the internal face (`GET /internal/account/link/status/{mc_uuid}`) — read-only, reuses `UserByMCUUID`, no migration
|
||
- `fe2ece0` feat(api): public Bind-Code onboarding (`POST /auth/bind`) — the one pre-account entrypoint of `console.<root_domain>`; refuses a staff-UUID code with 403 without consuming it, so the public door provably never yields an admin principal
|
||
- `55592ed` feat(auth): public auth-bind endpoint wiring
|
||
- `6c3999a` fix(api): rate-limit email-OTP sends to close the email-bomb vector
|
||
- `879b177` fix(api): make OTP-start throttle atomic to close the concurrent-burst bypass
|
||
- **Tasks:** #29 (B2 data layer), #32 (OTP rate-limit), #35 (atomic throttle), #39 (console access model)
|
||
|
||
## What it did
|
||
|
||
Built the Go-verifiable data layer of forced web onboarding: prove control of an email
|
||
(OTP), record which Yggdrasil authenticated an in-game UUID, let a phone already signed in
|
||
to the panel complete a QR device-code link, and let an account-less player redeem a
|
||
one-time Bind Code minted in the Login Lobby to create+link+session in one public step.
|
||
The two fixes bound the OTP abuse surface — a per-target send rate limit and an atomic
|
||
reserve that closes the check-then-act race on the attempt counter.
|
||
|
||
## Why
|
||
|
||
The spec forces onboarding through the web so every account is provably email-controlled
|
||
and UUID-linked before it can operate anything. The `op.console` redline in `fe2ece0` — a
|
||
staff-UUID code is refused without being consumed — is what keeps the public console door
|
||
from ever minting an admin principal.
|
||
|
||
> **Backfill note.** Reconstructed 2026-07-07 from the commit history. The account/session
|
||
> logic, single-use codes, and the op.console redline were covered by handler tests + the
|
||
> OpenAPI parity gate at each commit; the identity guarantee behind a Bind Code lives in
|
||
> velocity/Java (CODE-ONLY) and is not verifiable from this repo. Not independently
|
||
> re-verified for this doc; current tree green at `9911b8c`.
|