Sheets via neuer KeyboardAwareSheet-Composable (in Modal pattern, auto-grow mit Tastatur, paddingBottom-Lift): EditMail, AddDomain, CreateRoom, ConnectMail. GameOverScreen behält Spring-Slide-In, nutzt RN Keyboard.addListener für Lift. - KeyboardAwareSheet.tsx — universal modal with sheet-grow + keyboard-padding - react-native-keyboard-controller installiert + KeyboardProvider in Root - Snake: time + ScoreProgressBar + useSnakeSounds (haptic, audio TODO) - Tetris: title weg, Buttons zentriert, kein Pressable mit style-fn - DPad-Buttons 60→48, more bg, no scale - useMe: pub-sub listener pattern für app-weite avatar/nickname-Updates - dm.tsx: resolveAvatar wrap (iron.png-Warning) - Mail-error-humanizer + locales Recovery-Doc-Update in docs/internal/RECOVERY_LOG_2026-05-10.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.5 KiB
MAIL_DAEMON_DEPLOYMENT — Backyard Handoff
Erstellt von: Mo (Mail-Architektur-Agent) Datum: 2026-05-09 Status: Bereit für Deployment — wartet auf Backyard-GO vom User
Kontext
Der rebreak-imap-idle Daemon ist ein eigenständiger Node.js-Prozess.
Er hält pro aktivem MailConnection-DB-Eintrag eine persistente IMAP-IDLE-Session
und triggert bei neuer Mail sofort /api/mail/scan-internal statt auf den 30min-Cron zu warten.
Der Daemon liegt unter backend/imap-idle/index.mjs und hat seine eigene package.json.
Er ist KEIN Teil des Nitro-Builds — er wird direkt via node gestartet.
Was Backyard tun muss (in dieser Reihenfolge)
Schritt 1 — GH-Actions: imap-idle ins Artifact einschließen
In .github/workflows/deploy-backend.yml (oder analog) muss das backend/imap-idle/-Verzeichnis
ins deploy-Artifact aufgenommen werden.
Das Artifact enthält aktuell wahrscheinlich nur backend/.output-staging/ und backend/prisma/.
backend/imap-idle/ muss ebenfalls mit kopiert werden.
Konkretes Beispiel (je nach Artifact-Aufbau anpassen):
# In der scp/rsync-Step des deploy-workflows:
- name: Copy imap-idle to server
run: |
scp -r backend/imap-idle/ rebreak-server:/srv/rebreak/backend/imap-idle/
Schritt 2 — npm install auf Server
Nach dem Artifact-Copy muss auf dem Server npm install in backend/imap-idle/ laufen.
Das installiert imapflow und pg lokal für den Daemon.
cd /srv/rebreak/backend/imap-idle && npm install --production
Diesen Schritt als deploy-Step in GH-Actions oder in deploy-from-artifact.sh ergänzen.
Schritt 3 — Zombie-Prozesse aufräumen
Vor dem ersten Start der neuen pm2-Einträge alte Stale-Einträge entfernen
(falls rebreak-imap-staging oder rebreak-idle-staging aus altem Setup noch existieren):
pm2 delete rebreak-idle-staging rebreak-imap-staging 2>/dev/null || true
Schritt 4 — ecosystem.config.js erweitern
Die folgenden Einträge in /srv/rebreak/ecosystem.config.js ergänzen
(unterhalb des bestehenden rebreak-staging-Eintrags einfügen):
// ─── IMAP IDLE Daemon Staging ───────────────────────────────────────────────
{
name: "rebreak-idle-staging",
script: "/srv/rebreak/backend/imap-idle/index.mjs",
interpreter: "/root/.nvm/versions/node/v24.11.1/bin/node",
cwd: "/srv/rebreak/backend/imap-idle",
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: "256M",
env: {
NODE_ENV: "production",
// ACHTUNG: Keine Secrets hier hinterlegen.
// Infisical-Wrapper via start-idle-staging.sh (Schritt 5).
},
},
// ─── IMAP IDLE Daemon Prod (auskommentiert bis Prod-Cutover) ───────────────
// {
// name: "rebreak-idle-prod",
// script: "/srv/rebreak/backend/imap-idle/index.mjs",
// interpreter: "/root/.nvm/versions/node/v24.11.1/bin/node",
// cwd: "/srv/rebreak/backend/imap-idle",
// instances: 1,
// autorestart: true,
// watch: false,
// max_memory_restart: "256M",
// env: { NODE_ENV: "production" },
// },
Schritt 5 — start-idle-staging.sh erstellen
Der Daemon braucht die gleichen Infisical-Secrets wie das Backend.
Eine eigene Start-Shell analog zu backend/start-staging.sh erstellen:
Pfad: /srv/rebreak/backend/imap-idle/start-idle-staging.sh
#!/bin/bash
# rebreak-imap-idle Staging — Infisical-Secret-Injection
set -euo pipefail
source /etc/environment
if [[ -z "${INFISICAL_CLIENT_ID:-}" || -z "${INFISICAL_CLIENT_SECRET:-}" ]]; then
echo "[idle] FEHLER: INFISICAL_CLIENT_ID / SECRET nicht gesetzt" >&2
exit 1
fi
INFISICAL_TOKEN=$(infisical login \
--method=universal-auth \
--client-id="${INFISICAL_CLIENT_ID}" \
--client-secret="${INFISICAL_CLIENT_SECRET}" \
--silent --plain 2>/dev/null)
[[ -z "$INFISICAL_TOKEN" ]] && { echo "[idle] Infisical login fehlgeschlagen" >&2; exit 1; }
NODE_BIN="/root/.nvm/versions/node/v24.11.1/bin/node"
DAEMON="/srv/rebreak/backend/imap-idle/index.mjs"
exec infisical run \
--projectId="${INFISICAL_PROJECT_ID:-14b11b35-ef59-4b8a-a16b-398f0cc3ad93}" \
--env=staging \
--token="$INFISICAL_TOKEN" \
-- bash -c '
set -e
export DATABASE_URL="${DATABASE_URL:-${NUXT_DATABASE_URL:-}}"
export ADMIN_SECRET="${ADMIN_SECRET:-${NUXT_ADMIN_SECRET:-}}"
export ENCRYPTION_KEY="${ENCRYPTION_KEY:-${NUXT_ENCRYPTION_KEY:-}}"
export BACKEND_URL="http://127.0.0.1:3016"
exec '"$NODE_BIN"' '"$DAEMON"'
'
Dann chmod +x start-idle-staging.sh und in ecosystem.config.js den script-Key
auf start-idle-staging.sh zeigen lassen (mit interpreter: "bash"),
analog zum Pattern von rebreak-staging.
Schritt 6 — pm2 starten
pm2 startOrReload /srv/rebreak/ecosystem.config.js
Verifikations-Schritte nach Deployment
# 1. pm2-Status prüfen
pm2 list
# Erwartung: rebreak-idle-staging → status=online, restart=0
# 2. Logs der ersten 60 Sekunden ansehen
pm2 logs rebreak-idle-staging --lines 100
# Erwartung: "[idle/<email>] connected (...)" für alle aktiven Mailboxen
# "[idle/db] refreshed — N active connections, N sessions"
# 3. Test: Mail an eine verbundene Mailbox schicken (Betreff: "casino bonus")
# Innerhalb von 5 Sekunden sollte im Log erscheinen:
# "[idle/<email>] exists-event received (new mail)"
# "[idle/<email>] scan-triggered → scanned=X blocked=1"
# 4. Memory-Check nach 10 Minuten
pm2 monit
# Erwartung: < 100MB bei <20 Connections, < 200MB bei 100 Connections
Rollback-Plan
Falls der Daemon crashed oder instabil ist:
pm2 stop rebreak-idle-staging
# NICHT delete — damit Logs erhalten bleiben
Auswirkung: Mail-Scanning fällt auf den bestehenden 30min-Cron zurück. Kein Komplett-Ausfall der Mail-Schutz-Funktion. Gambling-Mails werden weiter gelöscht, nur mit bis zu 30min Verzögerung statt Echtzeit.
Bekannte Provider-Quirks
| Provider | IMAP-Host | Port | TLS | Bekanntes Problem |
|---|---|---|---|---|
| Gmail | imap.gmail.com | 993 | Implicit | App-Password erforderlich (kein OAuth2) |
| iCloud | imap.mail.me.com | 993 | Implicit | App-Specific-Password in Apple-Settings |
| Outlook | outlook.office365.com | 993 | Implicit | IDLE-Drop nach ~20min — disableCompression |
| GMX | imap.gmx.net | 993 | Implicit | Stabil, kein besonderer Quirk |
| Web.de | imap.web.de | 993 | Implicit | Stabil |
| T-Online | secureimap.t-online.de | 993 | Implicit | Stabil |
| Posteo | posteo.de | 993 | Implicit | Stabil |
Outlook-spezifisch: Der Daemon setzt disableCompression: true wenn der Host
office365 enthält — verhindert partial-read-Fehler nach IDLE-Drop.
Datei-Übersicht
backend/imap-idle/
index.mjs — Daemon-Hauptdatei (ESM, standalone)
package.json — Eigene Dependencies (imapflow, pg)
README.md — Kurz-Doku (lokal starten, env-vars, log-format)
Abhaengigkeiten
imapflow ^1.2.18— IMAP-Client-Library (bereits in backend/package.json)pg ^8.16.3— Direkter Postgres-Zugriff (kein Prisma im Daemon-Kontext)- Node.js >= 20 (ESM, top-level await via main())
- Infisical-CLI auf dem Server (bereits installiert fuer rebreak-staging)