Class TicketExpiryEventId

java.lang.Object
com.aim2be.platform.outbox.redis.TicketExpiryEventId

public final class TicketExpiryEventId extends Object
Deterministic TicketExpired event-id generator โ€” UUIDv3(namespace, ticket_id "|" expires_at_epoch_ms) (refinement #2 + ADR-0014 D-4 / 0014-supporting/identity-redis-outbox-backend.md).

TicketMinted/TicketRevoked use UUIDv7 (time-ordered, unique per logical event). TicketExpired is DIFFERENT: the due-time worker may fire the same expiry twice (worker crash + replay), so its event-id MUST be deterministic so the duplicate collapses โ€” the expiry-decide.lua HEXISTS guard + the consumer-side dedup both key off this id. A v3 (name-based, MD5) UUID over ticket_id|expires_at yields the SAME id for the SAME (ticket, expiry) pair, every time.

This is the platform-libs PRIMITIVE; the identity-service ticket-mint wiring that calls it is Phase 1. It is exercised here (Phase 0b) by the expiry-decision tests.

MD5 is used here ONLY as the UUIDv3 name-hashing function mandated by RFC 4122 ยง4.3 โ€” it is NOT a security primitive (rule 01 forbids MD5/SHA-1 for hashing/passwords; a name-based UUID is neither). The determinism is the whole point; a stronger digest would change the UUID version and break the contract.

  • Field Details

    • TICKET_EVENT_NAMESPACE

      public static final UUID TICKET_EVENT_NAMESPACE
      Fixed namespace UUID for aim2be ticket-lifecycle events. A constant namespace makes the v3 ids stable across processes + restarts. Generated once (random v4) and frozen here as the aim2be ticket-event namespace.
  • Method Details

    • forTicket

      public static UUID forTicket(UUID ticketId, Instant expiresAt)
      Computes the deterministic TicketExpired event id.
      Parameters:
      ticketId - the expiring ticket's id; never null
      expiresAt - the ticket's expiry instant (millisecond precision is the identity granularity); never null
      Returns:
      a stable UUIDv3 for this (ticket, expiry) pair