Unterschriften-Verwaltung — E-Signatur (A-2)
Bezug: A-2, R4, R9, OP-SIGN-1 · Status: Provider-Abstraktion + Niveau-Matrix (Slice 4, 0.4.0) +
Unterschriften-Assistent inkl. Vor-Ort-/Demo-Abschluss gebaut (MED-D-198, Akten-Cockpit S5, 0.97.0) +
DocuSign-HTTP-Adapter gebaut (MED-D-220, 0.100.0, JWT-Grant/WebCrypto + Envelope + Connect-Webhook,
dormant ohne Secret) + echte Vor-Ort-/In-Person-Signatur gebaut (MED-D-236, 0.106.0, embedded/captive
recipient + recipient view); die Adapter sind noch nicht live verifiziert (kein Dev-Secret/Netz in der
Build-Umgebung — gegen gemocktes fetch unit-getestet); PandaDoc + QES-CSP-Anbindung bleiben offen
(OP-SIGN-1 Rest). Ohne konfiguriertes Secret läuft die Strecke weiter gegen die Fake-Provider-Attrappe
(durchgehend als Demo gekennzeichnet, MED-KB-5).
Vor-Ort-Signatur: echt (In-Person) vs. Attrappe (MED-D-236)
Die „Vor Ort unterschreiben"-Strecke des Assistenten hat zwei Ausprägungen, je nach aktivem Provider —
der Server entscheidet, der Client reagiert (eingebettet-Flag):
| Aspekt | Echt (DocuSign In-Person) | Attrappe (Fake-Provider) |
|---|---|---|
| Mechanik | Embedded/captive recipient (clientUserId gesetzt → kein E-Mail-Versand) + recipient view-URL, im iFrame auf dem Berater-Gerät | abschliessenDemo schließt ohne Roundtrip ab |
| Rechtswirkung | rechtsgültig (SES/AES je Dokumenttyp; QES → CSP-Rest) | keine — nur Demo (MED-KB-5) |
| Host | Der eingeloggte Berater (Name = anzeigename, E-Mail = Identität; MED-D-237) — DOCUSIGN_HOST_NAME/_EMAIL nur als Fallback | — |
| Abschluss | DocuSign-Redirect auf …/oeffentlich/signatur/vor-ort-fertig?event=signing_complete → iFrame-Handler → abgleich (Write-back) | direkt → erhalten (Prüfung offen) |
| Mehrere Dokumente | sequenziell (ein iFrame je Envelope, Index-Fortschritt) | Sammel-Abschluss |
| Route | POST /api/dokumente/:docId/signatur/vor-ort (vorbereiten) + POST /api/signaturen/:id/vor-ort-ansicht (URL) | POST /api/signaturen/:id/vor-ort-abschluss |
Sicherheitsriegel unverändert: der echte Adapter bietet kein abschliessenDemo → der Attrappen-
Abschluss liefert gegen DocuSign weiter 409 (nie fälschbar). Der Assistent blendet den Demo-Schnell-
Abschluss bei echten Vorgängen aus; das Demo-Banner erscheint nur, solange die Sitzung gegen den Fake läuft.
Landung wie Sign-on-Paper: das Dokument geht auf erhalten (Prüfung offen), nicht automatisch auf
geprüft/unterschrieben — der Berater bestätigt die Vor-Ort-Unterschrift (G-4).
Host = eingeloggter Berater (MED-D-237). Der DocuSign-In-Person-Host ist die Person, die die Session
leitet — bei uns der eingeloggte Berater (Name aus benutzer.anzeigename, E-Mail aus der Cloudflare-Access-
Identität), damit der DocuSign-Audit-Trail den echten Bezeuger zeigt (G-4), statt eines generischen
Sammel-Kontos. Harte Voraussetzung: die Berater-E-Mail muss ein Nutzer desselben DocuSign-Accounts
sein (sonst lehnt DocuSign den In-Person-Host ab) — jeder Vor-Ort-Berater ist also im DocuSign-Account
anzulegen. Fehlt die Identität (Dev/nicht eingeloggt), greift die Default-Konfiguration
DOCUSIGN_HOST_NAME/_EMAIL als Fallback. Anlage und Signaturansicht nutzen denselben Host — die
In-Person-Session sollte also derselbe Berater durchführen, der sie angelegt hat (DocuSign matcht den Host).
Live-Verifikation offen (OP-SIGN-1): Adapter unit-getestet gegen gemocktes fetch, echter In-Person-
Roundtrip noch nicht gefahren — Runbook s. Deploy.md §7d.
Entscheidung (A-2)
Unterschriften werden über einen Standard-E-Signatur-Dienst (DocuSign oder PandaDoc) eingeholt — kein Eigenbau (G-1). Medidentas spricht den Provider über eine Provider-Abstraktion an, sodass der Anbieter austauschbar bleibt und ein zweiter Provider (Fallback / Niveau-spezifisch) ergänzt werden kann.
eIDAS-Niveau je Dokumenttyp (zentral!)
Elektronische Signaturen haben unterschiedliche Rechtswirkung — das Niveau muss zum Dokumenttyp passen (RISK-2):
| Niveau | eIDAS | Wann | Beispiel-Dokumenttyp |
|---|---|---|---|
| SES | einfache Signatur | geringe Formanforderung | Einwilligung, Kenntnisnahme |
| AES | fortgeschritten (Identität gebunden, Änderung erkennbar) | erhöhte Beweiskraft | Standard-Verträge, Vollmachten |
| QES | qualifiziert (= eigenhändige Unterschrift, Zertifikat) | Schriftform gesetzlich gefordert | formgebundene Verträge |
CH: Schweiz nutzt ZertES (nicht eIDAS); QES-Äquivalent ist die qualifizierte ZertES-Signatur. Niveau ist je Dokumenttyp begründet festzulegen (Compliance-Tracker §3).
Einordnung Selfservice-Onboarding & Identverifikation (D-30)
Drei Schichten, die nicht vermischt werden dürfen:
| Schicht | Frage | Lösung bei Medidentas |
|---|---|---|
| Einwilligung/Kenntnisnahme | Hat der Kunde zugestimmt? | Checkbox + versionierter Text + Audit (öffentl. Onboarding-Formular, Slice 9) — kein Provider nötig (Art. 7 DSGVO: formfrei, Nachweisbarkeit genügt; SES-Fall der Matrix) |
| Unterschrift (Willenserklärung) | Hat er rechtswirksam gezeichnet? | DocuSign/PandaDoc am Onboarding-Abschluss: Maklervertrag → AES, Vollmacht → QES (konservativ; § 167 Abs. 2 BGB formfrei — real entscheidet die Akzeptanz der Produktgeber) |
| Identitätsverifikation | Ist er, wer er behauptet? | Nur bei GwG-Pflicht (OP-GWG-1/RISK-25): Standard = Berater-Ident im Termin (Ausweis, Mandant+Audit); VideoIdent/PostIdent nur Fallback für terminlose Strecken; QES-Flow enthält die Identifizierung implizit |
Anbieterwahl-Heuristik (OP-SIGN-1-Rest): Bei den wichtigsten Produktgebern abfragen, welches Niveau sie für Maklervollmachten akzeptieren — reicht AES → PandaDoc-Tendenz (Kosten/Templates); ist QES nötig → DocuSign mit EU-QES-Partner (CSP). In beiden Fällen: EU-Datenresidenz + AVV/Transfermechanismus (US-Konzern).
Anbietervergleich (OP-SIGN-1 — Entscheidungsgrundlage)
| Kriterium | DocuSign | PandaDoc |
|---|---|---|
| Marktreife / Verbreitung | sehr hoch | hoch |
| eIDAS QES/AES | ja (über Partner/CSP) | ja (über Partner) |
| EU-Datenresidenz | verfügbar (Region wählen) | verfügbar |
| Datenexport US | US-Konzern → Transfer prüfen (DPF/SCC) | US-Konzern → Transfer prüfen |
| Dokument-Erstellung/Templates | stark | sehr stark (CPQ/Proposals) |
| API / Webhooks | reif, breit | reif |
| Kosten | höher | tendenziell günstiger |
Empfehlung (vorläufig): Auswahl an den Pflicht-Niveaus und der Datenresidenz festmachen — wenn QES für formgebundene Verträge nötig ist, den Anbieter mit passender CSP-Anbindung und EU-Residenz wählen. Entscheidung in OP-SIGN-1 mit Begründung dokumentieren.
Provider-Abstraktion
Einheitliche Operationen der Abstraktion: envelopeErstellen(dokument, unterzeichner, niveau) ·
statusAbfragen(id) · webhookVerarbeiten(event) · signiertesDokumentAbrufen(id).
Sequenz: Unterschrift einholen
Nicht-funktional
- Idempotenz/Reconciliation: Webhook verpasst? → periodischer Status-Abgleich (RISK-6).
- Nachweis (G-4): Signatur-Zertifikat/Audit-Trail des Providers zusammen mit dem Dokument archivieren.
Umgesetzt (Slice 4, 0.4.0)
- Provider-Abstraktion
SignaturProvider(server/src/signatur/provider.ts):anfordern+status;FakeSignatur(signatur/fake.ts) für Tests/Staging. Provider-Wahl viaSIGNATUR_PROVIDER(MVP:fake). - Niveau-Matrix (
domain/signatur-niveau.ts, begründet, admin-editierbar gedacht): Vollmacht → QES, Vertrag/Auftrag → AES, Mandat/Einwilligung → SES, Default → AES. - Signatur-Dienst (
api/signatur-service.ts): anfordern (Niveau aus Matrix) · idempotenter Status-Abgleich (RISK-6) · bei Abschluss Rückablage der signierten Fassung in die Ablage (R9; produktiv R2, MED-D-61) + Dokument-Statusunterschrieben(R3) + Onboarding-Itemgeprüft(R2) — "eine Wahrheit" (G-2). - D1-Tabelle
signatur_vorgang(Migration v3), Felder R4-F01..08. REST:POST /api/dokumente/:id/signatur,GET /api/mandanten/:id/signaturen,POST /api/signaturen/:id/abgleich,POST /api/signaturen/:id/vor-ort-abschluss(MED-D-198). Ohne Provider/NextCloud →503.
Unterschriften-Assistent + Vor-Ort-/Demo-Abschluss (MED-D-198, Akten-Cockpit S5)
Ein geführter 3-Schritt-Assistent (Client-Overlay md-unterschriften-assistent) bündelt das Einholen:
(1) Prüfen (Dokument(e) wählen, eIDAS-Niveau je Typ automatisch aus der Matrix oder manuell überschreiben) ·
(2) Versenden (Sammel-Umschlag: mehrere Dokumente in einem Zug, Frist → Wiedervorlage) · (3) Verfolgen
(Status je Vorgang). Daneben eine Vor-Ort-Strecke für die In-Person-Signatur auf dem Berater-Gerät.
Sicherheitsriegel (nie fälschbare echte Vorgänge): der Vor-Ort-/Demo-Abschluss ist nur am Fake-Provider
möglich (SignaturProvider.abschliessenDemo? existiert ausschließlich in FakeSignatur; vorOrtAbschluss in
signatur-service.ts liefert 409 gegen einen echten Provider). Der Abschluss läuft über denselben
abgleich-Write-back-Pfad → signierte Fassung in die Ablage (R4→R3→R2), Dokument unterschrieben,
Onboarding-Item geprüft, Audit (G-4). Der Attrappe-Hinweis ist in der UI durchgehend sichtbar (MED-KB-5).
DocuSign-HTTP-Adapter (MED-D-220, 0.100.0)
Erster echter Provider hinter der Abstraktion: DocuSignSignatur (server/src/signatur/docusign.ts)
spricht die DocuSign-eSignature-REST-API direkt via fetch an — das Node-SDK docusign-esign läuft
nicht auf Cloudflare Workers, daher hand-gerollt:
- Auth = JWT Grant (Server-to-Server, kein User-Redirect): RS256-JWT wird in-Worker über WebCrypto
(
crypto.subtle) signiert (aud=Auth-Host,scope=signature impersonation), gegen/oauth/tokengetauscht; Access-Token wird gecacht. Der private Schlüssel ist PKCS#8 (PKCS#1 wird explizit abgelehnt — WebCryptoimportKey('pkcs8', …)). - Envelope-Flow:
anfordernlädt die Dokument-Bytes aus der Ablage (viasignatur-service.ts, R4→R3), base64-kodiert sie in einen Envelope (status:'sent', Signer = Mandanten-E-Mail/-Name,signHere-Tab), hängt eineeventNotification(Connect-Webhook-URL) an.status(envelopeId)fragt den Envelope ab und lädt bei Abschluss die kombinierte signierte Fassung (/documents/combined) für den Write-back. - Connect-Webhook (Push statt Pull): Route
POST /oeffentlich/signatur/docusign-webhook(api/app.ts, öffentlich = kein Access-Login, aber HMAC-verifiziert):X-DocuSign-Signature-1wird gegenDOCUSIGN_WEBHOOK_HMACper HMAC-SHA256 konstant-zeit geprüft (fail-closed ohne Key → 401), dannenvelopeId→interner Vorgang→abgleich. Der bestehende Pull-Abgleich (RISK-6) bleibt als Fallback für verpasste Webhooks. - QES→AES-Herabstufung mit Hinweis (Dev-Account-Grenze): ein QES-Dokumenttyp wird über den DocuSign-Dev-Account als AES versendet mit sichtbarem Hinweis — echte QES braucht einen eIDAS-QES-CSP-Vertrag (offen, s. u.). Bewusst festgehalten, nicht still herabgestuft.
- Sicherheitsriegel bleibt: DocuSign hat kein
abschliessenDemo→vorOrtAbschlussliefert 409; echte Vorgänge sind nie fälschbar (MED-D-198). - Dormant ohne Secret:
docuSignKonfigAusEnvgibtnullzurück, wenn ein Pflicht-Secret fehlt → Provider fällt auffakezurück / API503; das Deployment bleibt ohne Secret deploy-sicher (G-5). Secrets:DOCUSIGN_INTEGRATION_KEY,DOCUSIGN_USER_ID,DOCUSIGN_ACCOUNT_ID,DOCUSIGN_PRIVATE_KEY(PKCS#8-PEM),DOCUSIGN_WEBHOOK_HMAC+SIGNATUR_PROVIDER=docusign(s.docs/architektur/Deploy.md).
Offene Punkte
- OP-SIGN-1 (Rest): Live-Verifikation des DocuSign-Adapters gegen den echten Dev-Account (Secret +
Netzzugang außerhalb der Build-Sandbox), PandaDoc-Adapter als Alternative/Fallback + QES-CSP-
Anbindung (echte QES statt AES-mit-Hinweis) + Datenresidenz/AVV (US-Transfer, s.
Compliance.md). Abstraktion, Niveau-Matrix und der DocuSign-Adapter stehen; Live-Betrieb + zweiter Provider sind der Rest. Schritt-für-Schritt-Runbook (Scharfschalten + Live-Smoke-Test 1–7):docs/architektur/Deploy.md§7d inkl. „7d-Live-Verifikation". Bis dieser Smoke-Test durchlaufen ist, gilt der Adapter als gebaut, aber nicht live verifiziert (Unit-Tests: 10/10 gegen gemocktesfetch,signatur/docusign.test.ts).