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** |