# DM002 — Reconcilix Persistence Model

**Version:** 0.2  
**Status:** Accepted  
**Scope:** Relational persistence of DM001 in MySQL  
**Reference SQL:** `DM002.sql`  
**Principle:** KISS — nachvollziehbarer Zustand statt Event Sourcing.

## 1. Purpose

DM002 beschreibt die relationale Persistenzsicht auf DM001. Ziel ist, jeden Reconciliation-Vorgang fachlich nachvollziehbar zu speichern, ohne das System frühzeitig mit Event Sourcing, Graph Database oder komplexer Historisierung zu überladen.

Die bisherige Reconcilix-Anwendung verwendet keine Datenbank. In der nächsten Umsetzungsphase wird das bestehende System gemeinsam mit Reconcilix Engineering um DM001/DM002 und ME001/ME002 ergänzt. Dabei werden nur die betroffenen Module ergänzt oder ausgetauscht. MySQL wird für diesen neuen fachlichen Bereich als persistentes Backend eingeführt.

## 2. Design Principles

1. DM001 bleibt das fachliche Referenzmodell.
2. DM002 bildet den aktuellen fachlichen Zustand relational ab.
3. Domain Objects kennen die Persistenz nicht selbst.
4. Fremdschlüssel sichern die Nachvollziehbarkeit der Ableitungskette.
5. Klassifikationen werden zunächst als URI-Referenzen gespeichert.
6. Die erste Implementierung unterstützt nur den aktuellen Scope `CONCEPT` und xTree/MCT.
7. URI-Identifikatoren werden case-sensitive verglichen und deshalb mit `utf8mb4_bin` kollationiert.
8. Für URI-Spalten gelten folgende Längenregeln:

```text
Reconcilix classification URI: VARCHAR(512)
External resource/system URI:  VARCHAR(2048)
```

Reconcilix Classification URIs umfassen insbesondere Entity Types, Status, Techniques, Strategies, Properties, Matching Patterns und Decisions. Externe URIs umfassen insbesondere Candidate-, Target-Vocabulary-, Source- und Source-System-URIs.

## 3. Tables

### 3.1 `source_value`

| Column | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | interne ID |
| `value` | TEXT | unveränderter Literalwert |
| `source_field` | VARCHAR(255) NULL | Quellfeld |
| `source_record_id` | VARCHAR(255) NULL | Quelldatensatz |
| `datatype` | VARCHAR(100) NULL | Datentyp |
| `language` | VARCHAR(35) NULL | BCP 47 |
| `preferred_entity_type_uri` | VARCHAR(512) | Reconcilix Classification URI |
| `provenance_json` | JSON NULL | kompakte Source Provenance |
| `created_at` | DATETIME | Zeitpunkt |

### 3.2 `context_item`

| Column | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | interne ID |
| `source_value_id` | BIGINT FK | Bezug zum SourceValue |
| `context_type_uri` | VARCHAR(512) | Reconcilix Classification URI |
| `value` | TEXT | Kontextwert |
| `source_uri` | VARCHAR(2048) NULL | optionale externe Quelle |

### 3.3 `interpretation_graph`

| Column | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | interne ID |
| `source_value_id` | BIGINT FK | Bezug zum SourceValue |
| `span_start` | INT | inklusiver Startoffset |
| `span_end` | INT | exklusiver Endoffset; muss größer als `span_start` sein |
| `source_fragment` | TEXT | unveränderter, aus den Offsets gebildeter Ausschnitt |
| `status_uri` | VARCHAR(512) | Reconcilix Classification URI |
| `version` | INT DEFAULT 1 | Graph-Version |
| `created_at` | DATETIME | Zeitpunkt |

`source_fragment` muss exakt dem durch `span_start` und `span_end` bezeichneten Ausschnitt aus `source_value.value` entsprechen. Diese Invariante wird in der Application beziehungsweise Repository Layer validiert.

### 3.4 `interpretation_node`

| Column | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | interne ID |
| `interpretation_graph_id` | BIGINT FK | Graph |
| `parent_node_id` | BIGINT FK NULL | zunächst höchstens ein Parent |
| `value` | TEXT | interpretierter Wert |
| `level` | INT | denormalisierte Ableitungstiefe |
| `status_uri` | VARCHAR(512) | Reconcilix Classification URI |
| `created_by` | VARCHAR(255) NULL | Agent/System |
| `technique_uri` | VARCHAR(512) NULL | Reconcilix Classification URI |
| `note` | TEXT NULL | Erläuterung |
| `created_at` | DATETIME | Zeitpunkt |

Für `level` gilt:

```text
Root Node:  level = 0
Child Node: level = parent.level + 1
```

Die Parent-Beziehung muss azyklisch sein. Diese Invarianten werden in der Application beziehungsweise Repository Layer geprüft.

### 3.5 `interpretation_node_property`

Join Table für `0..* InterpretationProperty`.

| Column | Type | Notes |
|---|---|---|
| `interpretation_node_id` | BIGINT FK | Node |
| `property_uri` | VARCHAR(512) | Reconcilix Classification URI |
| `confidence` | DECIMAL(6,5) NULL | optional |
| `note` | TEXT NULL | optional |

Primary Key:

```text
(interpretation_node_id, property_uri)
```

### 3.6 `reconciliation_result`

| Column | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | interne ID |
| `interpretation_node_id` | BIGINT FK | bearbeitete Node |
| `success` | BOOLEAN | vorläufiges Kompatibilitätsattribut; in der ersten Anwendung nicht auswertungsrelevant |
| `matching_strategy_uri` | VARCHAR(512) NULL | Reconcilix Classification URI |
| `vocabulary_matching_pattern_uri` | VARCHAR(512) NULL | 0..1 Reconcilix Classification URI |
| `confidence` | DECIMAL(6,5) NULL | optional |
| `target_vocabulary_uri` | VARCHAR(2048) NULL | externes Target Vocabulary oder Source System |
| `note` | TEXT NULL | Erläuterung |
| `created_at` | DATETIME | Zeitpunkt |

`success` bleibt in v0.2 aus Gründen der Modell- und Implementierungskontinuität erhalten. Da seine fachliche Semantik noch nicht abschließend festgelegt ist, darf das Attribut in der ersten Anwendung weder für fachliche Entscheidungen noch für Evaluationen oder Workflow-Steuerung verwendet werden. Maßgeblich sind Candidates und `MatchDecision`.

### 3.7 `candidate_item`

| Column | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | interne technische ID |
| `reconciliation_result_id` | BIGINT FK | Ergebnis |
| `uri` | VARCHAR(2048) | externe fachliche Identifikation |
| `display_label` | TEXT | Anzeigeform |
| `entity_type_uri` | VARCHAR(512) | Reconcilix Classification URI |
| `source_system_uri` | VARCHAR(2048) NULL | externes Zielsystem |
| `score` | DECIMAL(10,8) NULL | Score |
| `rank` | INT NULL | Rang |
| `qualifier` | VARCHAR(1024) NULL | Homonymzusatz |
| `payload_json` | JSON NULL | optionale targetspezifische Zusatzdaten |

Innerhalb eines `ReconciliationResult` darf dieselbe vollständige Candidate-URI höchstens einmal vorkommen. Die Deduplizierung erfolgt in v0.2 in der Application Layer. Eine spätere Datenbankabsicherung kann beispielsweise über einen URI-Hash erfolgen.

`payload_json` dient ausschließlich zur optionalen Speicherung targetspezifischer Zusatzdaten, die nicht Bestandteil des stabilen Reconcilix Domain Model sind. Fachlich zentrale Eigenschaften dürfen nicht ausschließlich darin persistiert werden.

### 3.8 `match_decision`

| Column | Type | Notes |
|---|---|---|
| `id` | BIGINT PK | interne ID |
| `reconciliation_result_id` | BIGINT FK | Ergebnis |
| `selected_candidate_item_id` | BIGINT FK NULL | optionaler Candidate |
| `decision_uri` | VARCHAR(512) | kontrollierte Entscheidung |
| `decision_status_uri` | VARCHAR(512) | Status der Entscheidung, z. B. vorläufig, geprüft oder final |
| `confidence` | DECIMAL(6,5) NULL | optional |
| `decided_by` | VARCHAR(255) NULL | Person/Rolle/System |
| `comment` | TEXT NULL | Erläuterung |
| `decided_at` | DATETIME | Zeitpunkt |

Ein `ReconciliationResult` kann mehrere `MatchDecision` erhalten. Entscheidungen werden nicht überschrieben. `decision_status_uri` kennzeichnet, ob eine Entscheidung beispielsweise vorläufig, fachlich geprüft oder final ist. Die fachlich maßgebliche Entscheidung ist die als final klassifizierte Entscheidung. Die zulässigen Statuswerte werden über ein kontrolliertes Reconcilix-Vokabular bereitgestellt.

## 4. Relational Overview

Das folgende Mermaid-Diagramm ist der verbindliche logische relationale Überblick für DM002. Ein separates draw.io-Diagramm wird nicht weitergeführt.

```mermaid
erDiagram
    SOURCE_VALUE ||--o{ CONTEXT_ITEM : has
    SOURCE_VALUE ||--|{ INTERPRETATION_GRAPH : segmented_into
    INTERPRETATION_GRAPH ||--|{ INTERPRETATION_NODE : contains
    INTERPRETATION_NODE o|--o{ INTERPRETATION_NODE : derives
    INTERPRETATION_NODE ||--o{ INTERPRETATION_NODE_PROPERTY : classified_by
    INTERPRETATION_NODE ||--o{ RECONCILIATION_RESULT : produces
    RECONCILIATION_RESULT ||--o{ CANDIDATE_ITEM : contains
    RECONCILIATION_RESULT ||--o{ MATCH_DECISION : receives
    CANDIDATE_ITEM o|--o{ MATCH_DECISION : selected_by
```

## 5. Deliberate Simplifications

Nicht Bestandteil von v0.2:

- Event Sourcing
- Graph Database
- vollständige Run-Historisierung
- Node-Merge und mehrere Parent Nodes
- separate Tabellen für Candidate-Typen
- persistierte LLM-Prompts oder Embeddings
- materialisierte Auswertungsmodelle
- datenbankseitige Candidate-Deduplizierung über die vollständige URI

## 6. Deletion and Referential Integrity

Die aggregationsbezogenen Relationen verwenden `ON DELETE CASCADE`, sodass ein vollständiger Reconciliation-Verlauf ausgehend vom `SourceValue` konsistent entfernt werden kann.

Für Parent Nodes und ausgewählte Candidates wird `ON DELETE RESTRICT` verwendet. Dadurch können referenzierte fachliche Zwischenschritte oder ausgewählte Candidates nicht isoliert gelöscht werden.

Fachliche Reconciliation-Verläufe werden im Regelfall nicht teilweise gelöscht. Löschoperationen erfolgen aggregatbezogen oder über ausdrücklich definierte Bereinigungsprozesse.

## 7. Repository Boundary

Die Domain Classes speichern sich nicht selbst. Die Persistenz wird hinter einer Repository Boundary gekapselt.

Die konkrete API wird im ADR- und Implementierungsschritt festgelegt. Dabei sollen Aggregat- und Transaktionsgrenzen berücksichtigt werden. Mögliche Schnittstellen sind beispielsweise:

```text
ReconciliationTraceRepository
- saveReconciliationTrace(...)
- loadReconciliationTraceBySourceValueId(...)
```

oder getrennte Repositories:

```text
SourceValueRepository
InterpretationGraphRepository
ReconciliationResultRepository
```

Die Bezeichnungen und Methodensignaturen sind in DM002 ausdrücklich nicht verbindlich. Verbindlich ist die Trennung zwischen Domain Model und Persistenzimplementierung.

## 8. Bootstrap and Migration Boundary

`DM002.sql` ist ein Bootstrap- und Development-Schema für die neue relationale Persistenz. Es ist keine Migration für eine bestehende Datenbank und darf nicht ungeprüft auf produktive Datenbanken angewendet werden, da es die DM002-Tabellen vor ihrer Neuanlage löscht.

Da die bestehende Reconcilix-Anwendung derzeit keine Datenbank verwendet, beschreibt AM001 später die Einführung der Persistenz und den gezielten Austausch beziehungsweise die Ergänzung der betroffenen Module. DM002 legt dafür das Zielschema fest, nimmt aber keine Implementierungs- oder Migrationsschritte vorweg.

## 9. First Implementation Scope

Die erste MySQL-Umsetzung umfasst:

- alle acht Tabellen,
- Foreign Keys und grundlegende Indizes,
- Speichern eines vollständigen einfachen Reconciliation-Verlaufs,
- Lesen eines Verlaufs für Debugging und Evaluation,
- zunächst genau einen `InterpretationGraph` pro `SourceValue`,
- zunächst lineare Node-Ableitung,
- `CONCEPT` als Entity Type,
- xTree/MCT als Target,
- Application-Layer-Validierung der dokumentierten Invarianten.
