Files
galaxy-game/authsession/PLAN.md
T
2026-04-08 16:23:07 +02:00

30 KiB

Auth / Session Service Implementation Plan

This plan has been already implemented and stays here for historical reasons.

It should NOT be threated as source of truth for service functionality.

Purpose

This plan describes a detailed, incremental implementation path for Auth / Session Service that integrates with the existing Edge Gateway.

The plan is intentionally atomic. Each stage should be small enough to implement, review, and test without overloading development context.

Global Rules for the Entire Plan

  • keep domain logic independent from concrete storage backends;
  • keep gateway projection separate from source-of-truth records;
  • preserve the existing public auth contract expected by gateway:
    • send-email-code -> challenge_id
    • confirm-email-code -> device_session_id
  • keep confirm-email-code synchronous;
  • do not introduce a pending async session-provisioning model;
  • use synchronous internal REST where immediate answer is required;
  • use Redis Streams / pub-sub only for session lifecycle propagation and other event-style side effects;
  • keep implementation idempotent where retries are expected;
  • design Redis-backed stores behind interfaces so SQL migration remains possible.

Milestone Structure

Suggested milestones:

  1. Domain skeleton and ports
  2. In-memory service behavior and tests
  3. Redis-backed source-of-truth stores
  4. Gateway projection publisher
  5. Public HTTP API
  6. Internal trusted API
  7. Integration with user-service and config-provider ports
  8. Revoke/block flows
  9. Observability and hardening
  10. End-to-end integration with gateway

Suggested Module Structure

The structure described below is allowed to be changed during the Plan steps implementation.

authsession/
├── cmd/
│   └── authsession/
│       └── main.go
│
├── internal/
│   ├── app/
│   │   ├── app.go
│   │   ├── bootstrap.go
│   │   └── wiring.go
│   │
│   ├── config/
│   │   ├── config.go
│   │   ├── env.go
│   │   └── validation.go
│   │
│   ├── domain/
│   │   ├── challenge/
│   │   │   ├── model.go
│   │   │   ├── state.go
│   │   │   ├── policy.go
│   │   │   └── errors.go
│   │   │
│   │   ├── devicesession/
│   │   │   ├── model.go
│   │   │   ├── state.go
│   │   │   ├── revoke.go
│   │   │   └── errors.go
│   │   │
│   │   ├── userresolution/
│   │   │   ├── model.go
│   │   │   └── policy.go
│   │   │
│   │   ├── sessionlimit/
│   │   │   ├── model.go
│   │   │   └── policy.go
│   │   │
│   │   └── common/
│   │       ├── email.go
│   │       ├── time.go
│   │       ├── ids.go
│   │       └── types.go
│   │
│   ├── ports/
│   │   ├── challengestore.go
│   │   ├── sessionstore.go
│   │   ├── userdirectory.go
│   │   ├── configprovider.go
│   │   ├── mailsender.go
│   │   ├── projectionpublisher.go
│   │   ├── clock.go
│   │   ├── idgenerator.go
│   │   ├── codegenerator.go
│   │   └── codehasher.go
│   │
│   ├── service/
│   │   ├── sendemailcode/
│   │   │   └── service.go
│   │   ├── confirmemailcode/
│   │   │   └── service.go
│   │   ├── getsession/
│   │   │   └── service.go
│   │   ├── listusersessions/
│   │   │   └── service.go
│   │   ├── revokedevicesession/
│   │   │   └── service.go
│   │   ├── revokeallusersessions/
│   │   │   └── service.go
│   │   ├── blockuser/
│   │   │   └── service.go
│   │   └── shared/
│   │       ├── normalize.go
│   │       ├── projection.go
│   │       └── publicerrors.go
│   │
│   ├── api/
│   │   ├── publichttp/
│   │   │   ├── handler_send_email_code.go
│   │   │   ├── handler_confirm_email_code.go
│   │   │   ├── dto.go
│   │   │   └── errors.go
│   │   │
│   │   └── internalhttp/
│   │       ├── handler_get_session.go
│   │       ├── handler_list_user_sessions.go
│   │       ├── handler_revoke_device_session.go
│   │       ├── handler_revoke_all_user_sessions.go
│   │       ├── handler_block_user.go
│   │       ├── dto.go
│   │       └── errors.go
│   │
│   ├── adapters/
│   │   ├── redis/
│   │   │   ├── challengestore/
│   │   │   │   └── store.go
│   │   │   ├── sessionstore/
│   │   │   │   └── store.go
│   │   │   ├── configprovider/
│   │   │   │   └── provider.go
│   │   │   └── gatewayprojection/
│   │   │       ├── publisher.go
│   │   │       ├── snapshot.go
│   │   │       └── stream.go
│   │   │
│   │   ├── userservice/
│   │   │   ├── client.go
│   │   │   ├── mapper.go
│   │   │   └── stub.go
│   │   │
│   │   ├── mail/
│   │   │   ├── stub.go
│   │   │   └── rest_client.go
│   │   │
│   │   ├── crypto/
│   │   │   ├── codehasher.go
│   │   │   └── publickey.go
│   │   │
│   │   ├── clock/
│   │   │   └── system.go
│   │   │
│   │   └── id/
│   │       ├── challengeid.go
│   │       └── devicesessionid.go
│   │
│   ├── observability/
│   │   ├── logging.go
│   │   ├── metrics.go
│   │   └── tracing.go
│   │
│   └── testkit/
│       ├── fixtures.go
│       ├── fake_clock.go
│       ├── fake_idgen.go
│       ├── fake_mail.go
│       ├── fake_userdir.go
│       └── fake_projection.go
│
├── api/
│   ├── public-openapi.yaml
│   └── internal-openapi.yaml
│
└── README.md

Description

  • cmd/authsession — service entry point: process startup, configuration loading, application assembly, and HTTP server startup.

  • internal/app — top-level application orchestration layer: dependency initialization, runtime bootstrap, and component wiring.

  • internal/config — service configuration loading, normalization, and validation from environment and other sources.

  • internal/domain/challenge — domain model for the send_email_code / confirm_email_code challenge flow: states, transitions, TTL/retry policies, and domain errors.

  • internal/domain/devicesession — domain model for device_session: session state, revocation, revoke reasons, and related domain errors.

  • internal/domain/userresolution — domain model for user resolution by email through user-service: existing user, allowed registration, or blocked user.

  • internal/domain/sessionlimit — domain model and policy rules for active device_session limits.

  • internal/domain/common — shared domain value objects and helper types: email, time, identifiers, and common primitive types.

  • internal/ports — interfaces for all external dependencies: source-of-truth stores, user-service, mail delivery, config, projection publisher, clock, generators, and hashing.

  • internal/service/sendemailcode — use case for sending a code: email normalization, challenge lifecycle, suppression/send decision, and success-shaped public response.

  • internal/service/confirmemailcode — use case for confirming a code: challenge validation, public-key validation, resolve/create user flow, session-limit enforcement, device_session creation, and projection publication.

  • internal/service/getsession — use case for reading a single device_session for the trusted internal API.

  • internal/service/listusersessions — use case for listing user sessions for the trusted internal API.

  • internal/service/revokedevicesession — use case for revoking a single device session and publishing the updated gateway projection.

  • internal/service/revokeallusersessions — use case for revoking all active sessions of a user and publishing the resulting updates.

  • internal/service/blockuser — use case for blocking a user/email and revoking active sessions according to policy.

  • internal/service/shared — shared application-layer code: normalization helpers, gateway projection builders, and public error mapping.

  • internal/api/publichttp — public HTTP API for gateway integration: handlers, DTOs, and error mapping for send_email_code and confirm_email_code.

  • internal/api/internalhttp — trusted internal HTTP API: revoke/read/list/block endpoints, DTOs, and separate internal error policy.

  • internal/adapters/redis/challengestore — Redis adapter for source-of-truth challenge storage.

  • internal/adapters/redis/sessionstore — Redis adapter for source-of-truth device_session storage.

  • internal/adapters/redis/configprovider — Redis adapter for dynamic configuration, such as active-session limits.

  • internal/adapters/redis/gatewayprojection — Redis adapter for the Edge Gateway integration projection: KV snapshots and lifecycle updates in streams.

  • internal/adapters/userservice — user-service integration adapter: REST client, response-to-domain mapping, and stub implementation for early stages.

  • internal/adapters/mail — mail-delivery adapter: development stub and future REST mail-service client.

  • internal/adapters/crypto — cryptographic adapters: confirmation-code hashing and client_public_key validation/parsing.

  • internal/adapters/clock — system clock implementation.

  • internal/adapters/id — generation of stable domain identifiers such as challenge_id and device_session_id.

  • internal/observability — service logging, metrics, and tracing.

  • internal/testkit — test fixtures, fake/mock dependencies, and shared helpers for unit and integration tests.

  • api/public-openapi.yaml — formal specification of the public HTTP API.

  • api/internal-openapi.yaml — formal specification of the trusted internal HTTP API.

  • README.md — architectural service description covering its role in the system, contracts, domain rules, and integrations.


Stage 1. Freeze the Service Contract

Status: implemented.

Goal

Write down the exact service-level contracts before implementation starts.

Tasks

  • freeze public auth use cases:
    • send_email_code
    • confirm_email_code
  • freeze internal trusted use cases:
    • GetSession
    • ListUserSessions
    • RevokeDeviceSession
    • RevokeAllUserSessions
    • BlockUser
  • define canonical request/response DTOs for the service boundary;
  • define client-safe error classes for the public auth API;
  • define richer internal error classes for logs and internal API.

Deliverables

  • service contract notes in repo docs;
  • initial error catalog;
  • agreement on public vs internal API boundaries.

Exit Criteria

  • no unresolved ambiguity around public auth input/output shapes;
  • no unresolved ambiguity around internal revoke/read operations.

Stage 2. Define Core Domain Types

Status: implemented.

Goal

Create the minimal domain model without any transport or storage code.

Tasks

  • define challenge aggregate concept;
  • define device-session aggregate concept;
  • define revoke reason model;
  • define user resolution result model:
    • existing user
    • creatable user
    • blocked user
  • define session-limit decision model;
  • define mail-delivery result model;
  • define projection snapshot model for gateway integration;
  • define domain statuses and allowed transitions.

Important Constraints

  • challenge and session models must not depend on Redis-specific encoding;
  • gateway projection model must be separate from domain entities.

Deliverables

  • domain package with types only;
  • transition invariants documented in code comments and tests.

Exit Criteria

  • domain package compiles without storage adapters;
  • status transitions are covered by unit tests.

Stage 3. Define Service Ports

Status: implemented.

Goal

Create clean interfaces around every external dependency.

Tasks

Define interfaces conceptually equivalent to:

  • ChallengeStore
  • SessionStore
  • UserDirectory / UserResolver
  • ConfigProvider
  • MailSender
  • GatewaySessionProjectionPublisher
  • Clock
  • IDGenerator
  • CodeGenerator
  • CodeHasher

Notes

  • ChallengeStore and SessionStore are source-of-truth ports;
  • GatewaySessionProjectionPublisher is an integration port, not a domain store;
  • UserDirectory must support existing / creatable / blocked decisions and user creation when allowed;
  • ConfigProvider must support "limit absent" as a first-class case.

Deliverables

  • interface package or packages;
  • port-level test doubles.

Exit Criteria

  • service layer can be implemented against interfaces only.

Stage 4. Implement Pure Domain Services In Memory

Status: implemented.

Goal

Implement the auth logic once, against in-memory stores and adapters.

Tasks

Implement core use cases:

  • SendEmailCode
  • ConfirmEmailCode
  • GetSession
  • ListUserSessions
  • RevokeDeviceSession
  • RevokeAllUserSessions
  • BlockUser

Required Behaviors

SendEmailCode

  • normalize email;
  • consult UserDirectory policy if needed;
  • create challenge;
  • generate secure code;
  • store only hashed code;
  • attempt delivery or suppress it;
  • always return a success-shaped result with challenge_id.

ConfirmEmailCode

  • load challenge;
  • validate expiration and status;
  • validate code hash;
  • validate client_public_key format;
  • handle idempotent repeat confirm for same successful challenge and same key;
  • resolve/create user through UserDirectory;
  • reject blocked user;
  • load session-limit config;
  • count active sessions;
  • reject if limit exceeded;
  • create session;
  • store session;
  • move challenge into short-window confirmed state;
  • publish session projection;
  • return device_session_id.

Revoke Flows

  • update source of truth;
  • publish revoked projection for every affected session.

Deliverables

  • service layer with in-memory dependencies;
  • unit tests for every public behavior.

Exit Criteria

  • full service logic is testable without Redis or HTTP;
  • edge cases are covered by unit tests.

Stage 5. Design Challenge Rules in Detail

Status: implemented.

Goal

Remove ambiguity from challenge handling before persistent adapters are written.

Tasks

  • define challenge TTL;
  • define max confirm attempts;
  • define resend behavior policy, if any;
  • define short idempotency window after successful confirm;
  • define state machine for:
    • new challenge
    • sent/suppressed
    • confirmed
    • expired
    • failed
  • define exact behavior for repeated confirms:
    • same code + same key -> same session id
    • same code + different key -> fail
    • expired challenge -> fail
    • too many attempts -> fail

Deliverables

  • explicit challenge policy spec in code comments/tests.

Exit Criteria

  • no hidden challenge behavior remains undecided.

Stage 6. Define Public Error Policy

Status: implemented.

Goal

Make public auth failures predictable and safe.

Tasks

Decide exact client-safe categories for:

  • malformed e-mail;
  • malformed client_public_key;
  • unknown challenge;
  • expired challenge;
  • invalid code;
  • blocked by policy at confirm stage;
  • session limit exceeded;
  • temporarily unavailable.

Additional Rules

  • send_email_code must not reveal whether the e-mail exists or is blocked;
  • public errors should be normalized for gateway passthrough;
  • internal logs and traces may keep richer reasons.

Deliverables

  • public error mapping table;
  • internal error hierarchy.

Exit Criteria

  • gateway adapter behavior can be implemented without guesswork.

Stage 7. Implement Redis ChallengeStore

Status: implemented.

Goal

Add the first persistent backend for challenges.

Tasks

  • implement challenge read/write/update operations in Redis KV;
  • define Redis key scheme for challenges;
  • store hashed codes only;
  • store challenge status and timestamps;
  • support atomic compare-and-set style updates where required;
  • support expiration cleanup through TTL and/or explicit status.

Important Design Rule

The interface must not expose Redis primitives directly.

Deliverables

  • Redis-backed challenge store adapter;
  • adapter integration tests against Redis.

Exit Criteria

  • challenge lifecycle works against Redis under concurrent access assumptions.

Stage 8. Implement Redis SessionStore

Status: implemented.

Goal

Add the first persistent backend for sessions.

Tasks

  • implement create/read/list/revoke operations;
  • define Redis key scheme for sessions;
  • support listing all sessions for one user;
  • support revoking one session;
  • support revoking all sessions for one user;
  • support block-related session revocation;
  • support active-session counting for limit enforcement;
  • store revoke reason and actor metadata.

Important Design Rule

The session source-of-truth record must remain distinct from gateway projection encoding.

Deliverables

  • Redis-backed session store adapter;
  • adapter integration tests.

Exit Criteria

  • all session lifecycle operations are persistent and testable.

Stage 9. Implement Redis ConfigProvider

Status: implemented.

Goal

Support dynamic session-limit configuration.

Tasks

  • implement config lookup from Redis KV;
  • define config key scheme for auth-service settings;
  • support:
    • limit present with integer value
    • limit absent
    • invalid config value
  • define fallback behavior for invalid config read.

Required Behavior

  • missing config -> no session-count limit;
  • invalid config -> fail closed or fail safe according to explicit decision;
  • document the chosen policy.

Deliverables

  • Redis-backed config adapter;
  • tests for absent, valid, and invalid values.

Exit Criteria

  • session-limit logic no longer depends on hard-coded constants.

Stage 10. Implement Gateway Session Projection Publisher

Status: implemented.

Goal

Bridge auth source-of-truth state into gateway-facing cache/projection state.

Tasks

  • define exact projection snapshot structure consumed by gateway;
  • define Redis KV key scheme for gateway session lookup;
  • define Redis Stream schema for session lifecycle updates;
  • implement projection write on session create;
  • implement projection update on session revoke;
  • implement projection update for bulk revoke/all;
  • make publication idempotent and retry-safe.

Important Constraints

  • projection publisher should accept domain session data and transform it;
  • it must not force domain logic to know Redis snapshot shape.

Deliverables

  • Redis-backed projection publisher;
  • integration tests that emulate gateway expectations.

Exit Criteria

  • created sessions appear in gateway-readable projection;
  • revoked sessions produce gateway-readable invalidation/update records.

Stage 11. Implement Stub MailSender

Status: implemented.

Goal

Introduce the mail-delivery port without coupling auth logic to one concrete delivery transport.

Tasks

  • create a stub adapter with deterministic success/failure modes;
  • record delivery attempts for tests;
  • support explicit suppression mode for blocked/hidden flows;
  • ensure service logic can distinguish:
    • sent
    • suppressed
    • failed

Deliverables

  • stub mail adapter;
  • tests around challenge delivery state transitions.

Exit Criteria

  • auth logic is fully testable without real mail infrastructure.

Stage 12. Implement Stub UserDirectory

Status: implemented.

Goal

Introduce the user-service dependency before its real service exists.

Tasks

  • create an in-memory or stub REST-like adapter that can return:
    • existing user
    • creatable user
    • blocked user
  • support create-on-confirm behavior;
  • support lookups by normalized email;
  • support user block state.

Deliverables

  • stub user-service adapter;
  • integration tests for auth flows.

Exit Criteria

  • auth-service no longer needs to fake user decisions internally.

Stage 13. Implement Public HTTP API

Status: implemented.

Goal

Expose the synchronous public auth flow expected by gateway.

Tasks

  • create HTTP handlers for:
    • send_email_code
    • confirm_email_code
  • define JSON DTOs matching gateway expectations;
  • implement request validation;
  • implement response normalization;
  • implement mapping from internal errors to public client-safe errors;
  • add request timeout handling and structured logging.

Important Constraints

  • keep semantics aligned with gateway adapter expectations;
  • do not expose internal admin/session methods on the public listener.

Deliverables

  • public HTTP server;
  • handler tests;
  • end-to-end tests through HTTP.

Exit Criteria

  • gateway can call the service through a real HTTP adapter.

Stage 14. Implement Internal Trusted API

Status: implemented.

Goal

Expose lifecycle and read operations for trusted internal callers.

Tasks

Implement internal endpoints for:

  • GetSession
  • ListUserSessions
  • RevokeDeviceSession
  • RevokeAllUserSessions
  • BlockUser

Optional additions later:

  • unblock flow;
  • challenge inspection.

Notes

  • this may use REST for simplicity;
  • authentication/authorization of internal callers can be stubbed initially if there is not yet a platform-wide internal auth mechanism.

Deliverables

  • internal HTTP API;
  • handler tests.

Exit Criteria

  • session lifecycle can be driven without touching Redis manually.

Stage 15. Implement Revoke Logic Thoroughly

Status: implemented.

Goal

Make revoke behavior explicit and reliable.

Tasks

For RevokeDeviceSession:

  • load target session;
  • no-op or explicit result if already revoked;
  • persist revoke metadata;
  • publish revoked projection.

For RevokeAllUserSessions:

  • list active sessions for user;
  • revoke each relevant session;
  • publish projection for each affected session;
  • preserve reason metadata.

For BlockUser:

  • mark user blocked through UserDirectory or trusted policy adapter;
  • revoke all active sessions;
  • ensure future auth flow is denied at confirm stage and mail can be suppressed at send stage.

Deliverables

  • complete revoke implementation;
  • tests for single, bulk, and block flows.

Exit Criteria

  • gateway-facing revoke propagation is available for all revoke models.

Stage 16. Add Consistency Safeguards

Status: implemented.

Goal

Reduce create/revoke drift between source of truth and gateway projection.

Tasks

  • identify all places where source-of-truth write and projection publish happen;
  • add retry strategy for projection writes;
  • make projection publication idempotent;
  • define recovery behavior if projection publish fails after source-of-truth success;
  • add dead-letter or repair strategy placeholder if needed later;
  • document the consistency model.

Preferred Short-Term Outcome

  • source-of-truth success is never reported as auth success unless projection write/publish reached the required success threshold, or the failure handling policy is explicit and tested.

Deliverables

  • consistency policy document;
  • tests for partial failure scenarios.

Exit Criteria

  • known failure windows are explicit and bounded.

Stage 17. Add Public Anti-Abuse Hooks

Status: implemented.

Goal

Prepare the auth service for safe interaction behind gateway public routing.

Tasks

  • add service-level hooks for challenge resend throttling;
  • add max-attempt handling per challenge;
  • add metrics for suppressed/blocked/sent flows;
  • preserve soft anti-enumeration outward behavior.

Notes

Gateway already applies public-edge rate limits. This stage is about auth-specific flow protection, not replacing gateway limits.

Deliverables

  • abuse-control policy inside auth domain;
  • tests for throttling and attempt exhaustion.

Exit Criteria

  • auth flow cannot be trivially abused through repeated confirm attempts.

Stage 18. Add Observability

Status: implemented.

Goal

Make the service operable from the beginning.

Tasks

  • structured logs for all major state transitions;
  • metrics for all major operations;
  • tracing spans for public auth flow and internal API;
  • redact secrets and codes from logs;
  • include stable identifiers such as challenge id, device session id, user id, and reason codes where safe.

Minimum Metrics

  • challenges created;
  • deliveries sent/suppressed/failed;
  • confirm attempts;
  • confirm successes/failures;
  • sessions created;
  • session limit rejections;
  • sessions revoked by reason;
  • projection publish failures;
  • user-resolution outcomes.

Deliverables

  • metrics endpoint wiring if needed;
  • logging/tracing middleware;
  • observability tests where practical.

Exit Criteria

  • production debugging is possible without adding ad hoc logs later.

Stage 19. Add Gateway-Compatibility Tests

Status: implemented.

Goal

Test auth-service not just in isolation, but against gateway expectations.

Tasks

  • verify public auth HTTP DTO compatibility;
  • verify confirm-email-code returns ready device_session_id;
  • verify created session projection is readable by a gateway-compatible reader;
  • verify revoked projection invalidates session;
  • verify repeated confirm returns same session id in idempotency window;
  • verify blocked e-mail still keeps send_email_code outwardly success-shaped;
  • verify session limit exceeded returns stable client-visible error;
  • verify malformed client_public_key is rejected.

Deliverables

  • integration test suite focused on gateway contract.

Exit Criteria

  • no ambiguity remains about integration with existing gateway behavior.

Stage 20. Add Real REST Adapter to User Service Contract

Status: implemented.

Goal

Prepare for future extraction of User Service.

Tasks

  • define internal REST client for user resolution/create/block operations;
  • keep stub implementation for tests;
  • add timeout, retry, and error mapping policy;
  • define normalized email rules at the boundary.

Deliverables

  • REST client adapter for future user-service;
  • compatibility tests using stub server.

Exit Criteria

  • auth-service can later switch from stub to real user-service with no domain rewrite.

Stage 21. Add Real Mail Adapter Contract

Status: implemented.

Goal

Prepare for later internal mail-service-backed delivery.

Tasks

  • define mail adapter request/response contract;
  • preserve current stub for tests;
  • define delivery timeout and error mapping;
  • define how suppression vs explicit failure is represented.

Deliverables

  • mail adapter interface finalized;
  • optional HTTP client adapter skeleton.

Exit Criteria

  • auth flow is decoupled from the future mail implementation.

Stage 22. Production Hardening Pass

Status: implemented.

Goal

Review edge cases before calling the service implementation complete.

Tasks

  • test Redis reconnect behavior;
  • test duplicate publish behavior;
  • test crash/restart around confirm and revoke flows;
  • test large numbers of active sessions per user;
  • test concurrent confirms against the same challenge;
  • test concurrent revoke and confirm races;
  • test block-user during active auth flow;
  • test expired challenge cleanup strategy.

Deliverables

  • hardening checklist;
  • race-condition tests;
  • operational notes.

Exit Criteria

  • no major known race remains undocumented.

Stage 23. Optional Cleanup and Migration Readiness

Status: implemented.

Goal

Make future SQL migration realistic.

Tasks

  • review whether domain services leak Redis assumptions;
  • ensure all store interfaces are storage-agnostic;
  • isolate key naming, stream naming, and projection serialization;
  • add adapter contract tests reusable by future SQL backends.

Deliverables

  • backend-agnostic adapter tests;
  • migration readiness notes.

Exit Criteria

  • a future SQL backend can be added without reworking service-layer logic.

If implementation needs an aggressively small first milestone, do this subset first:

  1. domain types
  2. service ports
  3. in-memory service logic
  4. stub UserDirectory
  5. stub MailSender
  6. public HTTP API
  7. Redis SessionStore
  8. Redis ChallengeStore
  9. Redis projection publisher
  10. gateway-compatibility tests for:
  • send-email-code
  • confirm-email-code
  • session projection after confirm

This gives an end-to-end happy path quickly, without waiting for revoke/admin and full hardening.

  1. internal trusted API
  2. session-limit config provider
  3. revoke-device
  4. revoke-all
  5. block-user
  6. observability
  7. consistency safeguards
  8. hardening tests

Final Acceptance Criteria

The service can be considered implementation-ready when all of the following are true:

  • gateway can call public auth routes synchronously;
  • confirm-email-code returns a ready device_session_id;
  • the created session appears in gateway-compatible projection storage;
  • revoked sessions publish gateway-compatible revoke updates;
  • repeated successful confirm returns the same session id during the short idempotency window;
  • session creation respects dynamic limit config;
  • user block prevents future auth flow and can revoke active sessions;
  • all storage is hidden behind interfaces;
  • auth-service is not required on the authenticated command hot path;
  • logs, metrics, and tests cover the full lifecycle.

Implementation Order Summary

flowchart TD
    A["Freeze contracts"]
    B["Domain model"]
    C["Ports"]
    D["In-memory service logic"]
    E["Redis stores"]
    F["Projection publisher"]
    G["Public HTTP API"]
    H["Internal trusted API"]
    I["Revoke and block flows"]
    J["Observability and hardening"]
    K["Gateway compatibility tests"]

    A --> B --> C --> D --> E --> F --> G --> H --> I --> J --> K