Files
HiveGrid-Wireframes/hivegrid-cloud/docs/INTEGRATION-CONTRACTS.md
T

239 lines
11 KiB
Markdown

# HiveGrid Integration-Contracts
**Zweck:** Verbindliche Docking-Points, an denen jedes neue Modul anschließt. Wenn ein AI-Coding-Agent eine Funktion baut, ohne sie hier anzudocken, ist die Funktion **nicht erreichbar** und das Milestone gilt als nicht erledigt.
Diese Datei ist Quelle der Wahrheit für: Sidebar-Gruppen, Route-Patterns, Breadcrumbs, Permissions, Search-Index, Activity-Stream, Audit, i18n.
> **Naming-/Pfad-Realität (Stand 2026-06-04, siehe `docs/ARCHITECTURE-DECISIONS.md` AD-10):**
> Das HiveGrid-UI-Paket heißt real **`packages/ui-app`** (nicht `packages/ui-hivegrid`). Die
> Sidebar-Konfiguration liegt in **`apps/web/app/application/sidebar/`** (nicht `sidebar.config.ts`).
> Der Such-Index / `indexedEntities` gehört nach **`packages/search/`** (nicht
> `packages/db/src/search/indexed-entities.ts`). Geteilte Pakete bleiben `@toolctrl/*`; neue
> HiveGrid-Querschnittsdienste (z.B. Activity/`logActivity`) werden als neues `@hivegrid/*`-Paket
> angelegt. Lies die `ui-hivegrid`/`@hivegrid/*`/`sidebar.config.ts`-Erwähnungen unten entsprechend.
## 1. App-Shell-Sidebar (Mandanten-App `app.hivegrid.de`)
Sidebar ist in 6 feste Gruppen geteilt. Jede neue Funktion gehört in **genau eine** Gruppe:
```
🏢 ARBEITEN
├─ Dashboard → M147-M150
├─ Globale Suche (Cmd-K) → M058
├─ Lead-Inbox → M047-M051
├─ Verkaufsfälle (Sales) → M059-M064
├─ Aufträge (Projekte) → M065-M070
├─ Aufgaben → M071-M074
├─ Termine → M120
└─ Buchungs-Seiten → M126-M129
📇 STAMMDATEN
├─ Kontakte → M042-M046
├─ Firmen → M042-M046
├─ Dateien → M052-M055
├─ Tags / Schlagwörter → M044
└─ Custom-Felder → M044
📨 KOMMUNIKATION
├─ Email-Inbox → M096-M099
├─ Marketing-Kampagnen → M100-M104
├─ Telefonie → M105-M109
├─ Team-Chat → M110-M114
└─ Notification-Center (Glocke) → M115-M117
⚙️ AUTOMATION & KI
├─ Automation-Studio → M075-M082
├─ KI-Sprach-Assistent → M086
└─ Vorlagen / Templates → M082
👥 PERSONAL (HR-Hub)
├─ Schwarzes Brett → M137
├─ Mitarbeiter-Verzeichnis → M133
├─ Urlaub / Krankheit → M135, M136
├─ Lohnabrechnungen → M134
├─ Anträge → M139
└─ Passwort-Safe → M134
🛠️ EINSTELLUNGEN (Mandanten-Admin)
├─ Mandant (Stammdaten) → M018
├─ Mitarbeiter & Rollen → M023, M024
├─ Pipelines → M059, M065
├─ Forms → M121-M125
├─ Integrationen (Apps) → M008-M010
├─ KWP-Verbindung → M089-M095
├─ Audit-Log → M151
├─ Subscription / Abo → M153-M156
├─ Branding / Design → M030
└─ DSGVO / Datenschutz → M164-M166
```
**Plattform-Admin-App `admin.hivegrid.de`** hat eine separate Sidebar-Struktur (siehe M034-M041).
**Customer-Portal** hat eigene minimale Navigation (siehe M141-M146).
**Mobile-App-Tab-Bar** ist UI-Modus-abhängig — siehe M169.
## 2. Sidebar-Wiring-Pflicht
Jeder neue Modul-Bereich muss in `packages/ui-hivegrid/src/app-shell/sidebar.config.ts` registriert werden. Das ist die **einzige** Quelle der Wahrheit für Sidebar-Inhalte.
```ts
// packages/ui-hivegrid/src/app-shell/sidebar.config.ts
export type SidebarEntry = {
id: string; // eindeutig, kebab-case
group: 'arbeiten' | 'stammdaten' | 'kommunikation' | 'automation-ki' | 'personal' | 'einstellungen';
label: string; // i18n-Key, kein Hardcoded-String
icon: string; // lucide-react Icon-Name
route: string; // RR7-Route-Pattern
permission: string | string[]; // Permission-Key aus M004; Eintrag nur sichtbar wenn berechtigt
badge?: 'count' | 'dot' | null; // Live-Counter (z.B. ungelesene Mails)
order: number; // Sortierung innerhalb der Gruppe
feature_flag?: string; // optional: Sidebar-Eintrag nur sichtbar wenn Flag aktiv
};
```
**Regel:** Eine neue Funktion ohne Sidebar-Eintrag (oder ohne Inline-Verlinkung aus einem bestehenden Modul) wird **nicht akzeptiert**.
## 3. Route-Patterns
Verbindliche URL-Schemata. Abweichungen erfordern Change-Request.
| Bereich | Pattern | Beispiel |
|---|---|---|
| Mandanten-App | `app.hivegrid.de/<modul>/...` | `app.hivegrid.de/sales/D-2026-0042` |
| Mandant-Settings | `app.hivegrid.de/settings/<modul>/...` | `app.hivegrid.de/settings/integrationen/kwp` |
| Plattform-Admin | `admin.hivegrid.de/<bereich>/...` | `admin.hivegrid.de/mandanten/123` |
| Customer-Portal | `app.hivegrid.de/portal/<tenant>/...` | `app.hivegrid.de/portal/geerkens/projekte/42` |
| Public-Forms | `app.hivegrid.de/f/<tenant>/<slug>` | `app.hivegrid.de/f/geerkens/kontaktformular` |
| Public-Booking | `app.hivegrid.de/b/<tenant>/<slug>` | `app.hivegrid.de/b/geerkens/wartungstermin` |
| Public-Help | `app.hivegrid.de/help/<lang>/<kategorie>/<slug>` | `app.hivegrid.de/help/de/integrationen/kwp-setup` |
| Public-API | `app.hivegrid.de/api/v1/<resource>` | `app.hivegrid.de/api/v1/contacts` |
| **Connector-OAuth-Callback** | `app.hivegrid.de/integrations/<provider>/oauth/callback` | `app.hivegrid.de/integrations/google/oauth/callback` |
Die Tenant-Slug ist **nicht** im Pfad bei der Mandanten-App — Tenant kommt aus Subdomain oder Session.
**Externe OAuth-Connectors (Google-Kalender, KWP, später AirCall/Microsoft/…):** Der Redirect-/Callback-Endpoint
liegt **immer** auf `app.` (nicht `api.`) unter `/integrations/<provider>/oauth/callback` — konsistent zu den
Connector-Settings-Screens (`/settings/integrations/<modul>`, `/integrations/<provider>/…`). Begründung: Der
OAuth-Rückweg ist browser-basiert und braucht die an `app.` gebundene Nutzer-Session, um den Token dem richtigen
Nutzer/Tenant zuzuordnen; `api.hivegrid.de` (token-basiert, ohne Session) ist dafür nicht geeignet. Tenant wird
im OAuth-`state` mitgeführt (eine feste Callback-URL je Umgebung, kein Tenant im Pfad). Pro Umgebung registriert:
`app.hivegrid.de`, `staging-app.hivegrid.de`, `localhost:3000`. Das frühere `/api/apps/<slug>/oauth/callback`
ist abgelöst (2026-06-21).
## 4. Breadcrumbs-Konvention
Jede Detail-Route hat einen Breadcrumb in `packages/ui-hivegrid/src/breadcrumbs/`. Format:
```
[Sidebar-Gruppe] > [Modul] > [Listen-Name] > [Detail-Titel]
```
Beispiel: `Arbeiten > Verkaufsfälle > Anlagen-Verkauf > D-2026-0042 Heizung Schmidt`
## 5. Activity-Stream-Wiring (M045)
Jede schreibende Aktion in jedem Modul muss einen Activity-Stream-Eintrag erzeugen, falls die betroffene Entität einen Stream hat (Kontakt, Firma, Lead, Verkaufsfall, Auftrag).
**Pflicht-Service-Aufruf:**
```ts
import { logActivity } from '@hivegrid/activity';
await logActivity({
tenantId, actorId, actorType: 'user' | 'auto' | 'sync' | 'system',
entityType, entityId,
type: 'contact.created' | 'deal.stage_changed' | ...,
payload: { ... }, // Human-readable Klartext + ggf. Vorher/Nachher
});
```
Der `logActivity`-Aufruf ist NICHT der Audit-Eintrag — der entsteht zusätzlich automatisch via M001 Prisma-Middleware.
## 6. Audit-Wiring (M001)
Audit ist **automatisch** via Prisma-Middleware. Agent muss nichts manuell aufrufen. Wenn etwas im Audit fehlt: Bug in M001-Middleware, nicht im Modul-Code.
**Ausnahme:** Aktionen außerhalb von Prisma (z.B. Datei-Upload zu S3, externe Webhook-Aufrufe) müssen manuell auditiert werden:
```ts
import { auditEvent } from '@hivegrid/audit';
await auditEvent({ ... });
```
## 7. Notification-Wiring (M011)
Wenn ein Modul Mitarbeiter benachrichtigen soll: NIE direkt Email/Push senden. Immer:
```ts
import { notify } from '@hivegrid/notifications';
await notify({
tenantId, recipientId,
category: 'lead.received' | 'deal.won' | ...,
template: 'lead-received', // i18n-Key in M003
payload: { ... },
priority: 'normal' | 'high' | 'urgent',
});
```
Der Notification-Service in M011 entscheidet Kanal (In-App/Email/Push), Bündelung (M117), Stille-Stunden (M116).
## 8. Search-Index-Wiring (M056)
Neue Entität, die in der globalen Suche auftauchen soll, muss in `packages/db/src/search/indexed-entities.ts` registriert sein:
```ts
export const indexedEntities = {
contact: { table: 'Kontakt', searchable: ['displayName', 'email', 'phone'], permission: 'crm.read' },
deal: { table: 'Verkaufsfall', searchable: ['title', 'description'], permission: 'sales.read' },
// ...
};
```
Permission-aware Search (M057) liest diese Map.
## 9. i18n-Wiring (M003)
Alle UI-Texte als i18n-Keys. Locale-Files unter `packages/i18n/src/locales/de/<modul>.json`. ESLint-Rule blockt JSX-Text-Nodes ohne `t()`. Build-Lint blockt Hard-Strings im Build.
Naming: `<modul>.<bereich>.<key>`, z.B. `sales.kanban.empty_state` oder `auth.login.password_too_short`.
## 10. Permission-Keys (M004)
Permission-Definition als TypeScript-Konst in `packages/entitlements/src/permissions.ts`:
```ts
export const Permissions = {
CRM_READ: 'crm.read',
CRM_READ_OWN: 'crm.read_own',
CRM_WRITE: 'crm.write',
SALES_READ: 'sales.read',
SALES_VOLUME_READ: 'sales.volume.read', // separater Key für Volumen-Sichtbarkeit (siehe 3.11.2)
// ...
} as const;
```
Sidebar-Einträge, Routes, View-Models, Actions filtern alle gegen diese Keys.
## 11. View-Model-Pflicht (M013)
JEDE Route in `app/routes/**` baut im Loader ein View-Model. UI-Components in `packages/ui-hivegrid/**` empfangen NUR das VM und Action-Callbacks. Siehe AGENTS.md.
## 12. Smoke-Test pro Route (Pflicht)
Jede neue Route bekommt einen Smoke-Test in `e2e/smoke/<modul>.spec.ts`:
```ts
test('contact-detail loads with view-model', async ({ page }) => {
await loginAs(page, 'geerkens-admin');
await page.goto('/kontakte/test-kontakt-id');
await expect(page.getByRole('heading', { name: /kontakt/i })).toBeVisible();
});
```
Smoke-Tests laufen im Hot-Swap-Drill (M017) gegen `packages/ui-mock` — wenn sie da brechen, ist die Hot-Swap-Architektur verletzt.
## 13. Mobile-Tab-Bar-Wiring (M169)
Neue Funktionen, die in der Mobile-App relevant sind, müssen in `packages/ui-hivegrid/src/mobile/tab-bar.config.ts` für mindestens einen UI-Modus (Baustelle / Büro) registriert sein.
## 14. Customer-Portal-Wiring (M142, M143)
Funktionen, die Endkunden sehen sollen, müssen explizit in `packages/ui-hivegrid/src/customer-portal/portal-shell.config.ts` registriert sein. Default-Sichtbarkeit: **NICHT sichtbar**. Tenant-Admin gibt explizit frei (M142.5).