feat: user service
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
# Main Flows and Boundaries
|
||||
|
||||
## Auth / Session -> User
|
||||
|
||||
`Auth / Session Service` uses synchronous REST calls for user ownership
|
||||
decisions during public auth.
|
||||
|
||||
### Resolve by e-mail
|
||||
|
||||
`POST /api/v1/internal/user-resolutions/by-email`
|
||||
|
||||
Outcome vocabulary:
|
||||
|
||||
- `creatable`
|
||||
- `existing`
|
||||
- `blocked`
|
||||
|
||||
The decision is based on exact-after-trim e-mail matching plus the current
|
||||
block state for that subject.
|
||||
|
||||
### Ensure by e-mail
|
||||
|
||||
`POST /api/v1/internal/users/ensure-by-email`
|
||||
|
||||
Rules:
|
||||
|
||||
- `registration_context` is required
|
||||
- `registration_context` is create-only
|
||||
- existing users ignore the supplied registration context
|
||||
- blocked subjects return `blocked` rather than creating a user
|
||||
- the current rollout sends temporary `preferred_language="en"` from
|
||||
authsession and forwards the public confirm `time_zone`
|
||||
|
||||
Create side effects:
|
||||
|
||||
- generate opaque `user_id`
|
||||
- generate default `player-*` race name
|
||||
- store initial preferred language and time zone
|
||||
- materialize the initial free entitlement snapshot
|
||||
- publish initialization-style profile, settings, and entitlement events
|
||||
|
||||
## Gateway -> User
|
||||
|
||||
Gateway owns the external authenticated gRPC contract and transcodes to this
|
||||
service's internal REST API.
|
||||
|
||||
External authenticated message types:
|
||||
|
||||
- `user.account.get`
|
||||
- `user.profile.update`
|
||||
- `user.settings.update`
|
||||
|
||||
Internal REST routes:
|
||||
|
||||
- `GET /api/v1/internal/users/{user_id}/account`
|
||||
- `POST /api/v1/internal/users/{user_id}/profile`
|
||||
- `POST /api/v1/internal/users/{user_id}/settings`
|
||||
|
||||
Rules:
|
||||
|
||||
- gateway derives `user_id` from authenticated session context only
|
||||
- success returns the shared account aggregate
|
||||
- business errors return stable `code` and `message`
|
||||
- timeout or upstream `503` stay transport-level unavailable at gateway
|
||||
|
||||
### Profile update
|
||||
|
||||
`UpdateMyProfile` changes only `race_name`.
|
||||
|
||||
Rules:
|
||||
|
||||
- preserve stored casing on success
|
||||
- enforce canonical reservation uniqueness
|
||||
- reject conflicts as `409 conflict`
|
||||
- reject writes while `profile_update_block` is active
|
||||
- return current aggregate on no-op rename
|
||||
|
||||
### Settings update
|
||||
|
||||
`UpdateMySettings` changes only:
|
||||
|
||||
- `preferred_language`
|
||||
- `time_zone`
|
||||
|
||||
Rules:
|
||||
|
||||
- validate BCP 47 and IANA semantics
|
||||
- reject writes while `profile_update_block` is active
|
||||
- return the refreshed account aggregate
|
||||
|
||||
## Lobby -> User
|
||||
|
||||
`Game Lobby Service` reads one synchronous eligibility snapshot through:
|
||||
|
||||
- `GET /api/v1/internal/users/{user_id}/eligibility`
|
||||
|
||||
Rules:
|
||||
|
||||
- unknown users return `exists=false`
|
||||
- current entitlement is expiry-repaired lazily
|
||||
- active sanctions are filtered to the lobby-relevant set
|
||||
- effective limits combine default catalog values plus active overrides
|
||||
- markers are derived from sanctions, entitlement, and limits
|
||||
|
||||
## Geo -> User
|
||||
|
||||
`Geo Profile Service` synchronizes the latest approved effective declared
|
||||
country through:
|
||||
|
||||
- `POST /api/v1/internal/users/{user_id}/declared-country/sync`
|
||||
|
||||
Rules:
|
||||
|
||||
- input must be uppercase ISO 3166-1 alpha-2
|
||||
- syncing the stored value is a no-op
|
||||
- `User Service` stores only the current effective value
|
||||
- geo owns review workflow and history
|
||||
- successful updates publish `user.declared_country.changed`
|
||||
|
||||
## Admin Reads And Commands
|
||||
|
||||
Trusted admin callers use:
|
||||
|
||||
- exact reads by `user_id`, e-mail, and race name
|
||||
- deterministic filtered listing
|
||||
- explicit entitlement commands
|
||||
- explicit sanction commands
|
||||
- explicit limit commands
|
||||
|
||||
Listing rules:
|
||||
|
||||
- order by `created_at desc`, then `user_id desc`
|
||||
- combine filters with `AND`
|
||||
- `page_token` is opaque and filter-bound
|
||||
|
||||
## Domain Events
|
||||
|
||||
The shared auxiliary event stream contains post-commit state propagation for:
|
||||
|
||||
- `user.profile.changed`
|
||||
- `user.settings.changed`
|
||||
- `user.entitlement.changed`
|
||||
- `user.sanction.changed`
|
||||
- `user.limit.changed`
|
||||
- `user.declared_country.changed`
|
||||
|
||||
Operation vocabularies:
|
||||
|
||||
- profile and settings:
|
||||
- `initialized`
|
||||
- `updated`
|
||||
- entitlement:
|
||||
- `initialized`
|
||||
- `granted`
|
||||
- `extended`
|
||||
- `revoked`
|
||||
- `expired_repaired`
|
||||
- sanction:
|
||||
- `applied`
|
||||
- `removed`
|
||||
- limit:
|
||||
- `set`
|
||||
- `removed`
|
||||
Reference in New Issue
Block a user