# Python-SDK **Status:** `backlog: Data-Engineering-Use-Cases oder Python-Backend-Integrations für Tenants werden spürbar (mind. 2 Tenant-Anfragen, oder eigener Bedarf in Daten-Pipelines / Notebooks)` **Task-ID:** #64 **Phase:** 11 (Backlog) **Estimated Effort:** ~1 Woche wenn aktiviert **Owner:** unassigned ## Problem Die Boilerplate liefert mit Phase 08 (`ts-sdk.md`) ein TypeScript-SDK aus, das von Browser-/Node-Konsumenten benutzt werden kann. Tenants mit Python-Stacks (Data-Engineering, Notebooks, FastAPI/Django-Backends, ML-Pipelines, Scraper) müssten heute selbst über `requests` gegen die OpenAPI-Spec arbeiten. Sobald das spürbar wird (Anfragen, Friction-Reports), lohnt sich ein offizielles, generiertes Python-SDK. Solange kein Python-Bedarf existiert, ist der Maintenance-Aufwand (Two-SDKs-in-Sync halten, PyPI-Releases bauen, Python-Typing-Edge-Cases) nicht gerechtfertigt. ## Depends on - `../08-mobile-cli-storybook-sdk/ts-sdk.md` — die gleiche OpenAPI-Spec aus dem TS-SDK-Setup ist Quelle der Wahrheit für den Python-Codegen - bestehende OpenAPI-Spec-Generation aus der API-Route-Definition ## Blocks - nichts (Backlog-Item, blockt keine aktive Roadmap) ## Approach **Codegen via `openapi-generator-cli` (Java-basiert, am bequemsten als Docker-Image) gegen die gleiche OpenAPI-Spec wie TS-SDK.** Begründung gegen Alternativen: - *Manuell geschriebenes Python-SDK*: doppelter Maintenance-Aufwand, drift-anfällig. Verworfen. - *openapi-python-client (Pythonic Codegen)*: schmaler in Custom-Templates, modernere Typing, aber kleinerer Ökosystem-Support. Sekundär-Option wenn openapi-generator zu verbose ist. - *Custom Codegen via Jinja-Templates*: zu viel Eigenentwicklung. Verworfen. **Output:** `packages/api-client-py/` als PyPI-publishable Package, semver-aligned mit dem TS-SDK (gleiche Major-Version pro API-Version). **Custom-Templates** liefern Boilerplate-spezifische Helpers: - **Auth-Handling:** API-Key (Header `Authorization: Bearer `) und JWT-Bearer, einheitlicher Constructor (`Client(api_key=...)` oder `Client(jwt=...)`) - **Pagination-Iterator:** generierte List-Endpoints geben Python-Iterator zurück, der automatisch über `cursor`/`page` paginiert - **Retry-Logik:** via `tenacity` mit Exponential-Backoff + Jitter, nur für 5xx + 429 + Network-Errors - **Webhook-Verify:** Helper `verify_webhook(secret, payload, signature)` mit HMAC-SHA256 (gleiche Signaturlogik wie TS-SDK) **Tests:** `pytest` gegen eine lokal hochgezogene Boilerplate-API (Test-Setup im Repo), Snapshot-Tests für generierten Code (regenerate-Drift erkennen). **Release-Pipeline:** GitHub-Actions-Workflow `python-sdk-release.yml` baut bei Tag-Push (`api-client-py-vX.Y.Z`) Wheel + sdist und published auf PyPI via Trusted-Publishing (kein PyPI-Token im Repo). ## Implementation Steps 1. **Generator-Setup** — `openapi-generator-cli` als Docker-Image-Pinned-Version in `scripts/codegen-python.sh`, OpenAPI-Spec wird aus dem laufenden Dev-Server gezogen oder aus dem schon im TS-SDK gespeicherten JSON. Commit: `11-backlog/python-sdk: add codegen script` 2. **Erstes Codegen-Run** — Output in `packages/api-client-py/`, Basis-Generator-Output ohne Customizations committen. Commit: `11-backlog/python-sdk: initial generated client` 3. **Custom-Templates: Auth** — Jinja-Templates für Configuration-Class und Auth-Helpers überschreiben, einheitlicher Constructor. Commit: `11-backlog/python-sdk: custom auth templates` 4. **Custom-Templates: Pagination** — Iterator-Wrapper um List-Endpoints, automatisches Cursor-Following. Commit: `11-backlog/python-sdk: pagination iterator` 5. **Retry + Webhook-Verify-Helper** — `tenacity`-basierter Retry-Decorator, `hmac`-basierter Webhook-Verifier in `api_client/webhooks.py`. Commit: `11-backlog/python-sdk: retry + webhook helpers` 6. **pytest-Suite gegen lokale API** — Dev-Server hochfahren, gegen ein paar key Endpoints testen (List + Pagination, Create, Webhook-Verify, Retry-on-503). Commit: `11-backlog/python-sdk: pytest integration suite` 7. **PyPI-Release-Workflow + Doku** — GitHub-Actions-Workflow mit Trusted-Publishing, `packages/api-client-py/README.md` mit Quick-Start + Auth-Beispielen + Pagination-Beispiel + Webhook-Verify-Beispiel. Commit: `11-backlog/python-sdk: release workflow + readme` ## Test Requirements - **Unit-Tests:** Auth-Header-Setting, Pagination-Iterator (Cursor-Termination, Empty-Response), Retry-Logik (5xx triggert Retry, 4xx nicht), Webhook-Verify (gültig + ungültig + Replay-Toleranz) - **Integration-Tests:** gegen lokal hochgezogene Boilerplate-API (Pytest-Fixture startet API + Test-DB) — Create + List + Pagination + Auth-Failure-Cases - **Snapshot-Tests:** generierter Code im Repo committed; CI failt wenn Re-Generation ohne Schema-Änderung den Output ändert - **Coverage-Target:** ≥80% für Custom-Helpers (Auth, Pagination, Retry, Webhooks); generierter Code ausgenommen - **Test-Files:** `packages/api-client-py/tests/` **NICHT als completed markieren bevor alle Tests grün sind.** ## Acceptance Criteria - [ ] `packages/api-client-py/` enthält generiertes Client-Package mit Custom-Auth/Pagination/Retry/Webhook-Helpers - [ ] `pytest` Suite läuft grün gegen lokale Boilerplate-API - [ ] Snapshot-Tests detektieren ungewollten Codegen-Drift - [ ] PyPI-Release-Workflow funktioniert (Dry-Run auf TestPyPI verifiziert) - [ ] README mit Quick-Start + Auth + Pagination + Webhook-Beispielen vorhanden - [ ] Tests grün - [ ] Progress-Log + PROGRESS.md aktualisiert ## Rollback Strategy - Python-SDK ist ein zusätzliches Package — Entfernung beeinträchtigt API nicht - Bei brüchiger PyPI-Release: alte Version bleibt verfügbar, neue Version yanken via PyPI-Web-UI - Custom-Templates können stufenweise zurückgenommen werden (z.B. Pagination raus, manueller Cursor wieder); Konsumenten müssen dann auf vorherige Version pinnen ## Security Notes - **API-Keys werden nur über Constructor übergeben, nicht aus ENV gelesen** — Verantwortung bleibt beim Konsumenten, Logging-Filter verhindert versehentliches Logging des Keys - Webhook-Verify-Helper verwendet `hmac.compare_digest` (timing-safe) statt String-Vergleich - Generierter Code wird auf bekannte CVEs in transitiven Deps gescannt (`pip-audit` im CI) - TLS-Verifikation ist Default-On, kein Override-Flag im public API ## Subagent Recommendations - **Planning:** `Plan`-Subagent mit `ts-sdk.md`-Output als Referenz für Feature-Parität - **Research:** `Explore`-Subagent für openapi-generator vs openapi-python-client Vergleich (entscheidet zwischen den beiden falls openapi-generator nicht passt) - **Implementation:** ein `general-purpose`-Subagent pro Step - **Tests:** separater `general-purpose`-Subagent für die Pytest-Suite - **Verification:** `gsd-verifier` für Acceptance-Criteria - **Code-Review:** `gsd-code-reviewer` nach Step 7 ## Staging-Deployment-Steps 1. Branch `agent/11-backlog-python-sdk` pushen 2. Boilerplate-API lokal (oder auf Staging) starten 3. `pip install -e packages/api-client-py` im Test-venv 4. Manuelles Smoke-Script ausführen (List + Create + Webhook-Verify) 5. TestPyPI-Dry-Release vor echtem PyPI-Release ## Deviations from Plan _(Wird vom ausführenden Agent gefüllt.)_ ## Progress Log _(Wird vom ausführenden Agent gefüllt.)_