239 lines
11 KiB
Markdown
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).
|