diff --git a/repos/INSIGHT-Platform/BRIEFING.md b/repos/INSIGHT-Platform/BRIEFING.md index 19923dd..ff0b440 100644 --- a/repos/INSIGHT-Platform/BRIEFING.md +++ b/repos/INSIGHT-Platform/BRIEFING.md @@ -67,30 +67,78 @@ Folgende Module kannst du 1:1 oder minimal angepasst übernehmen: | MVP-Feature | Grund | |---|---| -| `ExpertProfile` (Skills, Erfahrung, Sprachen) | IT-Berater-Profil für MVP — kein Teil von INSIGHT | -| `ExpertProject` (Projekthistorie) | IT-Berater-Profil für MVP — kein Teil von INSIGHT | -| `ExpertCertification` (Zertifikate) | IT-Berater-Profil für MVP — kein Teil von INSIGHT | -| `ExpertAttachment` (PDF/Word Export) | IT-Berater-Profil für MVP — kein Teil von INSIGHT | -| `ProfileAccessGroup` (Profilzugriff) | IT-Berater-spezifisch — kein Teil von INSIGHT | -| `MasterData` (Departments, Locations, etc.) | MVP-spezifisch — kein Teil von INSIGHT | -| Tab "Experten Profil" im Profil | IT-Berater-Feature — kein Teil von INSIGHT | +| `ProfileAccessGroup` (Gruppen-basierter Profilzugriff) | Wird durch RBAC `moduleRoles.expertprofile` ersetzt | +| `MasterData` (Departments, Locations, CostCenters, etc.) | MVP-spezifisch — kein Teil von INSIGHT | | `AdminProfileAccessPage`, `AdminMasterDataPage` | MVP-spezifisch — kein Teil von INSIGHT | -**Folgende MVP-Features werden übernommen (inkl. Profil-Seite):** +**Folgende MVP-Features werden übernommen:** | Feature | Details | |---|---| -| **Profil-Seite** | Name, Avatar, Kontakt, Adresse, Organisation (4 Felder) | +| **Profil-Seite** | Tabs: Profil \| Experten Profil \| Passwort ändern \| 2FA \| Integrationen | | **"O365 übernehmen"** Button | Einmaliger manueller Import aller Felder aus M365 | -| **Profil-Sync beim Login** | Automatisch: Name, Jobitel, Department, Company aus M365 aktualisieren | +| **Profil-Sync beim Login** | Automatisch: Name, Jobtitel, Department, Company aus M365 | | **Passwort ändern** | Eigenes Passwort mit Verifikation des aktuellen Passworts | | **2FA Tab** | TOTP aktivieren/deaktivieren (nur für lokale Auth-User) | | **Integrationen Tab** | Microsoft 365: verbinden, Status anzeigen, trennen | +| **Experten Profil Tab** (eigenes) | User bearbeitet sein eigenes Experten Profil | +| **ExpertProfile Datenmodell** | Skills, Sprachen, Erfahrung, Projekthistorie, Zertifikate, Anlagen | +| **PDF / Word Export** | Eigenes Profil exportieren | > **Hintergrund Profil-Sync:** Wenn ein User sich via MS SSO einloggt, werden Name, JobTitle, > Department, CompanyName, OfficeLocation automatisch aus dem M365-Token aktualisiert. > Der "O365 übernehmen"-Button ermöglicht zusätzlich den manuellen Sync (Graph API `/me`). -> Das setzt voraus, dass MS SSO konfiguriert ist — ohne SSO nur lokales Profil. + +--- + +## Experten Profile — Eigenständiger Menüpunkt + +**"Experten Profile" ist ein eigener Menüpunkt in der Hauptnavigation** (nicht nur ein persönlicher Tab). + +### Was er leistet: + +| Aktion | Wer darf das | +|---|---| +| Eigenes Experten Profil bearbeiten | Jeder eingeloggte User (im Tab "Experten Profil" seiner Profil-Seite) | +| Alle Profile auflisten und **ansehen** | `moduleRoles.expertprofile: "VIEWER"` oder höher | +| Profile anderer User **bearbeiten** | `moduleRoles.expertprofile: "EDITOR"` oder höher | +| Profile **exportieren** (PDF/Word) | `moduleRoles.expertprofile: "EDITOR"` oder höher | +| Alles + Profil-Zuweisung verwalten | `moduleRoles.expertprofile: "ADMIN"` oder `platformRole: PLATFORM_ADMIN` | + +### RBAC für Experten Profile: + +``` +moduleRoles.expertprofile: + "ADMIN" → vollständiger Zugang, kann alle Profile bearbeiten + exportieren + "EDITOR" → kann alle Profile bearbeiten + exportieren + "VIEWER" → kann alle Profile nur ansehen (kein Export, kein Bearbeiten) + (nicht gesetzt) → nur eigenes Profil über persönliche Profil-Seite +``` + +### UI-Konzept: + +``` +Navigation Sidebar: + └── 📋 Experten Profile (sichtbar für User mit expertprofile-Rolle) + ├── Liste aller User mit Profilvorschau + ├── Klick auf User → vollständiges Profil ansehen + ├── [Bearbeiten]-Button (nur für EDITOR/ADMIN) + └── [PDF Export] / [Word Export] (nur für EDITOR/ADMIN) +``` + +### MVP-Referenzdateien für Experten Profile: + +| MVP-Datei | Für INSIGHT nutzen | +|---|---| +| `packages/core-service/src/core/expert-profile/expert-profile.service.ts` | Experten Profil CRUD | +| `packages/core-service/src/core/expert-profile/expert-profile.controller.ts` | Endpoints | +| `packages/core-service/src/core/expert-profile/profile-export.service.ts` | PDF/Word Export | +| `packages/core-service/prisma/core.schema.prisma` (ExpertProfile-Modelle) | Datenmodell | +| `packages/frontend/src/profile/ProfilePage.tsx` | Eigenes Profil + Experten-Profil-Tab | + +**Anpassung gegenüber MVP:** Im MVP war der Profilzugriff über `ProfileAccessGroup` geregelt +(Gruppen mit `canView`, `canEdit`, `canExport`). In INSIGHT wird das durch +`moduleRoles.expertprofile` ersetzt — einfacher, konsistent mit dem restlichen RBAC-System. --- @@ -152,9 +200,10 @@ model User { createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") - authProvider AuthProvider[] - integrations UserIntegration[] - auditLogs AuditLog[] + authProvider AuthProvider[] + integrations UserIntegration[] + auditLogs AuditLog[] + expertProfile ExpertProfile? @@map("users") } @@ -242,6 +291,106 @@ model AuditLog { @@index([createdAt]) @@map("audit_logs") } + +// -------------------------------------------------------- +// ExpertProfile - Experten-Profil (1:1 mit User) +// -------------------------------------------------------- +model ExpertProfile { + id String @id @default(uuid()) @db.Uuid + userId String @unique @map("user_id") @db.Uuid + + skills String[] @default([]) + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + experiences ExpertExperience[] + languages ExpertLanguage[] + projects ExpertProject[] + certifications ExpertCertification[] + attachments ExpertAttachment[] + + @@map("expert_profiles") +} + +model ExpertExperience { + id String @id @default(uuid()) @db.Uuid + expertProfileId String @map("expert_profile_id") @db.Uuid + area String @db.VarChar(200) + years Int + level String? @db.VarChar(50) + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + expertProfile ExpertProfile @relation(fields: [expertProfileId], references: [id], onDelete: Cascade) + @@map("expert_experiences") +} + +model ExpertLanguage { + id String @id @default(uuid()) @db.Uuid + expertProfileId String @map("expert_profile_id") @db.Uuid + language String @db.VarChar(100) + level String @db.VarChar(20) // Muttersprache, C2, C1, B2, B1, A2, A1 + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + expertProfile ExpertProfile @relation(fields: [expertProfileId], references: [id], onDelete: Cascade) + @@map("expert_languages") +} + +model ExpertProject { + id String @id @default(uuid()) @db.Uuid + expertProfileId String @map("expert_profile_id") @db.Uuid + fromMonth Int @map("from_month") + fromYear Int @map("from_year") + toMonth Int? @map("to_month") + toYear Int? @map("to_year") + isCurrent Boolean @default(false) @map("is_current") + role String @db.VarChar(200) + tasks String? @db.Text + company String? @db.VarChar(200) + companySize String? @map("company_size") @db.VarChar(20) + industry String? @db.VarChar(200) + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + expertProfile ExpertProfile @relation(fields: [expertProfileId], references: [id], onDelete: Cascade) + @@index([expertProfileId, fromYear, fromMonth]) + @@map("expert_projects") +} + +model ExpertCertification { + id String @id @default(uuid()) @db.Uuid + expertProfileId String @map("expert_profile_id") @db.Uuid + title String @db.VarChar(300) + issuingBody String @map("issuing_body") @db.VarChar(300) + website String? @db.VarChar(500) + issueYear Int @map("issue_year") + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + expertProfile ExpertProfile @relation(fields: [expertProfileId], references: [id], onDelete: Cascade) + @@map("expert_certifications") +} + +model ExpertAttachment { + id String @id @default(uuid()) @db.Uuid + expertProfileId String @map("expert_profile_id") @db.Uuid + filename String @db.VarChar(255) + mimetype String @db.VarChar(100) + size Int + data String @db.Text // Base64 + + createdAt DateTime @default(now()) @map("created_at") + + expertProfile ExpertProfile @relation(fields: [expertProfileId], references: [id], onDelete: Cascade) + @@map("expert_attachments") +} ``` --- @@ -250,15 +399,26 @@ model AuditLog { ``` User.platformRole: - PLATFORM_ADMIN → Zugang zum kompletten Admin-Bereich + PLATFORM_ADMIN → Zugang zum kompletten Admin-Bereich + alle Experten Profile USER → Normaler Nutzer -User.moduleRoles (JSON): +User.moduleRoles (JSON-Objekt mit Rollen pro Modul): + + Experten Profile: + { "expertprofile": "ADMIN" } → Alle Profile ansehen + bearbeiten + exportieren + { "expertprofile": "EDITOR" } → Alle Profile ansehen + bearbeiten + exportieren + { "expertprofile": "VIEWER" } → Alle Profile nur ansehen (kein Export, kein Bearbeiten) + (nicht gesetzt) → Nur eigenes Profil über persönliche Profil-Seite + + CRM (Phase 3): { "crm": "ADMIN" } → Admin im CRM-Modul { "crm": "MANAGER" } → Manager im CRM-Modul { "crm": "USER" } → Normaler CRM-Nutzer { "crm": "VIEWER" } → Nur lesen - {} → Kein Zugang zu CRM + (nicht gesetzt) → Kein Zugang zu CRM + + Kombiniert möglich: + { "expertprofile": "EDITOR", "crm": "MANAGER" } ``` **Im JWT-Token** werden beide Felder mitgegeben: @@ -267,7 +427,7 @@ User.moduleRoles (JSON): "sub": "uuid", "email": "user@firma.de", "platformRole": "USER", - "moduleRoles": { "crm": "MANAGER" }, + "moduleRoles": { "expertprofile": "EDITOR", "crm": "MANAGER" }, "jti": "uuid", "iat": 1234567890, "exp": 1234568790 @@ -322,7 +482,13 @@ npx prisma migrate dev --name init 5. `core/auth/sso/` — EntraIdService, SsoController (aus MVP 1:1 übernehmen) 6. `core/users/` — UsersService, UsersController (aus MVP, `moduleRoles` statt `tenantRole`) 7. `core/settings/` — SettingsController (aus MVP, External Links + Branding + Company + SSL + AI-Config) -8. `core/modules/` — NEU: ModuleRegistryService (Module aus DB laden, User-Rollen-Zuweisung) +8. `core/integrations/` — IntegrationsService, IntegrationsController (aus MVP, M365 OAuth2 Tokens) +9. `core/expert-profile/` — ExpertProfileService, ExpertProfileController, ProfileExportService (aus MVP) + - Eigenes Profil bearbeiten: alle authentifizierten User + - Fremde Profile lesen: `moduleRoles.expertprofile` = VIEWER/EDITOR/ADMIN + - Fremde Profile bearbeiten: `moduleRoles.expertprofile` = EDITOR/ADMIN + - Export: `moduleRoles.expertprofile` = EDITOR/ADMIN +10. `core/modules/` — NEU: ModuleRegistryService (Module aus DB laden, User-Rollen-Zuweisung) **4. JWT RS256 Keys generieren:** ```bash @@ -372,21 +538,40 @@ npm install react-hot-toast @heroicons/react 4. `shell/App.tsx` — Routing-Struktur (ohne CRM-Routen — die kommen Phase 3) 5. `shell/AppLayout.tsx` — Haupt-Layout (Sidebar + Topbar + Outlet) 6. `shell/DashboardPage.tsx` — Leeres Dashboard mit Widget-Platzhaltern -7. `profile/ProfilePage.tsx` — Eigenes Profil (aus MVP) -8. `admin/AdminLayout.tsx` — Admin-Navigation (aus MVP, CRM-Settings entfernen) -9. `admin/AdminUsersPage.tsx` — User-Verwaltung + Rollen-Zuweisung (aus MVP erweitern) -10. `admin/AdminSsoPage.tsx` — SSO-Konfiguration (aus MVP 1:1) -11. `admin/AdminCustomizePage.tsx` — Branding (aus MVP 1:1) -12. `admin/AdminExternalLinksPage.tsx` — Externe Links (aus MVP 1:1) -13. `admin/AdminCompanyPage.tsx` — Firmendaten (aus MVP 1:1) -14. `admin/AdminSslPage.tsx` — SSL/Domain (aus MVP 1:1) -15. `admin/AdminAiSettingsPage.tsx` — KI-Einstellungen (aus MVP 1:1) -16. `admin/AdminModulesPage.tsx` — NEU: Modul-Registry (welche Module aktiv) +7. `profile/ProfilePage.tsx` — Eigenes Profil mit Tabs: Profil | Experten Profil | Passwort | 2FA | Integrationen (aus MVP) +8. `expert-profiles/ExpertProfilesPage.tsx` — **NEU**: Menüpunkt "Experten Profile" (Liste aller User-Profile, permission-gesteuert) +9. `expert-profiles/ExpertProfileDetailPage.tsx` — **NEU**: Einzelnes Profil ansehen + bearbeiten (EDITOR/ADMIN) + exportieren +10. `admin/AdminLayout.tsx` — Admin-Navigation (aus MVP) +11. `admin/AdminUsersPage.tsx` — User-Verwaltung + Rollen-Zuweisung (aus MVP erweitern) +12. `admin/AdminSsoPage.tsx` — SSO-Konfiguration (aus MVP 1:1) +13. `admin/AdminCustomizePage.tsx` — Branding (aus MVP 1:1) +14. `admin/AdminExternalLinksPage.tsx` — Externe Links (aus MVP 1:1) +15. `admin/AdminCompanyPage.tsx` — Firmendaten (aus MVP 1:1) +16. `admin/AdminSslPage.tsx` — SSL/Domain (aus MVP 1:1) +17. `admin/AdminAiSettingsPage.tsx` — KI-Einstellungen (aus MVP 1:1) +18. `admin/AdminModulesPage.tsx` — **NEU**: Modul-Registry (welche Module aktiv, Rollen-Konfiguration) + +**Navigation Sidebar — Hauptmenü:** +``` +🏠 Dashboard +📋 Experten Profile ← nur sichtbar wenn moduleRoles.expertprofile gesetzt +── Admin-Bereich ── ← nur sichtbar für PLATFORM_ADMIN +⚙️ Benutzer +⚙️ SSO / Sicherheit +⚙️ Erscheinungsbild +⚙️ Externe Links +⚙️ Firmendaten +⚙️ SSL / Domain +⚙️ KI-Einstellungen +⚙️ Module +``` **Wichtig für Admin-User-Management (NEU gegenüber MVP):** - User-Liste zeigt: Name, E-Mail, platformRole, moduleRoles - PLATFORM_ADMIN kann platformRole ändern -- PLATFORM_ADMIN kann moduleRoles pro Modul zuweisen (Dropdown: ADMIN/MANAGER/USER/VIEWER/Kein Zugang) +- PLATFORM_ADMIN kann moduleRoles pro Modul zuweisen: + - expertprofile: ADMIN / EDITOR / VIEWER / (kein Zugang) + - crm: ADMIN / MANAGER / USER / VIEWER / (kein Zugang) ← Phase 3, schon vorbereiten ---