# Source-Policy System - Implementierungsplan

## Zusammenfassung

Whitelist-basiertes Datenquellen-Management fuer das edu-search-service unter `/compliance/source-policy`. Fuer Auditoren pruefbar mit vollstaendigem Audit-Trail.

**Kernprinzipien:**
- Nur offizielle Open-Data-Portale und amtliche Quellen (§5 UrhG)
- Training mit externen Daten: **VERBOTEN**
- Alle Aenderungen protokolliert (Audit-Trail)
- PII-Blocklist mit Hard-Block

---

## 1. Architektur

```
┌─────────────────────────────────────────────────────────────────┐
│                    admin-v2 (Next.js)                           │
│  /app/(admin)/compliance/source-policy/                         │
│  ├── page.tsx (Dashboard + Tabs)                                │
│  └── components/                                                │
│      ├── SourcesTab.tsx (Whitelist-Verwaltung)                  │
│      ├── OperationsMatrixTab.tsx (Lookup/RAG/Training/Export)   │
│      ├── PIIRulesTab.tsx (PII-Blocklist)                        │
│      └── AuditTab.tsx (Aenderungshistorie + Export)             │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                  edu-search-service (Go)                        │
│  NEW: internal/policy/                                          │
│  ├── models.go        (Datenstrukturen)                         │
│  ├── store.go         (PostgreSQL CRUD)                         │
│  ├── enforcer.go      (Policy-Enforcement)                      │
│  ├── pii_detector.go  (PII-Erkennung)                          │
│  └── audit.go         (Audit-Logging)                          │
│                                                                 │
│  MODIFIED:                                                      │
│  ├── crawler/crawler.go    (Whitelist-Check vor Fetch)         │
│  ├── pipeline/pipeline.go  (PII-Filter nach Extract)           │
│  └── api/handlers/policy_handlers.go (Admin-API)               │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                     PostgreSQL                                  │
│  NEW TABLES:                                                    │
│  - source_policies        (versionierte Policies)              │
│  - allowed_sources        (Whitelist pro Bundesland)           │
│  - operation_permissions  (Lookup/RAG/Training/Export Matrix)  │
│  - pii_rules              (Regex/Keyword Blocklist)            │
│  - policy_audit_log       (unveraenderlich)                    │
│  - blocked_content_log    (blockierte URLs fuer Audit)         │
└─────────────────────────────────────────────────────────────────┘
```

---

## 2. Datenmodell

### 2.1 PostgreSQL Schema

```sql
-- Policies (versioniert)
CREATE TABLE source_policies (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    version INTEGER NOT NULL DEFAULT 1,
    name VARCHAR(255) NOT NULL,
    bundesland VARCHAR(2),  -- NULL = Bundesebene/KMK
    is_active BOOLEAN DEFAULT true,
    created_at TIMESTAMP DEFAULT NOW(),
    approved_by UUID,
    approved_at TIMESTAMP
);

-- Whitelist
CREATE TABLE allowed_sources (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    policy_id UUID REFERENCES source_policies(id),
    domain VARCHAR(255) NOT NULL,
    name VARCHAR(255) NOT NULL,
    license VARCHAR(50) NOT NULL,  -- DL-DE-BY-2.0, CC-BY, §5 UrhG
    legal_basis VARCHAR(100),
    citation_template TEXT,
    trust_boost DECIMAL(3,2) DEFAULT 0.50,
    is_active BOOLEAN DEFAULT true
);

-- Operations Matrix
CREATE TABLE operation_permissions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    source_id UUID REFERENCES allowed_sources(id),
    operation VARCHAR(50) NOT NULL,  -- lookup, rag, training, export
    is_allowed BOOLEAN NOT NULL,
    requires_citation BOOLEAN DEFAULT false,
    notes TEXT
);

-- PII Blocklist
CREATE TABLE pii_rules (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(255) NOT NULL,
    rule_type VARCHAR(50) NOT NULL,  -- regex, keyword
    pattern TEXT NOT NULL,
    severity VARCHAR(20) DEFAULT 'block',  -- block, warn, redact
    is_active BOOLEAN DEFAULT true
);

-- Audit Log (immutable)
CREATE TABLE policy_audit_log (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    action VARCHAR(50) NOT NULL,
    entity_type VARCHAR(50) NOT NULL,
    entity_id UUID,
    old_value JSONB,
    new_value JSONB,
    user_email VARCHAR(255),
    created_at TIMESTAMP DEFAULT NOW()
);

-- Blocked Content Log
CREATE TABLE blocked_content_log (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    url VARCHAR(2048) NOT NULL,
    domain VARCHAR(255) NOT NULL,
    block_reason VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT NOW()
);
```

### 2.2 Initial-Daten

Datei: `edu-search-service/policies/bundeslaender.yaml`

```yaml
federal:
  name: "KMK & Bundesebene"
  sources:
    - domain: "kmk.org"
      name: "Kultusministerkonferenz"
      license: "§5 UrhG"
      legal_basis: "Amtliche Werke (§5 UrhG)"
      citation_template: "Quelle: KMK, {title}, {date}"
    - domain: "bildungsserver.de"
      name: "Deutscher Bildungsserver"
      license: "DL-DE-BY-2.0"

NI:
  name: "Niedersachsen"
  sources:
    - domain: "nibis.de"
      name: "NiBiS Bildungsserver"
      license: "DL-DE-BY-2.0"
    - domain: "mk.niedersachsen.de"
      name: "Kultusministerium Niedersachsen"
      license: "§5 UrhG"
    - domain: "cuvo.nibis.de"
      name: "Kerncurricula Niedersachsen"
      license: "DL-DE-BY-2.0"

BY:
  name: "Bayern"
  sources:
    - domain: "km.bayern.de"
      name: "Bayerisches Kultusministerium"
      license: "§5 UrhG"
    - domain: "isb.bayern.de"
      name: "ISB Bayern"
      license: "DL-DE-BY-2.0"
    - domain: "lehrplanplus.bayern.de"
      name: "LehrplanPLUS"
      license: "DL-DE-BY-2.0"

# Default Operations Matrix
default_operations:
  lookup:
    allowed: true
    requires_citation: true
  rag:
    allowed: true
    requires_citation: true
  training:
    allowed: false  # VERBOTEN
  export:
    allowed: true
    requires_citation: true

# Default PII Rules
pii_rules:
  - name: "Email Addresses"
    type: "regex"
    pattern: "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"
    severity: "block"
  - name: "German Phone Numbers"
    type: "regex"
    pattern: "(?:\\+49|0)[\\s.-]?\\d{2,4}[\\s.-]?\\d{3,}[\\s.-]?\\d{2,}"
    severity: "block"
  - name: "IBAN"
    type: "regex"
    pattern: "DE\\d{2}\\s?\\d{4}\\s?\\d{4}\\s?\\d{4}\\s?\\d{4}\\s?\\d{2}"
    severity: "block"
```

---

## 3. Backend Implementation

### 3.1 Neue Dateien

| Datei | Beschreibung |
|-------|--------------|
| `internal/policy/models.go` | Go Structs (SourcePolicy, AllowedSource, PIIRule, etc.) |
| `internal/policy/store.go` | PostgreSQL CRUD mit pgx |
| `internal/policy/enforcer.go` | `CheckSource()`, `CheckOperation()`, `DetectPII()` |
| `internal/policy/audit.go` | `LogChange()`, `LogBlocked()` |
| `internal/policy/pii_detector.go` | Regex-basierte PII-Erkennung |
| `internal/api/handlers/policy_handlers.go` | Admin-Endpoints |
| `migrations/005_source_policies.sql` | DB-Schema |
| `policies/bundeslaender.yaml` | Initial-Daten |

### 3.2 API Endpoints

```
# Policies
GET    /v1/admin/policies
POST   /v1/admin/policies
PUT    /v1/admin/policies/:id

# Sources (Whitelist)
GET    /v1/admin/sources
POST   /v1/admin/sources
PUT    /v1/admin/sources/:id
DELETE /v1/admin/sources/:id

# Operations Matrix
GET    /v1/admin/operations-matrix
PUT    /v1/admin/operations/:id

# PII Rules
GET    /v1/admin/pii-rules
POST   /v1/admin/pii-rules
PUT    /v1/admin/pii-rules/:id
DELETE /v1/admin/pii-rules/:id
POST   /v1/admin/pii-rules/test  # Test gegen Sample-Text

# Audit
GET    /v1/admin/policy-audit?from=&to=
GET    /v1/admin/blocked-content?from=&to=
GET    /v1/admin/compliance-report  # PDF/JSON Export

# Live-Check
POST   /v1/admin/check-compliance
       Body: { "url": "...", "operation": "lookup" }
```

### 3.3 Crawler-Integration

In `crawler/crawler.go`:
```go
func (c *Crawler) FetchWithPolicy(ctx context.Context, url string) (*FetchResult, error) {
    // 1. Whitelist-Check
    source, err := c.enforcer.CheckSource(ctx, url)
    if err != nil || source == nil {
        c.enforcer.LogBlocked(ctx, url, "not_whitelisted")
        return nil, ErrNotWhitelisted
    }

    // ... existing fetch ...

    // 2. PII-Check nach Fetch
    piiMatches := c.enforcer.DetectPII(content)
    if hasSeverity(piiMatches, "block") {
        c.enforcer.LogBlocked(ctx, url, "pii_detected")
        return nil, ErrPIIDetected
    }

    return result, nil
}
```

---

## 4. Frontend Implementation

### 4.1 Navigation Update

In `lib/navigation.ts` unter `compliance` Kategorie hinzufuegen:

```typescript
{
  id: 'source-policy',
  name: 'Quellen-Policy',
  href: '/compliance/source-policy',
  description: 'Datenquellen & Compliance',
  purpose: 'Whitelist zugelassener Datenquellen mit Operations-Matrix und PII-Blocklist.',
  audience: ['DSB', 'Compliance Officer', 'Auditor'],
  gdprArticles: ['Art. 5 (Rechtmaessigkeit)', 'Art. 6 (Rechtsgrundlage)'],
}
```

### 4.2 Seiten-Struktur

```
/app/(admin)/compliance/source-policy/
├── page.tsx              # Haupt-Dashboard mit Tabs
└── components/
    ├── SourcesTab.tsx    # Whitelist-Tabelle mit CRUD
    ├── OperationsMatrixTab.tsx  # 4x4 Matrix
    ├── PIIRulesTab.tsx   # PII-Regeln mit Test-Funktion
    └── AuditTab.tsx      # Aenderungshistorie + Export
```

### 4.3 UI-Layout

**Stats Cards (oben):**
- Aktive Policies
- Zugelassene Quellen
- Blockiert (heute)
- Compliance Score

**Tabs:**
1. **Dashboard** - Uebersicht mit Quick-Stats
2. **Quellen** - Whitelist-Tabelle (Domain, Name, Lizenz, Status)
3. **Operations** - Matrix mit Lookup/RAG/Training/Export
4. **PII-Regeln** - Blocklist mit Test-Funktion
5. **Audit** - Aenderungshistorie mit PDF/JSON-Export

**Pattern (aus audit-report/page.tsx):**
- Tab-Navigation: `bg-purple-600 text-white` fuer aktiv
- Status-Badges: `bg-green-100 text-green-700` fuer aktiv
- Tabellen: `hover:bg-slate-50`
- Info-Boxen: `bg-blue-50 border-blue-200`

---

## 5. Betroffene Dateien

### Neue Dateien erstellen:

**Backend (edu-search-service):**
```
internal/policy/models.go
internal/policy/store.go
internal/policy/enforcer.go
internal/policy/audit.go
internal/policy/pii_detector.go
internal/api/handlers/policy_handlers.go
migrations/005_source_policies.sql
policies/bundeslaender.yaml
```

**Frontend (admin-v2):**
```
app/(admin)/compliance/source-policy/page.tsx
app/(admin)/compliance/source-policy/components/SourcesTab.tsx
app/(admin)/compliance/source-policy/components/OperationsMatrixTab.tsx
app/(admin)/compliance/source-policy/components/PIIRulesTab.tsx
app/(admin)/compliance/source-policy/components/AuditTab.tsx
```

### Bestehende Dateien aendern:

```
edu-search-service/cmd/server/main.go           # Policy-Endpoints registrieren
edu-search-service/internal/crawler/crawler.go  # Policy-Check hinzufuegen
edu-search-service/internal/pipeline/pipeline.go  # PII-Filter
edu-search-service/internal/database/database.go  # Migrations
admin-v2/lib/navigation.ts                      # source-policy Modul
```

---

## 6. Implementierungs-Reihenfolge

### Phase 1: Datenbank & Models
1. Migration `005_source_policies.sql` erstellen
2. Go Models in `internal/policy/models.go`
3. Store-Layer in `internal/policy/store.go`
4. YAML-Loader fuer Initial-Daten

### Phase 2: Policy Enforcer
1. `internal/policy/enforcer.go` - CheckSource, CheckOperation
2. `internal/policy/pii_detector.go` - Regex-basierte Erkennung
3. `internal/policy/audit.go` - Logging
4. Integration in Crawler

### Phase 3: Admin API
1. `internal/api/handlers/policy_handlers.go`
2. Routen in main.go registrieren
3. API testen

### Phase 4: Frontend
1. Hauptseite mit PagePurpose
2. SourcesTab mit Whitelist-CRUD
3. OperationsMatrixTab
4. PIIRulesTab mit Test-Funktion
5. AuditTab mit Export

### Phase 5: Testing & Deployment
1. Unit Tests fuer Enforcer
2. Integration Tests fuer API
3. E2E Test fuer Frontend
4. Deployment auf Mac Mini

---

## 7. Verifikation

### Nach Backend (Phase 1-3):
```bash
# Migration ausfuehren
ssh macmini "cd /path/to/edu-search-service && go run ./cmd/migrate"

# API testen
curl -X GET http://macmini:8088/v1/admin/policies
curl -X POST http://macmini:8088/v1/admin/check-compliance \
  -d '{"url":"https://nibis.de/test","operation":"lookup"}'
```

### Nach Frontend (Phase 4):
```bash
# Build & Deploy
rsync -avz admin-v2/ macmini:/path/to/admin-v2/
ssh macmini "docker compose build admin-v2 && docker compose up -d admin-v2"

# Testen
open https://macmini:3002/compliance/source-policy
```

### Auditor-Checkliste:
- [ ] Alle Quellen in Whitelist dokumentiert
- [ ] Operations-Matrix zeigt Training = VERBOTEN
- [ ] PII-Regeln aktiv und testbar
- [ ] Audit-Log zeigt alle Aenderungen
- [ ] Blocked-Content-Log zeigt blockierte URLs
- [ ] PDF/JSON-Export funktioniert

---

## 8. KMK-Spezifika (§5 UrhG)

**Rechtsgrundlage:**
- KMK-Beschluesse, Vereinbarungen, EPA sind amtliche Werke nach §5 UrhG
- Frei nutzbar, Attribution erforderlich

**Zitierformat:**
```
Quelle: KMK, [Titel des Beschlusses], [Datum]
Beispiel: Quelle: KMK, Bildungsstandards im Fach Deutsch, 2003
```

**Zugelassene Dokumenttypen:**
- Beschluesse (Resolutions)
- Vereinbarungen (Agreements)
- EPA (Einheitliche Pruefungsanforderungen)
- Empfehlungen (Recommendations)

**In Operations-Matrix:**
| Operation | Erlaubt | Hinweis |
|-----------|---------|---------|
| Lookup | Ja | Quelle anzeigen |
| RAG | Ja | Zitation im Output |
| Training | **NEIN** | VERBOTEN |
| Export | Ja | Attribution |

---

## 9. Lizenzen

| Lizenz | Name | Attribution |
|--------|------|-------------|
| DL-DE-BY-2.0 | Datenlizenz Deutschland | Ja |
| CC-BY | Creative Commons Attribution | Ja |
| CC-BY-SA | CC Attribution-ShareAlike | Ja + ShareAlike |
| CC0 | Public Domain | Nein |
| §5 UrhG | Amtliche Werke | Ja (Quelle) |

---

## 10. Aktueller Stand

**Phase 1: Datenbank & Models - ABGESCHLOSSEN**
- [x] Codebase-Exploration edu-search-service
- [x] Codebase-Exploration admin-v2
- [x] Plan dokumentiert
- [x] Migration 005_source_policies.sql erstellen
- [x] Go Models implementieren (internal/policy/models.go)
- [x] Store-Layer implementieren (internal/policy/store.go)
- [x] Policy Enforcer implementieren (internal/policy/enforcer.go)
- [x] PII Detector implementieren (internal/policy/pii_detector.go)
- [x] Audit Logging implementieren (internal/policy/audit.go)
- [x] YAML Loader implementieren (internal/policy/loader.go)
- [x] Initial-Daten YAML erstellen (policies/bundeslaender.yaml)
- [x] Unit Tests schreiben (internal/policy/policy_test.go)
- [x] README aktualisieren

**Phase 2: Admin API - AUSSTEHEND**
- [ ] API Handlers implementieren (policy_handlers.go)
- [ ] main.go aktualisieren
- [ ] API testen

**Phase 3: Integration - AUSSTEHEND**
- [ ] Crawler-Integration
- [ ] Pipeline-Integration

**Phase 4: Frontend - AUSSTEHEND**
- [ ] Frontend page.tsx erstellen
- [ ] SourcesTab Component
- [ ] OperationsMatrixTab Component
- [ ] PIIRulesTab Component
- [ ] AuditTab Component
- [ ] Navigation aktualisieren

**Erstellte Dateien:**
```
edu-search-service/
├── migrations/
│   └── 005_source_policies.sql     # DB Schema (6 Tabellen)
├── internal/policy/
│   ├── models.go                   # Datenstrukturen & Enums
│   ├── store.go                    # PostgreSQL CRUD
│   ├── enforcer.go                 # Policy-Enforcement
│   ├── pii_detector.go             # PII-Erkennung
│   ├── audit.go                    # Audit-Logging
│   ├── loader.go                   # YAML-Loader
│   └── policy_test.go              # Unit Tests
└── policies/
    └── bundeslaender.yaml          # Initial-Daten (8 Bundeslaender)
```
