asobi_ops_controller (asobi v0.72.6)
View SourceHTTP surface of the ops plane: every read, plus the two account-lifecycle routes.
Every list endpoint here returns the same envelope, clamps its own paging, and rejects a sort field it does not recognise with 400 rather than ordering by something the caller did not ask for.
These routes are mounted behind asobi_ops_auth:verify/1, the operator
capability check (ADR 0007) - never the player-scoped bearer check the rest of
/api/v1 uses, which would let any authenticated player, guest included,
enumerate the deployment. Every read projection here is still held to exactly
what the equivalent public endpoint already exposes.
erase_player/1 and export_player/1 are the exceptions to that last
sentence, deliberately: an operator answering a deletion or access request
needs more than a player's own profile view. They are the only two routes on
this plane that are not reads, they carry their own capability classes
(erasure and player_data), and the erasure is audited inside its own
transaction. See asobi_player_erase.
Summary
Functions
Erase one player and everything core holds about them. Irreversible.
Everything core holds about one player, as one JSON object.
Types
-type response() :: {json, map()} | {json, integer(), map(), map()} | {asobi_error, asobi_error:code()} | {asobi_error, asobi_error:code(), asobi_error:details()}.
Functions
-spec chat_channels(cowboy_req:req()) -> response().
-spec chat_messages(cowboy_req:req()) -> response().
-spec economy_item(cowboy_req:req()) -> response().
-spec economy_items(cowboy_req:req()) -> response().
-spec economy_listing(cowboy_req:req()) -> response().
-spec economy_listings(cowboy_req:req()) -> response().
-spec erase_player(cowboy_req:req()) -> response().
Erase one player and everything core holds about them. Irreversible.
The body must echo the player's username, and the echo is checked against
the row server-side. That guard is not distribution-shaped - the limitation it
answers is a human clicking the wrong row, or a page being clickjacked into
posting on the operator's behalf - so OTP does not dissolve it. It costs one
comparison and makes an unattended POST insufficient.
-spec export_player(cowboy_req:req()) -> response().
Everything core holds about one player, as one JSON object.
player_data, not read: a leaderboard view is one thing, and the whole of
one identified person's record is another.
-spec features(cowboy_req:req()) -> response().
-spec leaderboard_entries(cowboy_req:req()) -> response().
-spec leaderboards(cowboy_req:req()) -> response().
-spec match(cowboy_req:req()) -> response().
-spec matches(cowboy_req:req()) -> response().
-spec matchmaker(cowboy_req:req()) -> response().
-spec notifications(cowboy_req:req()) -> response().
-spec player(cowboy_req:req()) -> response().
-spec players(cowboy_req:req()) -> response().
-spec stats(cowboy_req:req()) -> response().
-spec tournament(cowboy_req:req()) -> response().
-spec tournaments(cowboy_req:req()) -> response().