From 1cb99f8639e214314fcde6775fb639ebd3d2f3c9 Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Sun, 12 Apr 2026 14:05:11 +0200
Subject: [PATCH] l18n fixes
---
d-guides/coding-conventions.md | 70 ++++++++++++----
d-guides/unused-api-endpoints.md | 140 +++++++++++++++++++++++++++++++
2 files changed, 192 insertions(+), 18 deletions(-)
create mode 100644 d-guides/unused-api-endpoints.md
diff --git a/d-guides/coding-conventions.md b/d-guides/coding-conventions.md
index 16e0ece..f5f0ff6 100644
--- a/d-guides/coding-conventions.md
+++ b/d-guides/coding-conventions.md
@@ -1,5 +1,5 @@
-
+
# Coding-Konventionen
@@ -10,6 +10,23 @@
- **PascalCase** fuer Klassen und Pydantic-Models
- Dateien: `camelCase` fuer Module (z.B. `mainServiceAi.py`, `routeBilling.py`)
+## i18n Grundprinzip: Uebersetzen an der Quelle
+
+Jeder Text wird **an der Quelle** uebersetzt. Backend-Strings werden im Backend uebersetzt, Frontend-Strings im Frontend. Der Empfaenger rendert direkt — keine doppelte Uebersetzung, keine Checks.
+
+**Backend liefert IMMER in der korrekten Sprache.** Das Frontend muss nichts pruefen oder nochmals uebersetzen.
+
+| Text-Quelle | Wer uebersetzt | Empfaenger |
+|---|---|---|
+| Frontend-Komponente (Button, Label, h1) | Frontend: `t('Speichern')` | rendert direkt |
+| Backend statische Struktur (Navigation, Katalog) | Backend: `t()` registriert Key, `resolveText()` liefert zur Request-Zeit | Frontend: `item.uiLabel` direkt rendern |
+| Backend API-Response (Fehlermeldung, Erfolg) | Backend: `t("Zugriff verweigert")` | Frontend: `error.detail` direkt rendern |
+| Backend DB-Wert (TextMultilingual) | Backend: `resolveText(role.description)` | Frontend: `role.description` direkt rendern |
+
+**Kernregel:** Strings vom Backend sind **immer bereits uebersetzt**. Das Frontend darf `t()` **nie** auf Backend-Werte anwenden — weder `t(item.label)` noch `t(variable)`. Keine `typeof === 'object'` Checks, keine Fallback-Ketten. Nur eigene Frontend-Literale wie `t('Speichern')`.
+
+**Redundanz vermeiden:** Derselbe Text darf nicht an zwei Stellen mit `t()` getaggt werden.
+
## Frontend (React/TypeScript)
- Keine Browser-Dialoge (`alert`, `confirm`, `prompt`) -- stattdessen `useConfirm()` / `usePrompt()` Hooks
@@ -37,7 +54,18 @@ t('Offen (Status)') // vs. t('Offen (Zustand)')
```
- **Key = deutscher Klartext** (kein Dot-Notation-Schema)
-- **`t()` NUR mit String-Literalen** — `t(variable)` ist verboten. Backend-Werte (feature.label, role.description etc.) sind bereits uebersetzt und werden direkt gerendert.
+- **`t()` NUR mit String-Literalen** — `t(variable)` ist verboten. Backend-Werte (Navigation-Labels, Feature-Labels, Role-Descriptions etc.) sind bereits uebersetzt und werden direkt gerendert:
+
+```tsx
+// FALSCH - Backend-Wert nochmal durch t()
+label: t(item.uiLabel) // Backend hat schon uebersetzt!
+{t(plan.title)}
// Backend hat schon uebersetzt!
+
+// RICHTIG - Backend-Wert direkt rendern
+label: item.uiLabel
+{plan.title}
+```
+
- Fuer statische Frontend-Maps (Wochentage, Monatsnamen, Status-Labels) wird `t()` per `switch`-Funktion mit Literalen aufgerufen, nicht ueber Map-Lookup:
```tsx
@@ -86,29 +114,35 @@ return {"message": t("Datei erfolgreich hochgeladen", "api.routeFiles",
**Nicht** mit `t()` taggen: Log-Eintraege, AI-Prompts, interne technische Fehlermeldungen.
-### Statische Dicts mit i18n-Keys: t() auf Modul-Ebene registrieren
+### Statische Dicts mit i18n-Keys: t() registriert, resolveText() liefert
-Wenn ein Modul statische Dicts/Listen mit UI-sichtbaren Texten definiert (z.B. `BADGE_DEFINITIONS`, Level-Labels), muessen die Keys **auf Modul-Ebene** via `t()` registriert werden. Nur so erscheinen sie im `xx`-Basisset und koennen uebersetzt werden.
+Statische Dicts (Navigation, Kataloge) haben **zwei Schritte**:
+
+1. **Import-Zeit:** `t()` im Dict **registriert** den Key (und gibt den deutschen String zurueck, der im Dict gespeichert wird)
+2. **Request-Zeit:** `resolveText()` in der Route nimmt den deutschen String und liefert die Uebersetzung fuer die aktuelle Sprache
```python
+# mainSystem.py — t() registriert Keys bei Import-Zeit
from modules.shared.i18nRegistry import t
-# Alle Keys auf Modul-Ebene mit t("...") registrieren (Import-Zeit), siehe z.B. CommCoach BADGE_DEFINITIONS
-
-# Dict mit deutschen Quelltexten als Strings (NICHT t() im Dict!)
-BADGE_DEFINITIONS = {
- "first_session": {"label": "Erste Session", "icon": "star"},
- "streak_3": {"label": "3-Tage-Serie", "icon": "fire"},
-}
-
-# Runtime: resolveText (nicht t(variable))
-from modules.shared.i18nRegistry import resolveText
-
-def getBadgeDefinitions():
- return {k: {**v, "label": resolveText(v["label"])} for k, v in BADGE_DEFINITIONS.items()}
+NAVIGATION_SECTIONS = [
+ {"title": t("Meine Sicht"), "items": [
+ {"label": t("Uebersicht"), "objectKey": "ui.system.home", ...},
+ ]},
+]
```
-**Warum?** `t()` registriert Keys nur beim ersten Aufruf. Wenn `t()` nur in einer Funktion steht, wird der Key erst beim ersten Request registriert -- **nach** dem Boot-Sync. Der Key fehlt dann im `xx`-Set und kann nicht uebersetzt werden.
+```python
+# routeSystem.py — resolveText() uebersetzt zur Request-Zeit
+from modules.shared.i18nRegistry import resolveText
+
+def _formatBlockItem(item):
+ return {"uiLabel": resolveText(item["label"]), ...}
+```
+
+**Warum zwei Schritte?** `t()` wird bei Import-Zeit ausgewertet — der Rueckgabewert ist immer deutsch (Default-Sprache). Der Wert im Dict ist daher ein fester deutscher String. `resolveText()` nimmt diesen deutschen String zur Request-Zeit und liefert die korrekte Uebersetzung.
+
+**Warum Modul-Ebene?** `t()` registriert Keys nur beim ersten Aufruf. Wenn `t()` nur in einer Funktion steht, wird der Key erst beim ersten Request registriert — **nach** dem Boot-Sync. Der Key fehlt dann im `xx`-Set und kann nicht uebersetzt werden.
### TextMultilingual-Felder: Backend loest auf via resolveText()
diff --git a/d-guides/unused-api-endpoints.md b/d-guides/unused-api-endpoints.md
new file mode 100644
index 0000000..2f6a838
--- /dev/null
+++ b/d-guides/unused-api-endpoints.md
@@ -0,0 +1,140 @@
+
+
+
+# Ungenutzte API-Endpunkte — Kandidaten zum Loeschen
+
+Analyse vom 2026-04-12. Geprueft gegen:
+- `frontend_nyla/src/` (UI)
+- `service-teams-browser-bot/` (Teams Bot)
+- `private-llm/` (Private LLM)
+
+Keiner dieser Endpunkte wird in irgendeinem der drei Repos referenziert.
+
+---
+
+## Komplett ungenutzte Route-Module
+
+### `routeMessaging.py` — 14 Endpunkte (alle loeschen)
+
+| Method | Path | Funktion |
+|--------|------|----------|
+| GET | `/api/messaging/subscriptions` | Subscriptions auflisten |
+| POST | `/api/messaging/subscriptions` | Subscription erstellen |
+| GET | `/api/messaging/subscriptions/{id}` | Subscription abrufen |
+| PUT | `/api/messaging/subscriptions/{id}` | Subscription aktualisieren |
+| DELETE | `/api/messaging/subscriptions/{id}` | Subscription loeschen |
+| GET | `/api/messaging/subscriptions/{id}/registrations` | Registrierungen auflisten |
+| POST | `/api/messaging/subscriptions/{id}/subscribe` | Registrierung erstellen |
+| DELETE | `/api/messaging/subscriptions/{id}/unsubscribe` | Abmelden |
+| GET | `/api/messaging/registrations` | Alle Registrierungen |
+| PUT | `/api/messaging/registrations/{id}` | Registrierung aktualisieren |
+| DELETE | `/api/messaging/registrations/{id}` | Registrierung loeschen |
+| POST | `/api/messaging/trigger/{id}` | Subscription ausloesen |
+| GET | `/api/messaging/deliveries` | Zustellungen auflisten |
+| GET | `/api/messaging/deliveries/{id}` | Zustellung abrufen |
+
+### `routeSecurityAdmin.py` — 9 Endpunkte (alle loeschen)
+
+| Method | Path | Funktion |
+|--------|------|----------|
+| GET | `/api/admin/tokens` | Token/Sessions auflisten |
+| POST | `/api/admin/tokens/revoke/user` | Tokens per User widerrufen |
+| POST | `/api/admin/tokens/revoke/session` | Session widerrufen |
+| POST | `/api/admin/tokens/revoke/id` | Token per ID widerrufen |
+| POST | `/api/admin/tokens/revoke/mandate` | Tokens per Mandate widerrufen |
+| GET | `/api/admin/databases` | Datenbanken auflisten |
+| GET | `/api/admin/databases/{name}/tables` | Tabellen auflisten |
+| POST | `/api/admin/databases/{name}/tables/{table}/drop` | Tabelle loeschen |
+| POST | `/api/admin/databases/drop` | Datenbank loeschen |
+
+### `routeAdminRbacExport.py` — 4 Endpunkte (alle loeschen)
+
+| Method | Path | Funktion |
+|--------|------|----------|
+| GET | `/api/rbac/export/global` | Globale RBAC exportieren |
+| POST | `/api/rbac/import/global` | Globale RBAC importieren |
+| GET | `/api/rbac/export/mandate` | Mandate RBAC exportieren |
+| POST | `/api/rbac/import/mandate` | Mandate RBAC importieren |
+
+---
+
+## Teilweise ungenutzte Route-Module
+
+### `routeVoiceGoogle.py` — 8 Endpunkte loeschen
+
+Genutzt werden: `GET /languages`, `GET /voices`, `POST /stt/token`.
+
+| Method | Path | Funktion |
+|--------|------|----------|
+| POST | `/voice-google/speech-to-text` | Audio STT |
+| POST | `/voice-google/detect-language` | Sprache erkennen |
+| POST | `/voice-google/translate` | Text uebersetzen |
+| POST | `/voice-google/realtime-interpreter` | Interpreter-Pipeline |
+| POST | `/voice-google/text-to-speech` | TTS |
+| GET | `/voice-google/health` | Health Check |
+| GET | `/voice-google/settings` | Voice-Einstellungen lesen |
+| POST | `/voice-google/settings` | Voice-Einstellungen speichern |
+
+### `routeClickup.py` — 10 Endpunkte loeschen
+
+Genutzt werden: `GET /{id}/tasks/{taskId}`, `GET /{id}/lists/{listId}`, `GET /{id}/teams/{teamId}`, `GET /{id}/lists/{listId}/fields`, `GET /{id}/lists/{listId}/tasks`.
+
+| Method | Path | Funktion |
+|--------|------|----------|
+| GET | `/api/clickup/{id}/teams` | Teams auflisten |
+| GET | `/api/clickup/{id}/teams/{teamId}/spaces` | Spaces auflisten |
+| GET | `/api/clickup/{id}/spaces/{spaceId}/folders` | Folders auflisten |
+| GET | `/api/clickup/{id}/spaces/{spaceId}/lists` | Listen in Space |
+| GET | `/api/clickup/{id}/folders/{folderId}/lists` | Listen in Folder |
+| GET | `/api/clickup/{id}/teams/{teamId}/tasks/search` | Tasks suchen |
+| GET | `/api/clickup/{id}/user` | ClickUp User |
+| POST | `/api/clickup/{id}/lists/{listId}/tasks` | Task erstellen |
+| PUT | `/api/clickup/{id}/tasks/{taskId}` | Task aktualisieren |
+| DELETE | `/api/clickup/{id}/tasks/{taskId}` | Task loeschen |
+
+### `routeSharepoint.py` — 3 Endpunkte loeschen
+
+Genutzt wird: `GET /api/sharepoint/folder-options` (ohne connectionId).
+
+| Method | Path | Funktion |
+|--------|------|----------|
+| GET | `/api/sharepoint/{id}/sites` | SharePoint Sites |
+| GET | `/api/sharepoint/{id}/sites/{siteId}/folders` | Folders unter Site |
+| GET | `/api/sharepoint/{id}/folder-options` | Folder-Optionen (mit connectionId) |
+
+### `routeFeatureGraphicalEditor.py` — 5 Endpunkte loeschen
+
+| Method | Path | Funktion |
+|--------|------|----------|
+| GET | `/api/workflows/{id}/info` | Workflow-Engine Info |
+| POST | `/api/workflows/{id}/schedule-sync` | Schedule-Trigger sync |
+| POST | `/api/workflows/{id}/workflows/{wfId}/webhooks/{epId}` | Webhook registrieren |
+| POST | `/api/workflows/{id}/workflows/{wfId}/forms/{epId}/submit` | Formular-Submit |
+| POST | `/api/workflows/{id}/runs/{runId}/resume` | Pausierten Run fortsetzen |
+
+---
+
+## Einzelne ungenutzte Endpunkte
+
+| Route-Datei | Method | Path | Funktion |
+|-------------|--------|------|----------|
+| `routeAdminRbacRules.py` | GET | `/api/rbac/catalog/stats` | RBAC Katalog-Statistiken |
+| `routeI18n.py` | GET | `/api/i18n/user-language-options` | Sprach-Optionen fuer User |
+| `routeI18n.py` | PUT | `/api/i18n/sets/update-all` | Alle Sprachsets aktualisieren |
+| `routeSecurityGoogle.py` | GET | `/api/google/config` | Google OAuth Config |
+| `routeSecurityGoogle.py` | POST | `/api/google/verify` | Token-Verifikation |
+| `routeSecurityMsft.py` | POST | `/api/msft/cleanup` | MSFT Auth Cleanup |
+| `routeAdminUserAccessOverview.py` | GET | `/api/admin/user-access-overview/{userId}/effective-permissions` | Effektive Berechtigungen |
+| `routeDataFiles.py` | GET | `/api/files/stats` | Datei-Statistiken |
+| `routeBilling.py` | GET | `/api/billing/admin/transactions/{id}/filter-values` | Filter-Werte Admin-Transaktionen |
+
+---
+
+## Zusammenfassung
+
+| Kategorie | Endpunkte |
+|-----------|-----------|
+| Komplett ungenutzte Module | 27 |
+| Teilweise ungenutzte Module | 26 |
+| Einzelne Endpunkte | 9 |
+| **Total** | **62** |