112 lines
7.1 KiB
Markdown
112 lines
7.1 KiB
Markdown
# 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 <key>`) 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.)_
|