feat: game lobby service
This commit is contained in:
+139
-28
@@ -217,9 +217,10 @@ paths:
|
||||
operationId: updateMyProfile
|
||||
summary: Update self-service profile fields
|
||||
description: |
|
||||
`race_name` uniqueness is enforced through a canonical reservation
|
||||
policy that is case-insensitive, rejects the frozen anti-fraud
|
||||
confusable pairs, and preserves the original stored casing.
|
||||
Accepts only `display_name`. Validation delegates to
|
||||
`pkg/util/string.go:ValidateTypeName`; an empty value is accepted
|
||||
and resets any stored display name. `user_name` is immutable and is
|
||||
not returned in the request body.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/UserIDPath"
|
||||
requestBody:
|
||||
@@ -387,21 +388,21 @@ paths:
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/internal/user-lookups/by-race-name:
|
||||
/api/v1/internal/user-lookups/by-user-name:
|
||||
post:
|
||||
tags:
|
||||
- AdminUsers
|
||||
operationId: getUserByRaceName
|
||||
summary: Read one user by exact race name
|
||||
operationId: getUserByUserName
|
||||
summary: Read one user by exact user name
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UserLookupByRaceNameRequest"
|
||||
$ref: "#/components/schemas/UserLookupByUserNameRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Exact user lookup result for the supplied `race_name`.
|
||||
description: Exact user lookup result for the supplied `user_name`.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -482,6 +483,24 @@ paths:
|
||||
description: Filter by the derived game-join eligibility marker.
|
||||
schema:
|
||||
type: boolean
|
||||
- name: user_name
|
||||
in: query
|
||||
description: Filter by exact `user_name`.
|
||||
schema:
|
||||
$ref: "#/components/schemas/UserName"
|
||||
- name: display_name
|
||||
in: query
|
||||
description: Filter by `display_name`. Combined with `display_name_match`.
|
||||
schema:
|
||||
$ref: "#/components/schemas/DisplayName"
|
||||
- name: display_name_match
|
||||
in: query
|
||||
description: Match mode for `display_name`; defaults to `exact`.
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- exact
|
||||
- prefix
|
||||
responses:
|
||||
"200":
|
||||
description: Deterministically ordered page of users.
|
||||
@@ -728,6 +747,46 @@ paths:
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/internal/users/{user_id}/delete:
|
||||
post:
|
||||
tags:
|
||||
- AdminUsers
|
||||
operationId: deleteUser
|
||||
summary: Soft-delete one regular-user account
|
||||
description: |
|
||||
Soft-deletes the account identified by `user_id`. The account record is
|
||||
preserved for audit with a `deleted_at` timestamp. Subsequent external
|
||||
auth, self-service, admin-read, and lobby-eligibility operations
|
||||
addressing the same `user_id` return `404 subject_not_found`.
|
||||
|
||||
The command is idempotent per `user_id`: calling it after the account
|
||||
is already soft-deleted returns `404 subject_not_found` and does not
|
||||
re-emit the `user.lifecycle.deleted` event.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/UserIDPath"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DeleteUserRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Soft-delete applied successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DeleteUserResponse"
|
||||
"400":
|
||||
$ref: "#/components/responses/InvalidRequestError"
|
||||
"404":
|
||||
$ref: "#/components/responses/SubjectNotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
components:
|
||||
parameters:
|
||||
UserIDPath:
|
||||
@@ -766,14 +825,24 @@ components:
|
||||
trimmed value as the exact stored and lookup value. The service does
|
||||
not lowercase or otherwise canonicalize e-mail before storage or exact
|
||||
lookup.
|
||||
RaceName:
|
||||
UserName:
|
||||
type: string
|
||||
description: |
|
||||
Stored race name preserving the user-selected casing after successful
|
||||
uniqueness checks. Uniqueness is enforced against a canonical
|
||||
reservation key rather than exact string equality only.
|
||||
minLength: 1
|
||||
Immutable auto-generated platform handle in `player-<suffix>` form.
|
||||
The suffix is eight characters drawn from a confusable-free
|
||||
alphanumeric alphabet. Assigned once at account creation and never
|
||||
changes thereafter.
|
||||
pattern: "^player-[a-z0-9]{8}$"
|
||||
minLength: 15
|
||||
maxLength: 64
|
||||
DisplayName:
|
||||
type: string
|
||||
description: |
|
||||
Optional free-text user-facing label. Validated by
|
||||
`pkg/util/string.go:ValidateTypeName`. Empty values are accepted and
|
||||
represent no display name. Uniqueness is not enforced.
|
||||
minLength: 0
|
||||
maxLength: 30
|
||||
LanguageTag:
|
||||
type: string
|
||||
description: |
|
||||
@@ -827,6 +896,7 @@ components:
|
||||
- private_game_manage_block
|
||||
- game_join_block
|
||||
- profile_update_block
|
||||
- permanent_block
|
||||
LimitCode:
|
||||
type: string
|
||||
description: |
|
||||
@@ -837,6 +907,7 @@ components:
|
||||
- max_owned_private_games
|
||||
- max_pending_public_applications
|
||||
- max_active_game_memberships
|
||||
- max_registered_race_names
|
||||
ActorRef:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -926,8 +997,9 @@ components:
|
||||
description: |
|
||||
Present for `existing` and `created`. A `created` outcome returns
|
||||
the durable newly materialized `user_id` created together with an
|
||||
initial generated `player-<shortid>` race name and free
|
||||
entitlement snapshot.
|
||||
initial auto-generated `user_name` handle and the free
|
||||
entitlement snapshot. `display_name` defaults to empty for new
|
||||
accounts.
|
||||
block_reason_code:
|
||||
type: string
|
||||
description: Present only for `outcome=blocked`.
|
||||
@@ -1077,7 +1149,7 @@ components:
|
||||
required:
|
||||
- user_id
|
||||
- email
|
||||
- race_name
|
||||
- user_name
|
||||
- preferred_language
|
||||
- time_zone
|
||||
- entitlement
|
||||
@@ -1090,8 +1162,10 @@ components:
|
||||
$ref: "#/components/schemas/UserID"
|
||||
email:
|
||||
$ref: "#/components/schemas/Email"
|
||||
race_name:
|
||||
$ref: "#/components/schemas/RaceName"
|
||||
user_name:
|
||||
$ref: "#/components/schemas/UserName"
|
||||
display_name:
|
||||
$ref: "#/components/schemas/DisplayName"
|
||||
preferred_language:
|
||||
$ref: "#/components/schemas/LanguageTag"
|
||||
time_zone:
|
||||
@@ -1114,6 +1188,15 @@ components:
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
deleted_at:
|
||||
type: string
|
||||
format: date-time
|
||||
description: |
|
||||
Soft-delete timestamp. Present only when the account has been
|
||||
soft-deleted by a trusted `DeleteUser` command. External reads by
|
||||
stable `user_id` return `404 subject_not_found` for such accounts;
|
||||
admin listings exclude them unless explicitly asked via the
|
||||
`deleted` filter.
|
||||
GetMyAccountResponse:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -1126,14 +1209,15 @@ components:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
description: |
|
||||
The current implementation accepts only `race_name` here. Attempts to
|
||||
mutate `email` or `declared_country` are rejected as `400
|
||||
invalid_request` through strict unknown-field handling.
|
||||
Accepts only `display_name`. An empty value is accepted and resets
|
||||
any stored display name. Any other field (including the legacy
|
||||
`race_name` payload) is rejected as `400 invalid_request` through
|
||||
strict unknown-field handling.
|
||||
required:
|
||||
- race_name
|
||||
- display_name
|
||||
properties:
|
||||
race_name:
|
||||
$ref: "#/components/schemas/RaceName"
|
||||
display_name:
|
||||
$ref: "#/components/schemas/DisplayName"
|
||||
UpdateMySettingsRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -1238,14 +1322,14 @@ components:
|
||||
properties:
|
||||
email:
|
||||
$ref: "#/components/schemas/Email"
|
||||
UserLookupByRaceNameRequest:
|
||||
UserLookupByUserNameRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- race_name
|
||||
- user_name
|
||||
properties:
|
||||
race_name:
|
||||
$ref: "#/components/schemas/RaceName"
|
||||
user_name:
|
||||
$ref: "#/components/schemas/UserName"
|
||||
UserLookupResponse:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -1451,6 +1535,33 @@ components:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ActiveLimit"
|
||||
DeleteUserRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
description: |
|
||||
Soft-delete command payload. The caller is expected to be
|
||||
`Admin Service`. `actor.type` must be non-empty; `actor.id` is
|
||||
optional.
|
||||
required:
|
||||
- reason_code
|
||||
- actor
|
||||
properties:
|
||||
reason_code:
|
||||
type: string
|
||||
actor:
|
||||
$ref: "#/components/schemas/ActorRef"
|
||||
DeleteUserResponse:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- user_id
|
||||
- deleted_at
|
||||
properties:
|
||||
user_id:
|
||||
$ref: "#/components/schemas/UserID"
|
||||
deleted_at:
|
||||
type: string
|
||||
format: date-time
|
||||
ErrorResponse:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
Reference in New Issue
Block a user