Adds the player-facing half of game account management: a panel on
/community/servers/[id] that shows your linked account for that server,
creates one, and changes its password.
None of these emulators speak OIDC and none will - each ships its own
login against its own auth database. So this is a bridge, not SSO: one
Drop identity tied to one native account per server, enforced by a unique
index on (userId, serverSlug). That constraint IS the feature.
Drop owns identity, authorization, the link table and the UI. The
per-game DB access and password crypto stay in mmo-portal's provider API
(SRP6 verifiers, EQEmu hashing) - code that writes into live auth DBs and
fails silently when subtly wrong.
The password never touches Drop's database; it goes straight through to
the provider, which turns it into whatever that emulator wants.
Notable details:
- GameServer.slug names the game, provider.key names the emulator. They
agree for eqemu and daoc but wow != trinitycore, so the mapping is an
explicit three-entry constant, not an assumption.
- Panel renders NOTHING when a server has no account backend (Impostor is
a lobby with no identity), rather than a dead button.
- 'backend unreachable' is kept distinct from 'you have no account' - the
latter would invite a duplicate during an outage.
- Provision creates in the game first, then links. The reverse would
leave a link pointing at a nonexistent account, which reads as
corruption to every later call.
- Authorization is just an authenticated Drop session with the ACL: Drop
access and game access already imply each other, so a third gate could
only disagree with them.
Typecheck clean.