# ED-04-003 – SourceDelivery Repository

**Status:** Final

**Related**

- ED-04_SourceDelivery_Aggregate.md
- ED-04-001_SourceDelivery_Domain_Object.md
- ED-04-002_SourceDelivery_Persistence.md
- ADR002_SOURCE_DELIVERY_MODEL_V4.md
- DM001_Domain_Model_v0.7_FINAL.md
- DM002_Persistence_Model_v0.6_FINAL.md

---

# 1. Ziel

Dieses Work Package implementiert das Repository für das `SourceDelivery`-Aggregate.

Das Repository stellt die fachliche Zugriffsschicht für `SourceDelivery` bereit und kapselt sämtliche Persistenzdetails.

---

# 2. Scope

Implementiert werden

- das Repository Interface,
- die relationale Repository-Implementierung,
- das Speichern,
- das Laden,
- sowie das Auffinden einer `SourceDelivery`.

Nicht Bestandteil sind

- SQL-Migrationen,
- Data Mapper,
- Application Service,
- Integrationstests.

---

# 3. Verantwortung

Das Repository ist verantwortlich für

- das Speichern neuer Aggregate,
- das Laden bestehender Aggregate,
- die Rehydration gespeicherter Aggregate,
- die Kapselung sämtlicher Persistenzdetails.

Nicht verantwortlich ist das Repository für

- Statusübergänge,
- Validierung,
- Geschäftslogik,
- Erzeugung neuer Aggregate.

---

# 4. Repository Interface

Mindestens folgende Operationen werden bereitgestellt.

```php
interface SourceDeliveryRepository
{
    public function save(SourceDelivery $delivery): void;

    public function findById(
        SourceDeliveryId $id
    ): ?SourceDelivery;

    public function findByExternalDeliveryId(
        TenantId $tenantId,
        string $externalDeliveryId
    ): ?SourceDelivery;
}
```

Weitere Suchoperationen werden erst implementiert, wenn hierfür ein fachlicher Bedarf besteht.

---

# 5. Save

```php
save(SourceDelivery)
```

speichert

- neue Aggregate,
- sowie Änderungen bestehender Aggregate.

Ob intern ein INSERT oder UPDATE erfolgt, ist eine Implementierungsentscheidung der Repository-Implementierung.

---

# 6. FindById

```php
findById(...)
```

lädt genau eine `SourceDelivery`.

Existiert kein Aggregate, wird

```php
null
```

zurückgegeben.

---

# 7. FindByExternalDeliveryId

Für OpenRefine und spätere Batch-Importe wird zusätzlich folgende Suche bereitgestellt:

```php
findByExternalDeliveryId(
    TenantId,
    externalDeliveryId
)
```

Die Suche dient

- Debugging,
- Support,
- Wiederaufnahme von Importen,
- späteren Replay-Szenarien.

Da `externalDeliveryId` derzeit nicht eindeutig ist, liefert die Methode höchstens eine fachlich passende Lieferung oder `null`.

Eine Erweiterung auf mehrere Treffer bleibt zukünftigen Work Packages vorbehalten.

---

# 8. Rehydration

Das Repository erzeugt beim Laden keine neuen Aggregate.

Stattdessen erfolgt die vollständige Rehydration der persistierten `SourceDelivery`.

Dabei bleiben

- id,
- tenantId,
- sourceSystemId,
- deliveryChannel,
- status,
- externalDeliveryId,
- receivedAt,
- completedAt

unverändert erhalten.

---

# 9. Zusammenarbeit mit dem Data Mapper

Das Repository verwendet den in ED-04-002 implementierten `SourceDeliveryMapper`.

Der Mapper übernimmt ausschließlich

- SQL-Abbildung,
- Row Mapping,
- Domain Mapping.

Das Repository enthält selbst keine SQL-Anweisungen.

---

# 10. Fehlerbehandlung

Technische Persistenzfehler werden als technische Exceptions weitergegeben.

Fachliche Validierungen erfolgen ausschließlich im Domain Layer.

Das Repository führt keine zusätzlichen fachlichen Prüfungen durch.

---

# 11. Unit Tests

Mindestens folgende Repository-Tests werden implementiert.

1. Neue `SourceDelivery` kann gespeichert werden.
2. Bestehende `SourceDelivery` kann geladen werden.
3. Nicht vorhandene ID liefert `null`.
4. Suche über `externalDeliveryId` funktioniert.
5. Alle Attribute werden vollständig rehydriert.
6. Änderungen am Status werden korrekt gespeichert.
7. Optionale Attribute bleiben erhalten.

---

# 12. Akzeptanzkriterien

Das Work Package gilt als abgeschlossen, wenn

- das Repository Interface implementiert ist,
- die relationale Repository-Implementierung vorhanden ist,
- Aggregate gespeichert werden können,
- Aggregate vollständig geladen werden können,
- die Rehydration vollständig erfolgt,
- sämtliche Persistenzdetails gekapselt sind,
- alle Repository-Tests erfolgreich ausgeführt werden.