# 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 the preferred-language candidate derived from public `Accept-Language`, falls back to `en` when needed, 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 `display_name`. Rules: - validate the submitted value through `pkg/util/string.go:ValidateTypeName` - an empty value is accepted and resets the stored display name - uniqueness is not enforced; multiple users may share the same value - `user_name` is immutable and cannot be updated through this operation - reject writes while `profile_update_block` is active - return the current aggregate on no-op updates ### 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`