11 KiB
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.mdAD-10): Das HiveGrid-UI-Paket heißt realpackages/ui-app(nichtpackages/ui-hivegrid). Die Sidebar-Konfiguration liegt inapps/web/app/application/sidebar/(nichtsidebar.config.ts). Der Such-Index /indexedEntitiesgehört nachpackages/search/(nichtpackages/db/src/search/indexed-entities.ts). Geteilte Pakete bleiben@toolctrl/*; neue HiveGrid-Querschnittsdienste (z.B. Activity/logActivity) werden als neues@hivegrid/*-Paket angelegt. Lies dieui-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.
// 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:
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:
import { auditEvent } from '@hivegrid/audit';
await auditEvent({ ... });
7. Notification-Wiring (M011)
Wenn ein Modul Mitarbeiter benachrichtigen soll: NIE direkt Email/Push senden. Immer:
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:
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:
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:
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).