docs: reorder & testing
This commit is contained in:
+50
-62
@@ -346,6 +346,12 @@ The current direct `Gateway -> User` self-service boundary uses that pattern:
|
||||
- `user.account.get`
|
||||
- `user.profile.update`
|
||||
- `user.settings.update`
|
||||
- `user.sessions.list`
|
||||
- `user.sessions.revoke`
|
||||
- `user.sessions.revoke_all`
|
||||
- `user.games.command`
|
||||
- `user.games.order`
|
||||
- `user.games.report`
|
||||
- external payloads and responses:
|
||||
- FlatBuffers
|
||||
- internal downstream transport:
|
||||
@@ -479,20 +485,25 @@ payload only: `user_id`, optional `device_session_id`, `event_type`,
|
||||
gateway derives `timestamp_ms`, recomputes `payload_hash`, signs the event,
|
||||
and only then forwards it to the matching `SubscribeEvents` streams.
|
||||
|
||||
Notification-owned user-facing payloads are expected to use
|
||||
`pkg/schema/fbs/notification.fbs`. The initial notification event vocabulary
|
||||
in v1 is exactly:
|
||||
Notification-owned user-facing payloads use
|
||||
`pkg/schema/fbs/notification.fbs`. Each catalog kind has a 1:1
|
||||
FlatBuffers table named with the camel-case form of the kind plus the
|
||||
`Event` suffix. The closed v1 vocabulary is exactly the 13 kinds
|
||||
defined in `backend/internal/notification/catalog.go`:
|
||||
|
||||
- `game.turn.ready`
|
||||
- `game.finished`
|
||||
- `lobby.invite.received`
|
||||
- `lobby.invite.revoked`
|
||||
- `lobby.application.submitted`
|
||||
- `lobby.membership.approved`
|
||||
- `lobby.membership.rejected`
|
||||
- `lobby.application.approved`
|
||||
- `lobby.application.rejected`
|
||||
- `lobby.membership.removed`
|
||||
- `lobby.membership.blocked`
|
||||
- `lobby.invite.created`
|
||||
- `lobby.invite.redeemed`
|
||||
- `lobby.race_name.registration_eligible`
|
||||
- `lobby.race_name.registered`
|
||||
- `lobby.race_name.pending`
|
||||
- `lobby.race_name.expired`
|
||||
- `runtime.image_pull_failed` (admin recipient)
|
||||
- `runtime.container_start_failed` (admin recipient)
|
||||
- `runtime.start_config_invalid` (admin recipient)
|
||||
|
||||
`lobby.application.submitted` is published toward `Gateway` only for the
|
||||
private-game owner flow. The public-game variant is email-only.
|
||||
@@ -589,68 +600,45 @@ Expected session fields available to the gateway:
|
||||
|
||||
### Session Cache
|
||||
|
||||
`SessionCache` provides the fast path for:
|
||||
`SessionCache` is the in-memory LRU + TTL store fronting every
|
||||
authenticated request. It serves the hot path for:
|
||||
|
||||
- session existence checks;
|
||||
- `device_session_id -> user_id`;
|
||||
- `device_session_id → user_id`;
|
||||
- access to the base64-encoded raw Ed25519 client public key used for
|
||||
signature verification;
|
||||
- revoked versus active status checks.
|
||||
- active vs revoked status checks.
|
||||
|
||||
Cache updates are event-driven.
|
||||
TTL is allowed only as a safety net and must not replace invalidation events.
|
||||
Implementation: a bounded LRU map (default 50 000 entries) wrapped by a
|
||||
safety-net TTL (default 10 minutes). On miss the cache calls
|
||||
`/api/v1/internal/sessions/{id}` against backend and seeds the entry.
|
||||
`session_invalidation` push frames flip the cached entry's status to
|
||||
`revoked` so subsequent authenticated requests are rejected at the edge
|
||||
without another backend round-trip. The TTL covers the case of a missed
|
||||
event (cursor aged out, gateway restart) by forcing a fresh backend
|
||||
lookup at most once per window.
|
||||
|
||||
The gateway keeps a process-local in-memory snapshot
|
||||
cache in front of the Redis fallback backend. Authenticated requests read the
|
||||
local snapshot first. A local miss performs one bounded Redis lookup and seeds
|
||||
the local snapshot so later requests for the same session avoid another Redis
|
||||
round-trip unless a later session event changes the cached state.
|
||||
The cache is process-local and unsynchronised across gateway instances.
|
||||
The MVP ships a single gateway instance (see
|
||||
`docs/ARCHITECTURE.md §18`); multi-instance scale-out is a later step
|
||||
that may revisit the topology.
|
||||
|
||||
The local snapshot cache intentionally has no TTL and no size-based
|
||||
eviction policy. Session lifecycle events are the authoritative mechanism for
|
||||
keeping the hot path current, while Redis fallback remains the safety net for
|
||||
cold misses and process restarts.
|
||||
Configuration:
|
||||
|
||||
The Redis fallback implementation uses `go-redis/v9`. `cmd/gateway` opens one
|
||||
shared `*redis.Client` via `pkg/redisconn` (instrumented with OpenTelemetry
|
||||
tracing and metrics), issues a single bounded `PING` on startup, and refuses
|
||||
to start when Redis is misconfigured or unavailable. The session cache,
|
||||
replay store, session-events subscriber, and client-events subscriber all
|
||||
use that shared client. See `docs/redis-config.md` for the rationale behind
|
||||
the shape and the project-wide rules in
|
||||
`ARCHITECTURE.md §Persistence Backends`.
|
||||
- `GATEWAY_SESSION_CACHE_MAX_ENTRIES` with default `50000`
|
||||
- `GATEWAY_SESSION_CACHE_TTL` with default `10m`
|
||||
|
||||
Required Redis connection variables:
|
||||
Redis is used by the gateway only for the authenticated Replay Store
|
||||
(see below). The shared client is opened via `pkg/redisconn` against
|
||||
`GATEWAY_REDIS_MASTER_ADDR` and `GATEWAY_REDIS_PASSWORD`; optional
|
||||
tuning lives under `GATEWAY_REDIS_REPLICA_ADDRS`, `GATEWAY_REDIS_DB`,
|
||||
and `GATEWAY_REDIS_OPERATION_TIMEOUT` (all documented in
|
||||
`docs/redis-config.md`).
|
||||
|
||||
- `GATEWAY_REDIS_MASTER_ADDR`
|
||||
- `GATEWAY_REDIS_PASSWORD`
|
||||
|
||||
Optional Redis connection variables:
|
||||
|
||||
- `GATEWAY_REDIS_REPLICA_ADDRS` (comma-separated; reserved for future
|
||||
read-routing — currently unused)
|
||||
- `GATEWAY_REDIS_DB` with default `0`
|
||||
- `GATEWAY_REDIS_OPERATION_TIMEOUT` with default `250ms`
|
||||
|
||||
> Removed: `GATEWAY_SESSION_CACHE_REDIS_ADDR`,
|
||||
> `GATEWAY_SESSION_CACHE_REDIS_USERNAME`,
|
||||
> `GATEWAY_SESSION_CACHE_REDIS_PASSWORD`,
|
||||
> `GATEWAY_SESSION_CACHE_REDIS_DB`,
|
||||
> `GATEWAY_SESSION_CACHE_REDIS_TLS_ENABLED`. `pkg/redisconn.LoadFromEnv`
|
||||
> rejects the deprecated `GATEWAY_REDIS_TLS_ENABLED` and
|
||||
> `GATEWAY_REDIS_USERNAME` variables at startup.
|
||||
|
||||
Per-subsystem Redis behavior variables (namespace, timeouts):
|
||||
|
||||
- `GATEWAY_REPLAY_REDIS_KEY_PREFIX` with default `gateway:replay:`
|
||||
- `GATEWAY_REPLAY_REDIS_RESERVE_TIMEOUT` with default `250ms`
|
||||
|
||||
Gateway no longer keeps a session cache projection or the two Redis
|
||||
Streams (`session_events`, `client_events`). Session lookup is a
|
||||
synchronous REST call to backend, and inbound client / session events
|
||||
arrive through the gRPC `Push.SubscribePush` consumer (see the
|
||||
**Backend Client** section below). Redis is therefore used only by
|
||||
the Replay Store.
|
||||
> Removed: the previous Redis-backed session-cache projection and its
|
||||
> environment variables (`GATEWAY_SESSION_CACHE_REDIS_*`,
|
||||
> `GATEWAY_REDIS_TLS_ENABLED`, `GATEWAY_REDIS_USERNAME`).
|
||||
> `pkg/redisconn.LoadFromEnv` rejects the deprecated names at startup.
|
||||
|
||||
### Backend Client
|
||||
|
||||
|
||||
Reference in New Issue
Block a user