
````markdown
# ADR003 – Aggregate Identifier Strategy

- **Status:** Proposed
- **Date:** 2026-07-26
- **Decision Owners:** LA, ED, PL
- **Scope:** Domain and Persistence Model
- **Related:** ADR002 – Source Delivery Model

---

# 1. Context

Reconcilix currently uses different identifier strategies for persisted domain objects.

Existing tables predominantly use database-generated numeric identifiers:

```text
BIGINT AUTO_INCREMENT
````

The newly introduced `SourceDelivery` aggregate uses an application-generated UUID represented as:

```text
VARCHAR(36)
```

This creates an inconsistent identifier model across aggregates and persistence mappings.

Reconcilix is evolving from a simple reconciliation application into an integration and provenance platform. Aggregate roots may be created before persistence and may later be processed through batch jobs, queues, APIs, or parallel workflows.

Database-generated identifiers introduce an unnecessary dependency between aggregate creation and relational persistence.

---

# 2. Decision

Reconcilix will use application-generated UUIDs as identifiers for all aggregate roots.

The canonical database representation is:

```sql
VARCHAR(36)
```

UUID values use the standard textual representation:

```text
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
```

Identifiers are generated in the application layer or domain model before persistence.

`AUTO_INCREMENT` identifiers will no longer be introduced for aggregate roots.

Foreign keys referencing aggregate roots use the same identifier type.

---

# 3. Initial Scope

The following aggregate roots are expected to use UUID identifiers:

* SourceDelivery
* SourceValue
* ReconciliationResult

Further aggregate roots must follow the same strategy when introduced or reviewed.

Internal entities that are not aggregate roots may continue to use numeric identifiers where this is technically appropriate and do not expose the identifier outside their aggregate boundary.

---

# 4. Rationale

UUID identifiers provide:

* persistence-independent aggregate creation
* consistent identifiers across APIs, queues, imports and databases
* safer parallel and distributed processing
* reduced coupling to relational database features
* deterministic creation of complete object graphs before persistence
* a uniform identifier strategy across Reconcilix aggregates

The decision is made early in the project lifecycle to avoid a later migration of large productive datasets and foreign-key relationships.

---

# 5. Consequences

## Positive

* Consistent aggregate identity model.
* No dependency on `AUTO_INCREMENT`.
* Aggregate IDs are available before persistence.
* Easier integration with external processing pipelines.
* Lower risk of identifier collisions across environments.

## Negative

* UUID indexes require more storage than numeric indexes.
* Existing numeric IDs and foreign keys must be changed.
* Mappers, repositories, migrations and tests require coordinated updates.
* UUID values are less convenient for manual database inspection.

---

# 6. Implementation Constraints

* UUID generation must be centralized through domain-specific identifier value objects.
* Raw UUID strings must not be generated directly in controllers or repositories.
* Each identifier value object must validate its UUID format.
* Database columns and corresponding foreign keys must use compatible types and collations.
* Existing public or integration-facing identifiers must not silently change without review.
* Schema changes must be delivered through explicit migrations.

---

# 7. Migration Strategy

Because Reconcilix is not yet operating with significant productive data, the identifier change should be implemented before further persistence features are added.

Preferred sequence:

1. Inventory all aggregate roots and foreign-key references.
2. Update identifier value objects.
3. Update database migrations.
4. Update mappers and repositories.
5. Update domain and integration tests.
6. Recreate or migrate local development databases.
7. Verify OpenRefine and end-to-end persistence workflows.

Where no relevant productive data exists, rebuilding the affected tables is preferred over maintaining a complex compatibility migration.

---

# 8. Alternatives Considered

## A. Continue using BIGINT AUTO_INCREMENT

Rejected because aggregate creation would remain coupled to relational persistence and the identifier strategy would remain inconsistent.

## B. Use UUID only for SourceDelivery

Rejected because this would preserve two competing identifier strategies without a clear architectural reason.

## C. Use binary UUID storage

Deferred.

Binary storage would reduce index size but would increase implementation and operational complexity. The textual `VARCHAR(36)` representation is preferred initially for transparency and maintainability.

---

# 9. Open Questions

* Which existing domain objects are aggregate roots and therefore require UUID identifiers?
* Should UUID version 4 or UUID version 7 become the canonical generation strategy?
* Should internal non-aggregate entities retain numeric identifiers?
* Is a dedicated UUID library required, or is the existing project implementation sufficient?

```

---

Ich glaube sogar, wir sollten **LA noch einmal drüberschauen lassen**. Das ADR ist inhaltlich gut, aber ich sehe schon zwei, drei Stellen, die ich architektonisch noch etwas schärfer formulieren würde (z.B. den Geltungsbereich "Aggregate Roots" vs. "alle Domain Objects"). Ich vermute, daraus wird noch eine Version **v1.1**, bevor wir es als `FINAL` ablegen.
```
