# v1.4.0 Implementierungsplan

**Status:** 🔄 Konzept
**Zeitplan:** Q3 2026 (geschätzt)
**Fokus:** Advanced Traffic Management & Multi-Cloud + gRPC Transformations

---

## Mission

**"Bringe gRPC zu GAL mit nahtlosen Protobuf-Transformationen über alle Provider hinweg."**

Ermögliche Benutzern die Transformation von gRPC Request/Response-Nachrichten mithilfe von Protobuf-Descriptors und mache gRPC-Services genauso einfach verwaltbar wie REST-APIs mit GALs provider-agnostischer Konfiguration.

---

## Feature-Übersicht

| Feature | Status | Aufwand | Priorität |
|---------|--------|---------|-----------|
| **1. gRPC Transformations** | 🔄 Ausstehend | 3-4 Wochen | 🔴 Hoch |
| **2. Cloud Provider Support (AWS)** | 🔄 Ausstehend | 4 Wochen | 🟡 Mittel |
| **3. Cloud Provider Support (Azure)** | 🔄 Ausstehend | 3 Wochen | 🟡 Mittel |
| **4. Cloud Provider Support (GCP)** | 🔄 Ausstehend | 3 Wochen | 🟡 Mittel |
| **5. A/B Testing & Traffic Splitting** | 🔄 Ausstehend | 2 Wochen | 🟡 Mittel |
| **6. Request Mirroring/Shadowing** | 🔄 Ausstehend | 2 Wochen | 🟢 Niedrig |
| **7. Advanced Routing** | 🔄 Ausstehend | 2 Wochen | 🟢 Niedrig |
| **8. GraphQL Support** | 🔄 Ausstehend | 3 Wochen | 🟢 Niedrig |

**Gesamtaufwand:** ~22-24 Wochen (5-6 Monate)
**Fortschritt:** 0/8 Features (0%)

---

## Feature 1: gRPC Transformations (DETAILLIERT)

**Status:** 🔄 Ausstehend
**Priorität:** 🔴 Hoch
**Aufwand:** 3-4 Wochen

### Motivation

- **Problem**: gRPC-Services benötigen Body-Transformationen (Trace-IDs hinzufügen, Secrets entfernen, Felder umbenennen) genau wie REST-APIs
- **Herausforderung**: Jeder Provider hat unterschiedliche Mechanismen für Protobuf-Handling
- **Lösung**: GAL bietet eine einheitliche Konfiguration für gRPC-Transformationen mit Proto-Descriptor-Management

### Konfigurationsmodell

```python
# gal/config.py

@dataclass
class ProtoDescriptor:
    """Protobuf-Descriptor-Konfiguration."""
    name: str                    # Descriptor-Name (z.B. "user_service")
    source: str                  # "file", "inline", "url"
    path: str = ""               # Pfad zur .proto oder .desc Datei
    content: str = ""            # Inline Proto-Definition
    url: str = ""                # URL zum Download der Proto-Datei

@dataclass
class GrpcTransformation:
    """gRPC Transformation Konfiguration."""
    enabled: bool = True
    proto_descriptor: str = ""   # Referenz zum ProtoDescriptor-Namen
    package: str = ""            # Protobuf-Package (z.B. "user.v1")
    service: str = ""            # Service-Name (z.B. "UserService")
    request_type: str = ""       # Message-Type (z.B. "CreateUserRequest")
    response_type: str = ""      # Message-Type (z.B. "CreateUserResponse")

    # Transformationsregeln (wiederverwenden der bestehenden Body Transformation)
    request_transform: Optional[RequestBodyTransformation] = None
    response_transform: Optional[ResponseBodyTransformation] = None

@dataclass
class Route:
    # ... bestehende Felder ...
    grpc_transformation: Optional[GrpcTransformation] = None

@dataclass
class Config:
    # ... bestehende Felder ...
    proto_descriptors: List[ProtoDescriptor] = field(default_factory=list)
```

### YAML-Konfigurationsbeispiel

```yaml
# Proto Descriptors (global)
proto_descriptors:
  - name: user_service_proto
    source: file
    path: /etc/gal/protos/user.desc

  - name: order_service_proto
    source: inline
    content: |
      syntax = "proto3";
      package order.v1;

      service OrderService {
        rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);
      }

      message CreateOrderRequest {
        string user_id = 1;
        repeated string product_ids = 2;
      }

# Services
services:
  - name: user_grpc_service
    protocol: grpc
    upstream:
      host: user-grpc-backend
      port: 50051

    routes:
      - path_prefix: /user.v1.UserService/CreateUser
        grpc_transformation:
          enabled: true
          proto_descriptor: user_service_proto
          package: user.v1
          service: UserService
          request_type: CreateUserRequest
          response_type: CreateUserResponse

          request_transform:
            add_fields:
              trace_id: "{{uuid}}"
              timestamp: "{{timestamp}}"
              gateway_version: "GAL-v1.4.0"
            remove_fields:
              - internal_secret
              - debug_info
            rename_fields:
              user_id: userId
              email_address: email

          response_transform:
            filter_fields:
              - password_hash
              - internal_id
            add_fields:
              server_time: "{{timestamp}}"
              server_id: "gateway-01"
```

### Provider-Implementierungen

#### Envoy (Lua Filter)

**Datei:** `gal/providers/envoy.py`

```python
def _generate_grpc_transformation_envoy(self, route):
    """Generiere Envoy Lua Filter für gRPC Transformation."""
    if not route.grpc_transformation or not route.grpc_transformation.enabled:
        return None

    grpc = route.grpc_transformation
    proto_desc = self._get_proto_descriptor(grpc.proto_descriptor)

    lua_code = f'''
function envoy_on_request(request_handle)
    local pb = require("pb")

    -- Proto Descriptor laden (einmal pro Worker)
    if not _proto_loaded then
        pb.loadfile("{proto_desc.path}")
        _proto_loaded = true
    end

    -- gRPC Message Body abrufen
    local body = request_handle:body()
    if not body then
        return
    end

    -- Protobuf Message dekodieren
    local msg = pb.decode("{grpc.request_type}", body:getBytes(0, body:length()))

    -- Transformationen anwenden
    {self._generate_grpc_request_transform_lua(grpc.request_transform)}

    -- Zurück zu Protobuf enkodieren
    local new_body = pb.encode("{grpc.request_type}", msg)
    body:setBytes(new_body)
end

function envoy_on_response(response_handle)
    local pb = require("pb")

    local body = response_handle:body()
    if not body then
        return
    end

    local msg = pb.decode("{grpc.response_type}", body:getBytes(0, body:length()))

    -- Response-Transformationen anwenden
    {self._generate_grpc_response_transform_lua(grpc.response_transform)}

    local new_body = pb.encode("{grpc.response_type}", msg)
    body:setBytes(new_body)
end
'''

    return {
        "name": "envoy.filters.http.lua",
        "typed_config": {
            "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua",
            "inline_code": lua_code
        }
    }
```

#### Nginx (OpenResty Lua)

**Datei:** `gal/providers/nginx.py`

```python
def _generate_grpc_transformation_nginx(self, route):
    """Generiere Nginx/OpenResty Lua-Blöcke für gRPC Transformation."""
    if not route.grpc_transformation or not route.grpc_transformation.enabled:
        return []

    grpc = route.grpc_transformation
    proto_desc = self._get_proto_descriptor(grpc.proto_descriptor)

    output = []
    output.append("# gRPC Transformation (OpenResty)")
    output.append("")

    # Request-Transformation
    output.append("access_by_lua_block {")
    output.append("    local pb = require('pb')")
    output.append(f"    pb.loadfile('{proto_desc.path}')")
    output.append("")
    output.append("    -- gRPC Message Body lesen")
    output.append("    ngx.req.read_body()")
    output.append("    local body = ngx.req.get_body_data()")
    output.append("")
    output.append(f"    -- Protobuf Message dekodieren")
    output.append(f"    local msg = pb.decode('{grpc.request_type}', body)")
    output.append("")

    # Felder hinzufügen
    if grpc.request_transform and grpc.request_transform.add_fields:
        output.append("    -- Felder hinzufügen")
        for key, value in grpc.request_transform.add_fields.items():
            if value == "{{uuid}}":
                output.append(f"    msg['{key}'] = ngx.var.request_id")
            elif value in ["{{timestamp}}", "{{now}}"]:
                output.append(f"    msg['{key}'] = ngx.utctime()")
            else:
                output.append(f"    msg['{key}'] = '{value}'")
        output.append("")

    # Felder entfernen
    if grpc.request_transform and grpc.request_transform.remove_fields:
        output.append("    -- Felder entfernen")
        for field in grpc.request_transform.remove_fields:
            output.append(f"    msg['{field}'] = nil")
        output.append("")

    # Felder umbenennen
    if grpc.request_transform and grpc.request_transform.rename_fields:
        output.append("    -- Felder umbenennen")
        for old_name, new_name in grpc.request_transform.rename_fields.items():
            output.append(f"    msg['{new_name}'] = msg['{old_name}']")
            output.append(f"    msg['{old_name}'] = nil")
        output.append("")

    output.append(f"    -- Zurück zu Protobuf enkodieren")
    output.append(f"    local new_body = pb.encode('{grpc.request_type}', msg)")
    output.append("    ngx.req.set_body_data(new_body)")
    output.append("}")
    output.append("")

    # Response-Transformation
    if grpc.response_transform:
        output.append("body_filter_by_lua_block {")
        output.append("    local pb = require('pb')")
        output.append("")
        output.append("    local chunk = ngx.arg[1]")
        output.append("    local eof = ngx.arg[2]")
        output.append("")
        output.append("    if eof then")
        output.append(f"        local msg = pb.decode('{grpc.response_type}', chunk)")
        output.append("")

        # Felder filtern
        if grpc.response_transform.filter_fields:
            output.append("        -- Sensible Felder filtern")
            for field in grpc.response_transform.filter_fields:
                output.append(f"        msg['{field}'] = nil")
            output.append("")

        # Felder hinzufügen
        if grpc.response_transform.add_fields:
            output.append("        -- Metadaten-Felder hinzufügen")
            for key, value in grpc.response_transform.add_fields.items():
                if value == "{{timestamp}}":
                    output.append(f"        msg['{key}'] = ngx.utctime()")
                else:
                    output.append(f"        msg['{key}'] = '{value}'")
            output.append("")

        output.append(f"        ngx.arg[1] = pb.encode('{grpc.response_type}', msg)")
        output.append("    end")
        output.append("}")

    return "\n".join(output)
```

#### Kong (Custom Plugin)

**Datei:** `gal/providers/kong.py`

```python
def _generate_grpc_transformation_kong(self, route):
    """Generiere Kong Plugin Config für gRPC Transformation."""
    if not route.grpc_transformation or not route.grpc_transformation.enabled:
        return None

    grpc = route.grpc_transformation

    logger.warning(
        "gRPC Transformation in Kong erfordert ein Custom Plugin oder grpc-gateway. "
        "Optionen:\n"
        "  1. Nutze Kongs grpc-gateway Plugin: https://docs.konghq.com/hub/kong-inc/grpc-gateway/\n"
        "  2. Entwickle ein Custom Kong Plugin mit lua-protobuf\n"
        "  3. Deploye einen externen Transformation Service mit Kongs request-transformer-advanced"
    )

    # Basis grpc-gateway Config
    return {
        "name": "grpc-gateway",
        "config": {
            "proto": grpc.proto_descriptor,
            "service": grpc.service,
        }
    }
```

#### APISIX (grpc-transcode Plugin)

**Datei:** `gal/providers/apisix.py`

```python
def _generate_grpc_transformation_apisix(self, route):
    """Generiere APISIX grpc-transcode Plugin Config."""
    if not route.grpc_transformation or not route.grpc_transformation.enabled:
        return {}

    grpc = route.grpc_transformation
    proto_desc = self._get_proto_descriptor(grpc.proto_descriptor)

    # APISIX grpc-transcode für gRPC ↔ REST
    # Für reine gRPC Transformation: serverless-pre-function verwenden
    return {
        "serverless-pre-function": {
            "phase": "rewrite",
            "functions": [
                f"""
                return function(conf, ctx)
                    local pb = require("pb")
                    local core = require("apisix.core")

                    -- Proto Descriptor laden
                    pb.loadfile("{proto_desc.path}")

                    -- Request Body abrufen
                    local body = core.request.get_body()
                    local msg = pb.decode("{grpc.request_type}", body)

                    -- Transformationen anwenden
                    {self._generate_grpc_transform_lua(grpc.request_transform)}

                    -- Zurück enkodieren
                    local new_body = pb.encode("{grpc.request_type}", msg)
                    ngx.req.set_body_data(new_body)
                end
                """
            ]
        }
    }
```

#### HAProxy (Lua Script)

**Datei:** `gal/providers/haproxy.py`

```python
def _generate_grpc_transformation_haproxy(self, route):
    """Generiere HAProxy Lua Script Referenz für gRPC Transformation."""
    if not route.grpc_transformation or not route.grpc_transformation.enabled:
        return []

    grpc = route.grpc_transformation

    logger.warning(
        "gRPC Transformation in HAProxy erfordert externe Lua-Scripts. "
        "Schritte:\n"
        "  1. lua-protobuf installieren: luarocks install lua-protobuf\n"
        "  2. Lua-Script erstellen: /etc/haproxy/lua/grpc_transform.lua\n"
        "  3. In global section laden: lua-load /etc/haproxy/lua/grpc_transform.lua\n"
        "  4. Im Backend referenzieren: http-request lua.grpc_transform"
    )

    output = []
    output.append(f"    # gRPC Transformation (erfordert Lua-Script)")
    output.append(f"    http-request lua.grpc_transform_{grpc.service}")
    output.append(f"    http-response lua.grpc_transform_response_{grpc.service}")

    return output
```

#### Traefik (Middleware Warning)

**Datei:** `gal/providers/traefik.py`

```python
def _generate_grpc_transformation_traefik(self, route):
    """Traefik gRPC Transformation Warnung."""
    if not route.grpc_transformation or not route.grpc_transformation.enabled:
        return None

    logger.warning(
        "gRPC Transformation wird von Traefik nicht nativ unterstützt. "
        "Alternativen:\n"
        "  1. ForwardAuth Middleware mit externem gRPC Transformation Service\n"
        "  2. Custom Traefik Plugin (Go-Entwicklung erforderlich)\n"
        "  3. Alternativen Provider verwenden: Envoy, Kong, APISIX, Nginx, HAProxy"
    )

    return None
```

### Proto Descriptor Management

**Datei:** `gal/proto_manager.py` (NEU)

```python
import os
import subprocess
from typing import Dict, Optional
from gal.config import ProtoDescriptor

class ProtoManager:
    """Verwaltet Protobuf-Descriptors für gRPC-Transformationen."""

    def __init__(self, proto_dir: str = "/etc/gal/protos"):
        self.proto_dir = proto_dir
        self.descriptors: Dict[str, ProtoDescriptor] = {}
        os.makedirs(proto_dir, exist_ok=True)

    def register_descriptor(self, descriptor: ProtoDescriptor):
        """Registriere einen Proto-Descriptor."""
        self.descriptors[descriptor.name] = descriptor

        if descriptor.source == "file":
            # Datei existiert bereits, validieren
            if not os.path.exists(descriptor.path):
                raise FileNotFoundError(f"Proto Descriptor nicht gefunden: {descriptor.path}")

        elif descriptor.source == "inline":
            # Inline Proto-Content in Datei schreiben
            proto_file = os.path.join(self.proto_dir, f"{descriptor.name}.proto")
            with open(proto_file, 'w') as f:
                f.write(descriptor.content)

            # Zu .desc kompilieren
            descriptor.path = self._compile_proto(proto_file)

        elif descriptor.source == "url":
            # Proto-Datei von URL herunterladen
            proto_file = self._download_proto(descriptor.url, descriptor.name)
            descriptor.path = self._compile_proto(proto_file)

    def _compile_proto(self, proto_file: str) -> str:
        """Kompiliere .proto zu .desc mit protoc."""
        desc_file = proto_file.replace(".proto", ".desc")

        result = subprocess.run([
            "protoc",
            f"--descriptor_set_out={desc_file}",
            f"--proto_path={self.proto_dir}",
            proto_file
        ], capture_output=True, text=True)

        if result.returncode != 0:
            raise RuntimeError(f"protoc Kompilierung fehlgeschlagen: {result.stderr}")

        return desc_file

    def _download_proto(self, url: str, name: str) -> str:
        """Proto-Datei von URL herunterladen."""
        import requests

        proto_file = os.path.join(self.proto_dir, f"{name}.proto")
        response = requests.get(url)
        response.raise_for_status()

        with open(proto_file, 'wb') as f:
            f.write(response.content)

        return proto_file

    def get_descriptor(self, name: str) -> Optional[ProtoDescriptor]:
        """Registrierten Proto-Descriptor nach Namen abrufen."""
        return self.descriptors.get(name)
```

### Test-Strategie

**Datei:** `tests/test_grpc_transformation.py` (15+ Tests)

```python
# Test-Kategorien:
# 1. Config-Model-Tests (GrpcTransformation, ProtoDescriptor)
# 2. YAML-Parsing-Tests
# 3. Proto-Descriptor-Management-Tests
# 4. Provider-spezifische Tests (Envoy, Kong, APISIX, Nginx, HAProxy, Traefik)
# 5. Integrationstests mit echten Proto-Dateien
```

### Dokumentation

**Datei:** `docs/guides/GRPC_TRANSFORMATIONS.md` (1000+ Zeilen, Deutsch)

Abschnitte:
- Übersicht & Anwendungsfälle
- Schnellstart (3 Beispiele)
- Proto Descriptor Management
- Konfigurationsoptionen
- Provider-Implementierungen (alle 6)
- Deployment-Strategien (Volume Mounts, ConfigMaps)
- Best Practices
- Troubleshooting

**Datei:** `examples/grpc-transformation-example.yaml` (10+ Szenarien)

### Meilensteine

**Woche 1-2:** Config Model + Proto Manager
- GrpcTransformation, ProtoDescriptor Models
- ProtoManager Implementierung
- YAML-Parsing
- 5+ Config-Tests

**Woche 2-3:** Provider-Implementierungen
- Envoy (Lua Filter)
- Nginx (OpenResty Lua)
- APISIX (Serverless Lua)
- Kong (Plugin-Warnung)
- HAProxy (Lua-Referenz)
- Traefik (Einschränkungs-Warnung)
- 10+ Provider-Tests

**Woche 3-4:** Dokumentation & Beispiele
- docs/guides/GRPC_TRANSFORMATIONS.md
- examples/grpc-transformation-example.yaml
- README.md Updates
- ROADMAP.md Updates

### Akzeptanzkriterien

✅ GrpcTransformation Config-Model implementiert
✅ ProtoManager kann .proto-Dateien laden/kompilieren
✅ Envoy generiert validen Lua-Filter für gRPC
✅ Nginx generiert valide OpenResty Lua-Blöcke
✅ APISIX generiert serverless-pre-function Config
✅ Kong zeigt hilfreiche Warnung + Alternativen
✅ HAProxy zeigt Lua-Script-Setup-Anweisungen
✅ Traefik zeigt Einschränkungs-Warnung + Alternativen
✅ 15+ Tests bestehen
✅ 1000+ Zeilen deutsche Dokumentation
✅ 10+ Beispiel-Szenarien

---

## Feature 2-8: Weitere v1.4.0 Features

*(Werden in zukünftigen Updates detailliert)*

**Cloud Provider Support:**
- AWS API Gateway
- Azure API Management
- Google Cloud API Gateway

**Advanced Traffic Management:**
- A/B Testing & Traffic Splitting
- Request Mirroring/Shadowing
- Advanced Routing (Headers, JWT, Geo)

**GraphQL Support:**
- Schema-Validierung
- Query Complexity Limits

---

## Zeitplan

- **Monat 1 (Wochen 1-4):** gRPC Transformations Feature
- **Monat 2 (Wochen 5-8):** AWS API Gateway Provider
- **Monat 3 (Wochen 9-12):** Azure API Management Provider
- **Monat 4 (Wochen 13-16):** Google Cloud API Gateway + A/B Testing
- **Monat 5 (Wochen 17-20):** Request Mirroring + Advanced Routing
- **Monat 6 (Wochen 21-24):** GraphQL Support + Testing + Dokumentation

**Gesamt:** 6 Monate (Q3 2026)

---

## Abhängigkeiten

- **protoc** (Protobuf Compiler) - für .proto → .desc Kompilierung
- **lua-protobuf** (Envoy, Nginx, APISIX, HAProxy) - Lua Protobuf-Bibliothek
- **requests** (Python) - zum Herunterladen von Proto-Dateien von URLs

---

## Nächste Schritte (Nach v1.3.0 Abschluss)

1. gRPC Transformations Anforderungen mit Benutzern überprüfen
2. Config Model Design finalisieren
3. Envoy + Nginx Implementierungen prototypen
4. Implementation in Q2 2026 beginnen

---

**Status:** 📝 Planungsdokument - Bereit für v1.4.0 Implementierung
