You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ziel: RealUnit-Kunden bekommen E-Mails mit RealUnit-Branding, Sie-Form, RealUnit-Texten und ohne DFX-Defaults (Du-Form, „Dein freundliches DFX Team", Bitcoiners-by-heart-Closing etc.).
Was bereits implementiert ist (Stand 29.4.26)
✅ Body-Texte 1:1 aus DAS-Doc mit Tippfehler-Fixes (wir → wird, Verizierung → Verifizierung, erfolgreicht → erfolgreich, Verkaufauftrag → Verkaufsauftrag, Möglich → möglich, fehlendes da in Kraken exchange service #12 ergänzt)
✅ „Aktientoken" / „Token" -Differenzierung wie im Original (Aktientoken in Erst-Erwähnung, Token im Verkaufs-Flow)
✅ Wallet-aware Translation in MailFactory mit Fallback auf DFX-Default (mail.X → mail-realunit.X)
✅ Body-Text-Injection in der Factory: leitet .body-Key vom Title-Key ab und prepended ihn vor die regulären Texts
✅ mail-realunit.json (DE) mit Overrides für payment, kyc, pending, chargeback, recommendation, account_merge, login, verification_code, support_message, account_deactivation, limit_request
2. App-Öffnen-Button mit Link auf RealUnit-Website
Architektur-Entscheidung (mit User-Bestätigung): Es gibt eine extra Website, die das App-Öffnen handhabt (Universal Links / App Links / App-Store-Fallback). Die DFX-API verlinkt einfach diese URL — keine Deep-Link-Logik im API-Code.
Annahme zur URL:https://app.realunit.ch/open(DAS muss bestätigen, siehe §Klärungen)
Implementation:
Neuer Block in realunit.hbs zwischen {{#each texts}} und {{!-- Closing Block --}} mit fest verdrahtetem Link-Button "App öffnen"
Style: bestehender .btn-Class (blau #1988C6)
Optional: Steuerbar pro Mail über einen Boolean-Flag (z. B. nur bei Kauf-/Verkaufs-Mails) — TBD
Alternativ: Body-Texte enden mit einem [url:https://app.realunit.ch/open]-Marker, der per Body-Text-Injection als Button gerendert wird
Akzeptanzkriterium: Mindestens die Mails #1 (Kauf abgeschlossen), #17 (Verkauf abgeschlossen) zeigen einen klickbaren "App öffnen"-Button mit Link auf die RealUnit-App-Website.
3. Disclaimer-Footer „Dies ist eine automatisierte Mail…"
Im Original v1.0 stand dieser Disclaimer nur in #1. Logisch sollte er in jeder Mail stehen, weil keine Antwort erwartet/verarbeitet wird.
Implementation:
Neuer Block in realunit.hbs direkt oberhalb des {{!-- Footer Legal Block --}} (also vor Adresse/Datenschutz/Impressum)
Text: "Dies ist eine automatisierte Mail. Bitte antworten Sie nicht an diese Adresse."
Style: kleine Schrift (font-size: 11px), Grauton (#6B7280), zentriert
Akzeptanzkriterium: In allen 38 Preview-HTMLs steht der Disclaimer-Text vor dem Legal-Footer.
DAS hat in v1.0 explizit zwei Mail-Typen abgelehnt bzw. infrage gestellt:
4a. #13 „Aktion ausstehend" — DAS-Zitat:„In welchem Fall kann diese Mail bei uns erfolgen? So unspezifische Mails möchte ich nicht versenden!"
→ Eindeutige Ablehnung.
4b. #6 „Problem bei der Einzahlung" — DAS-Zitat:„Annahme: Mail sollte ja gar nicht zur Anwendung kommen, da erst nach vollständigem KYC der Kunde Token kaufen kann, oder?"
→ DAS war unsicher („oder?"). DFX-Vorschlag: deaktivieren, weil bei nur SEPA/SIC mit verifiziertem Kunden-IBAN dieser Trigger faktisch wegfällt. Edge-Cases (Rücklastschrift Wochen später) laufen über manuellen Support.
Implementation: Auf RealUnit-Wallet-DB-Eintrag das Feld disabledMailTypes setzen mit den entsprechenden MailContextType-Werten:
für Feature/kyc mail #13: `CHARGEBACK_UNCONFIRMED` o. Ä. (genauen Mapping-Eintrag aus MailContextTypeMapper prüfen)
für Hotfix/kyc check #6: bislang ist unklar, welcher konkrete MailContext für „Problem bei Einzahlung" steht — ggf. nicht im DFX-Standardset, dann entfällt 4b automatisch
Akzeptanzkriterium: Auf DEV-Umgebung Trigger #13 manuell auslösen für RealUnit-Testuser → keine Mail wird versendet. Logs zeigen isDisabledMailWallet === true.
Hintergrund: DAS hat im Original-Doc drei Slots als „Guthaben wurde erstattet" betitelt (#12, #15, #17). Der Slot-Titel kommt vermutlich aus einer DFX-Default-Liste, aber DAS hat die jeweiligen Betreffe bewusst überschrieben:
#
Original-Slot-Titel
DAS-Betreff
DFX-Trigger
12
Guthaben wurde erstattet
„Verkauf RealUnit-Token – Rückerstattung"
BUY_FIAT_RETURN (limit)
15
Guthaben wurde erstattet
„Verkauf RealUnit-Token aktuell nicht möglich"
BUY_FIAT_RETURN (unavailable)
17
Guthaben wurde erstattet
„Verkauf RealUnit-Token – Überweisung erfolgt"
BUY_FIAT_COMPLETED ← Slot-Umwidmung!
→ DAS hat absichtlich den DFX-„Guthaben erstattet"-Slot für eine Verkauf-erfolgreich-Mail umgewidmet.
Das im PR-Body explizit erwähnen, damit Reviewer verstehen, warum payment.fiat_output.body einen so DAS-spezifischen Text hat (Bestätigung der Banküberweisung) statt den DFX-Default-Wortlaut.
Sobald 1–5 erledigt + Smoke-Test auf DEV bestanden.
🟢 Preview-Script-Erweiterung
7. Trigger-Erklärung pro Mail im HTML-Output
Anforderung von Cyrill (29.4.26): Pro generierter Mail im HTML-Output soll ein ausführlicher Text stehen, der erklärt, wann diese Mail versendet wird.
Begründung: DAS' originale Forderung Nr. 1: „Klare Erklärung wann eine Mail gesendet wird!" — bislang nur als Tabelle im v1.1-Begleitdokument vorhanden, nicht in den HTML-Previews selbst.
Implementation:
In scripts/generate-realunit-previews.js pro Mail-Definition ein Feld triggerExplanation mit ~3–5 Sätzen
Im HTML-Output oberhalb der eigentlichen Mail eine Info-Box rendern:
Überschrift: „Wann wird diese Mail versendet?"
Beschreibung in Fließtext (Sie-Form, Endkunden-Sprache)
Technischer Trigger (z. B. BUY_CRYPTO_COMPLETED)
Status-Übergang (z. B. PROCESSING → COMPLETE)
Im Index-HTML pro Card eine Kurzfassung als zweite Zeile
Sobald die Fiat-Einzahlung des Kunden bei DFX eingegangen und automatisch verbucht wurde. DFX überweist dann die RealUnit-Token in das Kunden-Wallet, und diese Mail bestätigt den abgeschlossenen Kauf.
Technischer Trigger: BUY_CRYPTO_COMPLETED Status vorher: PROCESSING / Status nachher: COMPLETE
Akzeptanzkriterium: Alle 38 Mails haben eine Trigger-Erklärung, die ohne Code-Wissen verständlich ist.
🟢 Klärungen mit DAS / RealUnit
8. Finale URL für die App-Öffnen-Website
DFX-Annahme:https://app.realunit.ch/open
DAS / RealUnit-App-Team muss bestätigen:
Domain (vielleicht auch realunit.app oder app.realunit.swiss)
Pfad (/open oder ein anderer)
Optional: Query-Parameter pro Mail-Kontext (z. B. ?action=tx&id={txId} für Verkauf-Tx, ?action=verification für KYC)
9. „Prüfen ob vorhanden:" — Schluss aus Original v1.0
DAS-Doc v1.0 endet mit "…. Prüfen ob vorhanden:" — eine angefangene, nicht ausgefüllte Liste. Welche Templates wollte DAS hier noch ergänzen?
Mögliche fehlende Templates aus DFX-Standard, die für RealUnit relevant sein könnten:
Login per Magic-Link
Account-Deactivation-Bestätigung
Limit-Request-Genehmigung
Empfehlungs-Mails (Recommendation)
→ Bei DAS nachfragen, welche zusätzlichen Trigger er noch beschreiben wollte.
10. v1.2-Doc an DAS
Begleit-Dokument zu diesem PR aufsetzen mit:
Allen Korrekturen gegenüber v1.0 (Tippfehler, Begriffsdifferenzierung, Slot-Umwidmung)
Trigger-Mapping pro Template (Tabelle DFX-Event ↔ DAS-Nummer)
Offenen Punkten 8 + 9
Hinweis auf Implementation-Stand: „Code in feat/realunit-mail-template, Preview-HTMLs unter scripts/email-previews/realunit/, ausführbar mit node scripts/generate-realunit-previews.js"
⚠️ Aktueller Blocker
macOS TCC blockiert Lese- und Schreibzugriff auf das lokale Repo. Mein Bash- und Edit-Tooling bekommt Operation not permitted (Errno 1). Bestätigt durch:
cat, head, python3 open(), node fs.readFileSync(), perl open — alle scheitern mit demselben Fehler
dangerouslyDisableSandbox: true ändert nichts (TCC ist OS-Layer, nicht Tool-Layer)
stat funktioniert (nur Metadata) → Filesystem-Permissions sind normal (0644, owner cyrilthommen)
Fix: Full Disk Access für die Claude-Code-App in System Settings → Privacy & Security neu erteilen, dann Claude Code neu starten.
DFX-Server-Konfig: env-Var REALUNIT_MAIL_USER + REALUNIT_MAIL_PASS müssen auf DEV + PRD gesetzt sein, damit Config.mail.wallet.RealUnit aktiv wird (siehe src/config/config.ts:630)
Kontext
Aufsetzung wallet-spezifischer Mail-Vorlagen für die RealUnit App, basierend auf den von DAS gelieferten Textvorlagen (Doc v1.0 vom 1.4.26).
feat/realunit-mail-templateWas bereits implementiert ist (Stand 29.4.26)
wir→wird,Verizierung→Verifizierung,erfolgreicht→erfolgreich,Verkaufauftrag→Verkaufsauftrag,Möglich→möglich, fehlendesdain Kraken exchange service #12 ergänzt)mail.X→mail-realunit.X).body-Key vom Title-Key ab und prepended ihn vor die regulären Textsmail-realunit.json(DE) mit Overrides für payment, kyc, pending, chargeback, recommendation, account_merge, login, verification_code, support_message, account_deactivation, limit_requestrealunit.hbsTemplate mit RealUnit-Branding:#F5F7F8) statt DFX-Dunkellilahttps://app.dfx.swiss/support) entfernt (Commit672219af9)general.support/thanks/team_questions/linksind leer im RealUnit-Overrideconfig.ts:mail.wallet.RealUnit.template = 'realUnit'scripts/generate-realunit-previews.js(Commite24a2cecd) generiert 38 HTML-Mails + Index nachscripts/email-previews/realunit/🔴 Offene Code-Änderungen
1.
info@realunit.chkomplett entfernen — Begründung: „nur In-App-Support"RealUnit-Wunsch: Kunden sollen ausschliesslich über den In-App-Support-Bereich gehen, keine Mail-Adresse als Eskalationsweg.
1a. Hardcoded Support-Block in
realunit.hbsAktueller Block:
```html
Sollten Sie Fragen haben, steht Ihnen das RealUnit-Team gerne unter info@realunit.ch zur Verfügung.
\`\`\`→ kompletten Support-Block entfernen (zwischen `{{!-- Support Block --}}` und dem Closing-Block).
1b.
verification_code.closinginmail-realunit.jsonAktuell:
```
"...kontaktieren Sie bitte unverzüglich den Support unter [mail:info@realunit.ch]."
```
→ Ändern zu In-App-Verweis, z. B.:
```
"...kontaktieren Sie bitte unverzüglich den Support in der RealUnit App unter Menü → Support."
```
Akzeptanzkriterium: Kein einziger `info@realunit.ch`-Link in den 38 generierten Preview-HTMLs (grep nach `mailto:info@realunit.ch` und `info@realunit.ch` ergibt 0 Treffer).
2. App-Öffnen-Button mit Link auf RealUnit-Website
Architektur-Entscheidung (mit User-Bestätigung): Es gibt eine extra Website, die das App-Öffnen handhabt (Universal Links / App Links / App-Store-Fallback). Die DFX-API verlinkt einfach diese URL — keine Deep-Link-Logik im API-Code.
Annahme zur URL:
https://app.realunit.ch/open(DAS muss bestätigen, siehe §Klärungen)Implementation:
realunit.hbszwischen{{#each texts}}und{{!-- Closing Block --}}mit fest verdrahtetem Link-Button "App öffnen".btn-Class (blau#1988C6)[url:https://app.realunit.ch/open]-Marker, der per Body-Text-Injection als Button gerendert wirdAkzeptanzkriterium: Mindestens die Mails #1 (Kauf abgeschlossen), #17 (Verkauf abgeschlossen) zeigen einen klickbaren "App öffnen"-Button mit Link auf die RealUnit-App-Website.
3. Disclaimer-Footer „Dies ist eine automatisierte Mail…"
Im Original v1.0 stand dieser Disclaimer nur in #1. Logisch sollte er in jeder Mail stehen, weil keine Antwort erwartet/verarbeitet wird.
Implementation:
realunit.hbsdirekt oberhalb des{{!-- Footer Legal Block --}}(also vor Adresse/Datenschutz/Impressum)font-size: 11px), Grauton (#6B7280), zentriertAkzeptanzkriterium: In allen 38 Preview-HTMLs steht der Disclaimer-Text vor dem Legal-Footer.
4. RealUnit-Wallet-Config: nicht-anwendbare Mail-Typen deaktivieren
DAS hat in v1.0 explizit zwei Mail-Typen abgelehnt bzw. infrage gestellt:
4a. #13 „Aktion ausstehend" — DAS-Zitat: „In welchem Fall kann diese Mail bei uns erfolgen? So unspezifische Mails möchte ich nicht versenden!"
→ Eindeutige Ablehnung.
4b. #6 „Problem bei der Einzahlung" — DAS-Zitat: „Annahme: Mail sollte ja gar nicht zur Anwendung kommen, da erst nach vollständigem KYC der Kunde Token kaufen kann, oder?"
→ DAS war unsicher („oder?"). DFX-Vorschlag: deaktivieren, weil bei nur SEPA/SIC mit verifiziertem Kunden-IBAN dieser Trigger faktisch wegfällt. Edge-Cases (Rücklastschrift Wochen später) laufen über manuellen Support.
Implementation: Auf RealUnit-Wallet-DB-Eintrag das Feld
disabledMailTypessetzen mit den entsprechendenMailContextType-Werten:MailContextTypeMapperprüfen)MailContextfür „Problem bei Einzahlung" steht — ggf. nicht im DFX-Standardset, dann entfällt 4b automatischAkzeptanzkriterium: Auf DEV-Umgebung Trigger #13 manuell auslösen für RealUnit-Testuser → keine Mail wird versendet. Logs zeigen
isDisabledMailWallet === true.🟡 Doku & PR-Verwaltung
5. PR #3598 Body um Slot-Umwidmung #17 ergänzen
Hintergrund: DAS hat im Original-Doc drei Slots als „Guthaben wurde erstattet" betitelt (#12, #15, #17). Der Slot-Titel kommt vermutlich aus einer DFX-Default-Liste, aber DAS hat die jeweiligen Betreffe bewusst überschrieben:
BUY_FIAT_RETURN(limit)BUY_FIAT_RETURN(unavailable)BUY_FIAT_COMPLETED← Slot-Umwidmung!→ DAS hat absichtlich den DFX-„Guthaben erstattet"-Slot für eine Verkauf-erfolgreich-Mail umgewidmet.
Das im PR-Body explizit erwähnen, damit Reviewer verstehen, warum
payment.fiat_output.bodyeinen so DAS-spezifischen Text hat (Bestätigung der Banküberweisung) statt den DFX-Default-Wortlaut.6. PR #3598 von DRAFT auf READY
Sobald 1–5 erledigt + Smoke-Test auf DEV bestanden.
🟢 Preview-Script-Erweiterung
7. Trigger-Erklärung pro Mail im HTML-Output
Anforderung von Cyrill (29.4.26): Pro generierter Mail im HTML-Output soll ein ausführlicher Text stehen, der erklärt, wann diese Mail versendet wird.
Begründung: DAS' originale Forderung Nr. 1: „Klare Erklärung wann eine Mail gesendet wird!" — bislang nur als Tabelle im v1.1-Begleitdokument vorhanden, nicht in den HTML-Previews selbst.
Implementation:
scripts/generate-realunit-previews.jspro Mail-Definition ein FeldtriggerExplanationmit ~3–5 SätzenBUY_CRYPTO_COMPLETED)PROCESSING → COMPLETE)Beispiel (Mail #1 Kauf abgeschlossen):
Akzeptanzkriterium: Alle 38 Mails haben eine Trigger-Erklärung, die ohne Code-Wissen verständlich ist.
🟢 Klärungen mit DAS / RealUnit
8. Finale URL für die App-Öffnen-Website
DFX-Annahme:
https://app.realunit.ch/openDAS / RealUnit-App-Team muss bestätigen:
realunit.appoderapp.realunit.swiss)/openoder ein anderer)?action=tx&id={txId}für Verkauf-Tx,?action=verificationfür KYC)9. „Prüfen ob vorhanden:" — Schluss aus Original v1.0
DAS-Doc v1.0 endet mit "…. Prüfen ob vorhanden:" — eine angefangene, nicht ausgefüllte Liste. Welche Templates wollte DAS hier noch ergänzen?
Mögliche fehlende Templates aus DFX-Standard, die für RealUnit relevant sein könnten:
→ Bei DAS nachfragen, welche zusätzlichen Trigger er noch beschreiben wollte.
10. v1.2-Doc an DAS
Begleit-Dokument zu diesem PR aufsetzen mit:
feat/realunit-mail-template, Preview-HTMLs unterscripts/email-previews/realunit/, ausführbar mitnode scripts/generate-realunit-previews.js"macOS TCC blockiert Lese- und Schreibzugriff auf das lokale Repo. Mein Bash- und Edit-Tooling bekommt
Operation not permitted(Errno 1). Bestätigt durch:cat,head,python3 open(),node fs.readFileSync(),perl open— alle scheitern mit demselben FehlerdangerouslyDisableSandbox: trueändert nichts (TCC ist OS-Layer, nicht Tool-Layer)statfunktioniert (nur Metadata) → Filesystem-Permissions sind normal (0644, ownercyrilthommen)Fix: Full Disk Access für die Claude-Code-App in System Settings → Privacy & Security neu erteilen, dann Claude Code neu starten.
🔵 Aufräumen
11. Lokalen Branch
feat/realunit-mail-templates(Plural) löschenÜbrig geblieben aus dem Doppel-PR-Versuch:
```bash
cd ~/Documents/GitHub/dfx/api && git branch -D feat/realunit-mail-templates
```
Remote-Branch wurde beim Schließen von PR #3639 bereits gelöscht.
Vorgeschlagene Reihenfolge der Umsetzung
feat/realunit-mail-template)npm run format:check && npm run type-check && npm run lint && node scripts/generate-realunit-previews.jsZusammenhang zu anderen Repos / Tasks
apple-app-site-association,assetlinks.json)REALUNIT_MAIL_USER+REALUNIT_MAIL_PASSmüssen auf DEV + PRD gesetzt sein, damitConfig.mail.wallet.RealUnitaktiv wird (siehesrc/config/config.ts:630)