<?xml version="1.0" encoding="UTF-8"?>
<!--
  redis-outbox-backend — Redis Lua-EVAL implementation of the OutboxBackend SPI.

  Wave A.2 Phase 0b per .planning/32-wave-a2-redis-outbox-design.md +
  docs/decisions/0014-supporting/identity-redis-outbox-backend.md. The single
  store that keeps identity-service's ticket MINT and its outbox event atomic:
  the mint is a Redis op, so the outbox row must live in Redis too (a PG outbox
  would reintroduce the dual-write gap). All co-touched keys are hash-tagged
  {prefix} so a single EVAL stays single-slot (cluster-safe by construction).

  Public API:
    - RedisOutboxBackend           (OutboxBackend impl, requiresActiveTransaction=false)
    - RedisOutboxPollerWorker      (cold sweep — lock+renewal+token CAD, batch<TTL)
    - RedisOutboxRelay             (inline hot relay — owns its own relay; the PG
                                    OutboxPublisher AFTER_COMMIT path is unusable
                                    for a transaction-free backend)
    - RedisDurabilityValidator     (AOF + appendfsync + noeviction guard, §7)
    - RedisOutboxRetentionWorker   (SENT HDEL retention, §9)
    - RedisOutboxRepairWorker      (zset/hash reconciliation, §10)
    - RedisOutboxProperties        (im2be.outbox.redis.* config)
    - RedisOutboxAutoConfiguration (autoconfig — @ConditionalOnProperty backend=REDIS)

  Consumers enable via:
    im2be.outbox.enabled=true
    im2be.outbox.backend=REDIS         (EXPLICIT — Redis-on-classpath must NOT
                                        auto-select; PG stays the default, §11)

  This module depends on outbox-publisher (OutboxBackend SPI + OutboxRecord +
  OutboxMetricsBinder) + spring-boot-starter-data-redis. It deliberately does
  NOT pull spring-data-jpa, so a Redis-only consumer (identity-service) never
  wires JPA.

  Cross-refs:
    - ADR-0014 D-3  (Redis Lua-EVAL Hash backend decision)
    - ADR-0002 §3b  (ticket-lifecycle events — security-audit pipeline)
    - .planning/32-wave-a2-redis-outbox-design.md (the 12 refinements)
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.aim2be</groupId>
        <artifactId>im2be-platform-libs-parent</artifactId>
        <version>1.1.0-SNAPSHOT</version>
    </parent>

    <artifactId>redis-outbox-backend</artifactId>
    <packaging>jar</packaging>
    <name>im2be-platform-libs :: redis-outbox-backend</name>
    <description>Redis Lua-EVAL implementation of the OutboxBackend SPI (ADR-0014 D-3, Wave A.2 Phase 0b).</description>

    <dependencies>
        <!-- The SPI + OutboxRecord + OutboxMetricsBinder this module implements.
             Brings spring-kafka (provided→compile here, see below), resilience4j,
             OTel-api, micrometer transitively at their declared scopes. -->
        <dependency>
            <groupId>com.aim2be</groupId>
            <artifactId>outbox-publisher</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!-- Redis (Lettuce) — the store. RedisTemplate + Lua EVAL execution. -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>

        <!-- JSON entry (de)serialisation for the Hash field values. Jackson is
             already on the Spring Boot classpath via the BOM; declared
             explicitly per rule 9 so the dependency is visible, not implicit. -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

        <!-- JSR-303 validation for RedisOutboxProperties (fail-fast on
             out-of-range tunables at binding time). -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

        <!-- spring-kafka is declared `provided` in outbox-publisher, so its
             API does NOT transit to this module at compile scope. The Redis
             relay/poller call KafkaTemplate directly, so re-declare it here.
             Provided (not compile): the consuming service brings the runtime
             impl, exactly as outbox-publisher does. -->
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- Resilience4j — re-declared because outbox-publisher exposes it at
             compile scope already, but the breaker around the Redis hot relay
             is constructed here. (Transitive from outbox-publisher; explicit
             per rule 9.) -->
        <dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-circuitbreaker</artifactId>
            <version>${resilience4j.version}</version>
        </dependency>

        <!-- Micrometer (provided — consumer brings the runtime registry). -->
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-core</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- OpenTelemetry API (provided — consumer wires its own SDK). -->
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-api</artifactId>
            <version>${opentelemetry.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>${testcontainers.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- micrometer-core + opentelemetry-api are already declared `provided`
             above; `provided` scope is visible on the test classpath too, so we
             do NOT re-declare them at test scope (a duplicate declaration makes
             Maven merge to one scope non-deterministically — caught in build). -->
    </dependencies>

    <build>
        <plugins>
            <!-- Failsafe wires the *IT.java integration tests so `mvn verify`
                 triggers the Testcontainers Valkey run. -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
