INSIGHT-MVP/Summarize.md
Thomas Reitz 4f141b94e5 feat(frontend): bullet-editor – nummerierte Liste + Tab/Shift+Tab Einrueckung
- Neue Funktion blLineAt() auf Modul-Ebene: parst Zeile an Cursor-Position
  (Einrueckung, Bullet/Nummeriert, Zahl, Zeileninhalt) ohne Closure-Probleme
- Neuer Toolbar-Button "1. Liste": toggled nummerierte Liste (1./2./3.);
  wandelt Bullet→Nummeriert und Nummeriert→Bullet automatisch um
- Tab-Taste: fuegt 2 Leerzeichen am Zeilenanfang ein (Einrueckung)
- Shift+Tab: entfernt bis zu 2 Leerzeichen (Ausrueckung)
- Enter in nummerierter Liste: setzt naechste Zeile mit N+1 fort
- Enter auf leerem Listenelement: beendet die Liste (Bullet + Nummeriert)
- Enter beruecksichtigt Einrueckung bei Bullets
- CSS: bulletToolbarSep (Trennlinie) + bulletToolbarHint (Keyboard-Hinweis)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 20:40:50 +01:00

41 KiB
Raw Blame History

INSIGHT MVP - Aenderungsprotokoll

Stand: 2026-03-13

Aktueller Sprint: CRM Phase 3 — Kanban-Board + Microsoft 365 OAuth-Integration (Feature-Branch: feature/crm-service)


Aenderungen 2026-03-13 (14): Experten-Profil BulletEditor mit nummerierter Liste + Tab-Einrueckung

Frontend

  • profile/sections/ProjectModal.tsx — BulletEditor erweitert:
    • Neuer Button "1. Liste": toggled nummerierte Liste (1. 2. 3.) ein/aus; konvertiert auch Bullet→Nummeriert und umgekehrt
    • Tab-Taste: rueckt aktuelle Zeile um 2 Leerzeichen ein; Shift+Tab nimmt sie wieder raus
    • Enter in nummerierter Liste: naechste Zeile erhaelt automatisch naechste Zahl (z.B. "3. " → "4. ")
    • Enter in leerer Listenelement: beendet die Liste (Bullet oder Nummeriert)
    • Enter beruecksichtigt Einrueckung (eingerueckte " • " → naechste Zeile ebenfalls " • ")
    • Modul-Level-Hilfsfunktion blLineAt(): parst Zeile an Cursor-Position
    • Toolbar-Hinweistext: "Tab = einruecken · Shift+Tab = ausruecken"
  • profile/ExpertProfileTab.module.css.bulletToolbarSep (vertikale Linie), .bulletToolbarHint (Hinweistext)

Deployment-Hinweis (Schritt 14)

  • Rebuild + Restart: nur frontend

Aenderungen 2026-03-13 (13): Experten-Profil Bullet-Editor fuer Aufgaben + Popup-Backdrop deaktiviert

Frontend

  • components/Modal.tsxonClick={onClose} vom Overlay-div entfernt: Popups schliessen sich nicht mehr durch Klick neben das Popup (betrifft alle Modal-Instanzen im Projekt)
  • components/Drawer.tsx — Gleiches: Drawer schliesst sich nicht mehr durch Klick auf den Backdrop
  • profile/sections/ProjectModal.tsx — Neue lokale BulletEditor-Komponente (keine externe Library): Toolbar mit "☰ Liste"-Button (toggled am Zeilenanfang ein/aus), automatische Aufzaehlungsfortsetzung beim Enter-Druck, leere Bullet-Zeile + Enter beendet die Liste; ersetzte die einfache <textarea> im Feld "Aufgaben"
  • profile/ExpertProfileTab.module.css — Neue CSS-Klassen: .bulletEditor, .bulletToolbar, .bulletBtn, .bulletEditorTextarea, .bulletBtn:hover; Editor-Container mit border + :focus-within-Ring analog zu Input-Feldern; Textarea innerhalb des Editors hat keinen eigenen Rand (verhindert doppelten Rahmen)

TypeScript

  • npx tsc --noEmit in packages/frontend: 0 Fehler

Deployment-Hinweis (Schritt 13)

  • Rebuild + Restart: nur frontend (kein Backend-Aenderung)

Aenderungen 2026-03-13 (12): Bug-Fix Sprachen im Experten-Profil

Backend (core-service)

  • core/expert-profile/dto/create-language.dto.ts@IsIn Validator um fehlende Werte erweitert: Verhandlungssicher, Fliesend, Gut waren nicht enthalten (Frontend sendete diese Werte → 400 Fehler); alle 10 Werte jetzt korrekt: ['Muttersprache', 'Verhandlungssicher', 'Fliesend', 'Gut', 'C2', 'C1', 'B2', 'B1', 'A2', 'A1']

Deployment-Hinweis (Schritt 12)

  • Rebuild + Restart: nur core-service

Aenderungen 2026-03-13 (11): Kontakt-Detailseite Breite, Outlook-Daten-Sektion, Felder, Outlook-Push

Backend (crm-service)

  • graph/graph.module.tsexports: [GraphService] ergaenzt (GraphService ist jetzt in anderen Modulen nutzbar)
  • graph/graph.service.ts — Neue Methode pushContactToOutlook(userJwt, contact): prueft via GET /me/contacts?$filter=emailAddresses/any(...) ob Kontakt in Outlook existiert; existiert er → PATCH (Update); existiert er nicht → POST (Neuanlage); befuellt Outlook-Kontakt mit givenName, surname, jobTitle, department, companyName, emailAddresses, businessPhones, mobilePhone, businessAddress
  • contacts/contacts.module.tsGraphModule importiert (ermoeglicht GraphService-Injektion)
  • contacts/contacts.controller.ts — Neuer Endpoint POST /crm/contacts/:id/push-to-outlook: laedt CRM-Kontakt, leitet alle relevanten Felder an graphService.pushContactToOutlook weiter; gibt { created: boolean, outlookContactId: string } zurueck

Frontend

  • crm/api.tscontactsApi.pushToOutlook(id): POST /crm/contacts/:id/push-to-outlook
  • crm/contacts/ContactDetailPage.tsx:
    • Breite: Aeusserer Wrapper mit maxWidth: 960px, margin: 0 auto
    • Kontaktdaten: Neues Feld "Typ" (Person/Organisation) ganz oben in der rechten Spalte; "Status" immer angezeigt (bisher nur wenn != ACTIVE); contact.companyName als Fallback wenn kein verknuepftes Unternehmen; state (Bundesland) in der Adresszeile ergaenzt; state-Bedingung fuer Adressblock
    • Outlook Daten (neue Bezeichnung fuer "Microsoft 365"): Sektion einklappbar (default: eingeklappt), Chevron-Toggle im Karten-Header; "Aufgaben"-Tab entfernt (M365Tab jetzt nur emails | calendar); TasksTab-Import entfernt; "In Outlook speichern"-Button im Header mit Status-Feedback (Speichern…/✓ In Outlook gespeichert/Fehler)
    • CONTACT_TYPE_LABELS Konstante, handlePushToOutlook Funktion, outlookExpanded + pushStatus States

TypeScript

  • npx tsc --noEmit in packages/frontend: 0 Fehler
  • npx tsc --noEmit in packages/crm-service: 0 neue Fehler (vorhandene pre-existing Fehler aus Prisma-Client-Mismatch auf lokalem Mac — werden durch prisma generate auf Server behoben)

Deployment-Hinweis (Schritt 11)

  • Rebuild + Restart: crm-service + frontend (kein neues DB-Schema, kein migrate benoetigt)

Aenderungen 2026-03-13 (10): Dediziertes Projektanfrage-Formular + Button in Vorgänge-Liste

Frontend

  • crm/deals/ProjectRequestFormModal.tsx — Neues dediziertes Modal "Neue Projektanfrage": Projektdetails-Sektion oben (Beschreibung, Auslastung/Start, Laufzeit/Vorort-Anteil, Stundensätze), darunter Vorgangsdaten (Titel, Pipeline/Stage, Kontakt, Unternehmen, Volumen/Abschluss, Notizen); Auto-Select bei genau einem isProjectType-Typ; Warnung wenn kein Typ konfiguriert; Submit-Button disabled bei fehlendem Typ
  • crm/deals/DealsPage.tsx — Zweiter Button "Neue Projektanfrage" (outlined, primary) neben "Neuer Vorgang"; isProjectRequestOpen State; ProjectRequestFormModal eingebunden

Aenderungen 2026-03-13 (9): Projektanfrage-Vorgangstyp (isProjectType + ProjectRequestDetails)

Backend (crm-service)

  • prisma/crm.schema.prismaDealType um isProjectType Boolean @default(false) erweitert; neues 1:1-Model ProjectRequestDetails (notes, workload, startDate, duration, onsitePercent, rateRemote, rateOnsite) mit ON DELETE CASCADE zu Deal; Deal.projectRequest ProjectRequestDetails? Relation hinzugefuegt
  • prisma/migrations/20260313_project_request/migration.sqlALTER TABLE deal_types ADD COLUMN is_project_type; CREATE TABLE project_request_details mit Unique-Index auf deal_id und FK mit CASCADE
  • src/deal-types/dto/create-deal-type.dto.tsisProjectType?: boolean (@IsBoolean) hinzugefuegt
  • src/deal-types/dto/update-deal-type.dto.tsisProjectType?: boolean hinzugefuegt
  • src/deals/dto/project-request.dto.ts — Neues DTO: notes, workload (0-100%), startDate, duration, onsitePercent (0-100%), rateRemote, rateOnsite
  • src/deals/dto/create-deal.dto.tsprojectRequest?: ProjectRequestDto mit @ValidateNested() + @Type(()=>ProjectRequestDto) hinzugefuegt
  • src/deals/deals.service.tscreate(): Nested projectRequest.create + include: {projectRequest:true}; findOne(): include: {projectRequest:true}; update(): projectRequest aus Destructuring extrahiert, upsert vor Deal-Update, include: {projectRequest:true}

Frontend

  • crm/types.tsDealType.isProjectType: boolean; CreateDealTypePayload.isProjectType?; neues Interface ProjectRequestDetails; CreateProjectRequestPayload; Deal.projectRequest?; Deal.dealType.isProjectType ergaenzt; CreateDealPayload.projectRequest?
  • crm/deals/DealFormModal.tsx — Vorgangsart-Dropdown an Anfang des Formulars; Projektanfrage-Sektion (grau hinterlegt, blauer Titel) erscheint conditional bei isProjectType=true: Beschreibung, Auslastung/Start-Zeile, Laufzeit/Vorort-Anteil-Zeile, Stundensatz Remote/Vorort-Zeile; Initialisierung aus deal.projectRequest beim Bearbeiten; Payload-Zusammenbau mit projectRequest-Objekt
  • crm/settings/CrmSettingsPage.tsxDealTypesConfig: isProjectType State + Spalte "Projektanfrage" in Tabelle (Checkbox im Edit-/Add-Modus, ✓/— im View-Modus)

Deployment-Hinweis (Schritt 9)

  • Server: prisma migrate deploy --schema prisma/crm.schema.prisma
  • Server: prisma generate --schema prisma/crm.schema.prisma
  • Rebuild + Restart: crm-service + frontend

Aenderungen 2026-03-13 (8): Vorgangsart (DealType) + Pipeline-Leerstate

Backend (crm-service)

  • prisma/crm.schema.prisma — Neues Model DealType (id, tenantId, name, color, sortOrder) mit @@unique([tenantId, name]), @@map("deal_types"); Relation deals Deal[]; Deal-Model um optionales Feld dealTypeId String? @map("deal_type_id") @db.Uuid + Relation dealType DealType? @relation(...) erweitert
  • prisma/migrations/20260313_deal_type/migration.sql — Migration: CREATE TABLE app_crm.deal_types, ALTER TABLE app_crm.deals ADD COLUMN deal_type_id, Unique/Index/FK-Constraints
  • src/deal-types/dto/create-deal-type.dto.ts — DTO: name (required), color (optional, Hex-Validierung), sortOrder (optional)
  • src/deal-types/dto/update-deal-type.dto.ts — Alle Felder optional
  • src/deal-types/deal-types.service.ts — CRUD-Service (findAll/create/update/remove) analog IndustriesService, Duplikat-Check, Nutzungs-Guard beim Loeschen
  • src/deal-types/deal-types.controller.ts — REST-Controller: GET/POST/PATCH/DELETE unter /crm/deal-types, TenantGuard
  • src/deal-types/deal-types.module.ts — NestJS-Modul
  • src/app.module.ts — DealTypesModule registriert
  • src/deals/dto/create-deal.dto.tsdealTypeId?: string (UUID, optional) hinzugefuegt
  • src/deals/deals.service.tsdealTypeId beim Create an Prisma weitergegeben

Frontend

  • crm/types.ts — Neues Interface DealType (id, tenantId, name, color, sortOrder, _count?); CreateDealTypePayload, UpdateDealTypePayload; Deal.dealTypeId: string|null + dealType?: {...}|null; CreateDealPayload.dealTypeId?: string
  • crm/api.tsdealTypesApi (list/create/update/delete auf /crm/deal-types) importiert; Typ-Imports erweitert
  • crm/hooks.tscrmKeys.dealTypes, useDealTypes, useCreateDealType, useUpdateDealType, useDeleteDealType
  • crm/settings/CrmSettingsPage.tsxDealTypesConfig-Komponente (analog IndustriesConfig mit Farbpicker, Sortierung); als erster Block im Tab "Weitere Einstellungen" platziert
  • crm/deals/DealFormModal.tsx — Vorgangsart-Dropdown (select mit DealType-Optionen, "— Keine —" als Default); Pipeline-Leerstate-Hinweis mit Link zu CRM-Einstellungen; dealTypeId State + Payload-Uebergabe

Deployment-Hinweis

Nach Deploy: npx prisma migrate deploy && npx prisma generate im crm-service ausfuehren.


Aenderungen 2026-03-13 (7): Profil-Bereich nach oben rechts verschoben (Topbar)

Frontend

  • shell/AppLayout.tsx — Profil-/Logout-/Theme-Bereich aus der Sidebar entfernt und in einen neuen <header className={styles.topbar}> am Anfang des <main>-Bereichs verschoben:
    • Theme-Schalter: 3 kompakte Icon-Buttons (☀ ☾ ⚙) als Gruppe, aktiver Modus hervorgehoben
    • Benutzer-Profil: Avatar + Name, klickbar → /profile
    • Logout: Icon-Button (Tuer-Pfeil-SVG) mit Tooltip "Abmelden"
    • <Outlet /> nun in <div className={styles.mainContent}> eingebettet (eigene Padding-Klasse)
    • Sidebar hat nur noch: Logo/Brand + Navigation + Admin-Link (deutlich aufgeraeumt)
  • shell/AppLayout.module.css — Theme-Toggle- und UserInfo-Abschnitte entfernt (ca. 150 Zeilen weniger); .main auf display:flex; flex-direction:column umgestellt; neues .mainContent { padding:2rem }; neue Klassen: .topbar, .topbarThemeGroup, .topbarThemeBtn(Active), .topbarUser, .topbarUserName, .topbarIconBtn

Aenderungen 2026-03-13 (6): Dashboard Home-Tab — Analoguhr, 3-Tage-Wetter, Spruch, kompakte Widgets

Frontend

  • components/AnalogClock.tsx + AnalogClock.module.css — Neue SVG-Analoguhr mit Stunden-/Minuten-/Sekundenzeiger (Gegengewicht), digitaler Zeit- und Datumsanzeige; aktualisiert jede Sekunde via setInterval
  • hooks/useWeather.ts — Open-Meteo API um 3-Tage-Prognose erweitert (&daily=weather_code,temperature_2m_max,temperature_2m_min&forecast_days=3); WeatherData um forecast: ForecastDay[] ergaenzt; neues Interface ForecastDay
  • shell/DashboardPage.tsx — Home-Tab vollstaendig ueberarbeitet:
    • Spruch des Tages (35 dt. Zitate, deterministisch nach Tagesdatum) rechtsbuendig im Header neben dem Willkommensnamen
    • 3-Spalten-Layout: Linke Spalte (240px): Analoguhr + WeatherWidget (aus Header verschoben) + 3-Tage-Prognose; Mittlere Spalte (flex:1): Kompakte Aufgaben + Kompakte E-Mails; Rechte Sidebar (300px, unveraendert): Messe-Ticker + Tagesagenda
    • HomeTasksWidget: Top-8 offene Aufgaben (CRM + O365, gleiche Zusammenfuehrungs-Logik wie DashboardTasksTab), direkt erledigbar, „Alle →" schaltet auf Aufgaben-Tab
    • HomeEmailsWidget: Posteingang-E-Mails der letzten 3 Tage (client-seitiger Filter), direkter Outlook-Link, „Alle →" schaltet auf E-Mail-Tab
    • role-Parameter aus HomeTab entfernt (nicht mehr angezeigt)
  • shell/DashboardPage.module.css — Neue CSS-Klassen: .quoteOfDay, .homeLeft, .forecastStrip, .forecastDay*, .homeWidgetCard, .homeTaskRow*, .homeEmailRow* u.a. (ca. 280 neue Zeilen)

Aenderungen 2026-03-13 (5): Erweiterte Profilfelder (analog O365) + Profilbild-Sync aus Microsoft 365

Backend: Core-Service

  • prisma/core.schema.prisma — 4 neue optionale Felder im User-Modell: jobTitle, department, companyName, officeLocation (mit @map auf snake_case, @db.VarChar)
  • prisma/migrations/20260313_user_profile_extra_fields/migration.sql — ALTER TABLE fuer die 4 neuen Spalten
  • core/users/dto/update-user.dto.ts — Neue Felder mit @IsOptional, @ValidateIf, @IsString, @MaxLength
  • core/users/users.service.tsfindById(), update(), updateProfile() um neue Felder erweitert

Backend: CRM-Service

  • graph/graph.service.tsM365UserProfile um department, companyName, officeLocation erweitert; getM365Profile() $select erweitert; neue Methode getM365Photo(): Graph /me/photos/96x96/$value als ArrayBuffer → Base64 JPEG Data-URL; 404/400 → null
  • graph/office365.controller.ts — Neuer Endpoint GET /crm/office365/photo

Frontend

  • auth/AuthContext.tsxUser-Interface: jobTitle?, department?, companyName?, officeLocation?
  • crm/types.tsM365UserProfile um department, companyName, officeLocation erweitert
  • crm/api.tsoffice365Api.getM365Photo() hinzugefuegt
  • profile/ProfilePage.tsx — 4 neue State-Variablen, Organisations-Fieldset (2×2 Grid), handleEnrichFromO365 ueberschreibt Profilfoto immer; Auto-Sync-Hook befuellt alle neuen Felder
  • hooks/useO365ProfileSync.ts — Fetcht Profil + Foto parallel; Profilfoto nur gesetzt wenn !user.avatar

Aenderungen 2026-03-13 (4): O365-Profil-Auto-Sync beim Login (useO365ProfileSync)

Frontend

  • hooks/useO365ProfileSync.ts — Neuer Hook: synchronisiert INSIGHT-Profil einmalig pro Browser-Session aus Microsoft 365; sessionStorage-Flag (o365_profile_synced) verhindert Mehrfach-Sync; stille Ausfuehrmg (kein UI-Feedback); bei Fehler wird Flag entfernt fuer naechsten Retry; PATCH /users/me mit Kontaktfeldern (firstName, lastName, phone, mobile, city, street, postalCode)
  • shell/AppLayout.tsxuseO365ProfileSync() direkt in der AppLayout-Komponente aufgerufen

Aenderungen 2026-03-13 (3): Dashboard Kalender-Tab — Monats-/Wochenansicht + Tages-Agenda

Backend: CRM-Service

  • graph/graph.service.ts — Neue Methode getCalendarEventsForRange(userJwt, userId, startDate, endDate): laedt Kalender-Termine fuer beliebigen Zeitraum via /me/calendarView, Redis-Cache 5 Min; wellKnownName aus getMailFolders() $select entfernt (400-Fehler auf Exchange-Tenants die das OData-Property nicht unterstuetzen)
  • graph/office365.controller.ts — Neuer Endpoint GET /crm/office365/calendar/range?startDate=&endDate= (vor @Get('calendar') definiert, um Routing-Konflikt zu vermeiden)

Frontend

  • crm/types.tsM365MailFolder.wellKnownName als optional markiert (nicht alle Exchange-Tenants liefern das Feld)
  • crm/api.tsoffice365Api.getCalendarRange(startDate, endDate)
  • crm/hooks.ts — Neuer Hook useOffice365CalendarRange(startDate, endDate)
  • shell/DashboardCalendarTab.tsx — Neue Hauptkomponente mit: Toolbar (Vor/Zurueck/Heute + Monat/Woche Toggle), MonthView (6×7 CSS-Grid, Heute-Kreis, Event-Chips max. 2 + "+N"), WeekView (7-Spalten-Grid, Events mit farbigem linken Rand, Klick oeffnet Outlook), DayAgenda (rechts 1/3 — Uhrzeit/Betreff/Ort/Teilnehmer, Online-Badge, Outlook-Link); deterministisches Event-Coloring per ID-Hash
  • shell/DashboardCalendarTab.module.css — Vollstaendiges Styling
  • shell/DashboardPage.tsx — Kalender-Tab ersetzt ComingSoonTab durch DashboardCalendarTab

Fix: Ordner-Sidebar 400-Fehler

  • DashboardEmailTab.tsx — Ordner-Sortierung auf Display-Name-Basis umgestellt (Posteingang/Inbox, Gesendete Elemente/Sent Items, etc.) da wellKnownName nicht verfuegbar; isInboxFolder() erkennt Posteingang per Anzeigename

Aenderungen 2026-03-13 (2): Dashboard E-Mail Tab — Outlook-Postfach mit Ordner-Navigation + Aktivitaeten-Speicherung

Backend: CRM-Service

  • contacts/contacts.service.ts — Neue Methode findByEmail(tenantId, email): sucht Kontakt anhand E-Mail-Adresse (legacy + multi-value emails)
  • contacts/contacts.controller.ts — Neuer Endpoint GET /crm/contacts/lookup?email=xxx (vor :id-Route, damit kein UUID-Konflikt)
  • graph/graph.service.ts — Neue Methoden: getMailFolders() (alle Outlook-Ordner inkl. unreadItemCount), getMailsByFolder(folderId, days) (E-Mails mit optionalem Tages-Filter via $filter receivedDateTime ge)
  • graph/office365.controller.ts — Neue Endpoints: GET /crm/office365/folders, GET /crm/office365/folders/:folderId/messages?days=7

Frontend

  • crm/types.ts — Neue Interfaces: M365MailFolder (id, displayName, totalItemCount, unreadItemCount, childFolderCount, wellKnownName), CrmContactLookup (id, firstName, lastName, email, companyName)
  • crm/api.tsoffice365Api.getMailFolders(), office365Api.getMailsInFolder(folderId, days), contactsApi.lookupByEmail(email)
  • crm/hooks.ts — Neue Hooks: useOffice365MailFolders(), useOffice365MailsInFolder(folderId, days), useContactByEmail(email) (mit retry: false fuer 404-Faelle)
  • shell/DashboardEmailTab.tsx — Neue Hauptkomponente mit: Ordner-Sidebar (sortiert nach Prioritaet: Posteingang, Gesendet, Entwuerfe, ...), Zeitfilter-Leiste (1/7/14 Tage/alle), E-Mail-Liste mit Outlook-Link, CRM-Badge fuer bekannte Absender, Aktivitaeten-Modal mit Kommentarfeld
  • shell/DashboardEmailTab.module.css — Vollstaendiges Styling
  • shell/DashboardPage.tsx — E-Mail-Tab ersetzt ComingSoonTab durch DashboardEmailTab

Aenderungen 2026-03-13: Office365-Seite + Graph API Bugfixes

Backend: CRM-Service — GraphModule erweitert

  • graph/graph.service.ts — Fix: $search + $orderby koennen nicht kombiniert werden (Graph API Limitation) → $orderby aus Kontakt-E-Mail-Suche entfernt; neue globale Methoden: getAllEmails, getAllCalendarEvents, getAllOutlookContacts, getTasks (war schon vorhanden); attendees zu Kalender-Abfragen ergaenzt; Fehler werden jetzt geloggt
  • graph/office365.controller.ts — Neuer Controller mit globalen Office365-Endpoints: GET /crm/office365/emails, GET /crm/office365/calendar, GET /crm/office365/contacts, GET /crm/office365/tasks
  • graph/graph.module.tsOffice365Controller registriert

Frontend: Office365-Uebersichtsseite

  • crm/office365/Office365Page.tsx — Neue Seite mit 4 Tabs: E-Mails, Kalender, Outlook-Kontakte, Aufgaben; zeigt alle M365-Daten des eingeloggten Users; Suchfilter fuer Kontakte; "CRM"-Button zum Navigieren in CRM-Kontakte
  • crm/office365/Office365Page.module.css — Vollstaendiges Styling (Cards, Tabs, Grid, Badges)
  • crm/types.tsM365Email.hasAttachments und M365CalendarEvent.attendees ergaenzt; neues Interface M365Contact
  • crm/api.tsoffice365Api (getEmails, getCalendar, getContacts, getTasks)
  • crm/hooks.tsuseOffice365Emails, useOffice365Calendar, useOffice365Contacts, useOffice365Tasks
  • shell/App.tsx — Route /crm/office365 hinzugefuegt
  • shell/AppLayout.tsx — NavLink "Office 365" (Grid-Icon) nach Kanban ergaenzt

Datenbankfix

  • user_integrations-Tabelle: Tenant-Membership fuer t.reitz@xinion.de in "Xinion GmbH" manuell angelegt (fehlende Zuordnung verursachte 403 auf allen CRM-Endpoints)

Aenderungen 2026-03-12: Microsoft 365 OAuth-Integration — Frontend

Frontend: MS365 Integration-Tab + Kontakt-Tabs

  • crm/types.ts — Neue Interfaces: UserIntegration, M365Email, M365EmailAddress, M365CalendarEvent, M365Task, M365TaskList
  • crm/api.tsintegrationsApi (list, disconnectM365, getM365ConnectUrl) + graphApi (getContactEmails, getContactCalendar, getContactTasks)
  • crm/hooks.tsuseIntegrations, useDisconnectM365, useContactEmails, useContactCalendar, useContactTasks
  • profile/ProfilePage.tsx:
    • Neuer Tab "Integrationen" (Typ: ProfileTab = 'personal' | 'expert' | 'password' | 'integrations')
    • Oeffnet automatisch wenn ?integration=microsoft-365 URL-Param gesetzt ist
    • Zeigt Erfolgs-/Fehlermeldung aus ?status=success|error Param
    • "Microsoft 365 verbinden" Button (Link zu /api/v1/auth/integrations/microsoft-365)
    • Verbunden-Ansicht: Tenant-ID, Token-Ablauf, "Verbindung trennen" Button
  • crm/contacts/EmailsTab.tsx — E-Mail-Liste aus MS Graph, ungelesen fett + blauer Rand, Link zu Outlook Web
  • crm/contacts/CalendarTab.tsx — Kalendertermine (naechste 90 Tage), Online-Meeting-Badge, Link zu Outlook Web
  • crm/contacts/TasksTab.tsx — Microsoft To Do Aufgaben, gruppiert nach Listen, Status-/Prioritaets-Badges
  • crm/contacts/ContactDetailPage.tsx:
    • Neuer "Microsoft 365" Abschnitt (Card) am Seitenende (nur wenn Kontakt E-Mail hat)
    • Drei Tabs: E-Mails / Kalender / Aufgaben
    • Ohne MS365-Verbindung: "Verbinden"-Button direkt im Tab
  • TypeScript npx tsc --noEmit: 0 Fehler

Aenderungen 2026-03-12: Microsoft 365 OAuth-Integration — CRM-Service (GraphModule)

  • crm-service/src/graph/graph.service.ts — Token von Core-Service holen (JWT-Forwarding), Graph-Calls (Emails/Kalender/Tasks), Redis-Cache 5 Min
  • crm-service/src/graph/graph.controller.ts — GET /crm/contacts/:id/emails|calendar|tasks
  • crm-service/src/graph/graph.module.ts — Modul-Definition
  • crm-service/src/app.module.ts — GraphModule registriert
  • crm-service/src/config/env.validation.tsCORE_SERVICE_URL ergaenzt
  • docker-compose.crm.ymlCORE_SERVICE_URL=http://core:3000 hinzugefuegt

Aenderungen 2026-03-12: Microsoft 365 OAuth-Integration — Core-Service

  • core-service/prisma/core.schema.prismaUserIntegration Modell + Relation auf User
  • core-service/prisma/migrations/20260312_user_integrations/migration.sql — Migration fuer user_integrations Tabelle
  • core-service/src/config/env.validation.tsAZURE_INTEGRATION_REDIRECT_URI, INTEGRATION_ENCRYPTION_KEY
  • core-service/src/core/auth/sso/entra-id.service.tsgetIntegrationAuthUrl, handleIntegrationCallback, refreshIntegrationToken
  • core-service/src/core/integrations/integrations.service.ts — AES-256-GCM Token-Verschluesselung, Token-CRUD, Auto-Refresh
  • core-service/src/core/integrations/integrations.controller.ts — OAuth-Flow + Token-Endpoints
  • core-service/src/core/integrations/integrations.module.ts
  • core-service/src/app.module.ts — IntegrationsModule registriert

Aenderungen 2026-03-12: Kanban-Board (Frontend)

  • frontend/src/crm/deals/KanbanPage.tsx — Drag-&-Drop Kanban-Board (@dnd-kit)
    • Pipeline-Selektor + Toggle "Abgeschlossene anzeigen"
    • DealCard (useDraggable), KanbanColumn (useDroppable), DragOverlay
    • Optimistisches Update via localStageMap; Rollback bei Fehler
  • frontend/src/crm/deals/KanbanPage.module.css — Styles fuer Board, Spalten, Cards
  • frontend/src/shell/App.tsx — Route /crm/kanban
  • frontend/src/shell/AppLayout.tsx — NavLink "Kanban" im CRM-Bereich
  • frontend/package.json@dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities

Aktueller Sprint: CRM Phase 2 / Vertraege-Modul (Feature-Branch: feature/crm-service)


Aenderungen 2026-03-12: Vertraege-Modul Frontend (ContractsCard)

Neue/geaenderte Dateien

  • crm/companies/ContractsCard.tsx — Vollstaendige Vertraege-Card fuer CompanyDetailPage
    • Tabelle mit Titel, Status-Badge, Laufzeit, Vertragswert
    • "+ Neu" Button oeffnet Create-Modal
    • Stift-Icon (Bearbeiten) + X-Icon (Loeschen) pro Zeile
    • Status-Farben: DRAFT=grau, ACTIVE=gruen, EXPIRED=orange, CANCELLED=rot
    • Wert-Formatierung (Intl.NumberFormat de-DE), Datumsformatierung
  • crm/types.tsCreateContractPayload, UpdateContractPayload, ContractsQueryParams ergaenzt
  • crm/api.tscontractsApi (list, create, update, delete) mit /crm/companies/:id/contracts
  • crm/hooks.tscrmKeys.contracts + useContracts, useCreateContract, useUpdateContract, useDeleteContract
  • crm/companies/CompanyDetailPage.tsxcontractCount Prop entfernt (Card laedt selbst)

Aenderungen 2026-03-12: CRM Phase 2 — Forecast, Import, Enrichment (Frontend komplett)

Phase 2.3: Forecasting

  • crm/forecast/ForecastPage.tsx — Prognose-Dashboard unter /crm/forecast
    • Pipeline-Filter (Dropdown) + Zeitraum-Toggle (Monat/Quartal/Jahr)
    • Summary-Cards: Offene Vorgaenge, Gesamtwert, Gewichteter Wert, Zeitraum
    • Tabelle: Stage | Wahrscheinlichkeit | Vorgaenge | Gesamtwert | Gewichteter Wert
  • crm/pipelines/PipelinesPage.tsx — Probability-Feld (0100%) pro Pipeline-Stage

Phase 2.2: CSV/Excel Import

  • crm/import/ImportPage.tsx — 3-Schritt-Wizard in CRM-Einstellungen → Tab "Import"
    • Schritt 1: Typ-Auswahl (Kontakte/Unternehmen/Vorgaenge) + Datei-Upload (CSV, XLSX, max 10MB)
    • Schritt 2: Spalten-Mapping (Auto-Match + manuell), Duplikat-Strategie, Kopfzeilen-Option
    • Schritt 3: Ergebnis (created/updated/skipped/errors + Fehlerdetails)
  • API-Konvertierungen: PERSON→contact, mapping Record→Array [{sourceColumn,targetField}]

Phase 2.4: Datenanreicherung

  • crm/companies/CompanyDetailPage.tsx — "Anreichern"-Button im Header
    • POST /companies/:id/enrich → Suggestions-Modal
    • Tabelle: Feld | Aktuell | Vorschlag | Quelle + "Uebernehmen"-Button (PATCH)
    • suggestions-Konvertierung: Backend-Record → UI-Array
  • crm/settings/CrmSettingsPage.tsx — North Data API-Key in Tab "Integrationen"

Kontakt-Entity UI/UX Redesign (aus dieser Sprint-Session)

  • components/Drawer.tsx + Drawer.module.css — Wiederverwendbarer Right-Side-Drawer
  • crm/contacts/ContactFormModal.tsx — Modal → Drawer, Zwei-Tab-Struktur (Allgemein/Details)
  • crm/contacts/ContactDetailPage.tsx:
    • Header: Name (Unternehmen) in Klammern, Aktiv/Inaktiv-Badge (Pill mit farbigem Dot)
    • Kontaktdaten-Card: immer alle Allgemein-Felder (leere Felder = "—"), 2 Sub-Spalten
    • Lexware-Section entfernt (Kontakte werden nicht separat in Lexware gepflegt)

TypeScript

  • npx tsc --noEmit in packages/frontend: 0 Fehler (alle Commits)

Aktueller Sprint: Sprint 1 (Alpha)


Aenderungen 2026-03-12: CRM UI/UX Redesign Kontakt-Entitaet

Drawer-Komponente (neu)

  • packages/frontend/src/components/Drawer.tsx Wiederverwendbares Right-Side-Drawer-Pattern mit Portal, ESC-Key, Backdrop-Click, optionalem Footer
  • packages/frontend/src/components/Drawer.module.css Animiertes Slide-In von rechts, sticky Header + Footer, scrollbarer Body

ContactFormModal Redesign (Modal → Drawer + Tabs)

  • Gewechselt von <Modal> (zentriert) zu <Drawer> (von rechts, 540px)
  • Zwei-Tab-Struktur:
    • Tab "Allgemein": Vorname, Nachname, Unternehmen (Autocomplete), Position, Abteilung, E-Mail, Telefon, Mobil, LinkedIn
    • Tab "Details & Adresse": Geburtsdatum, Quelle, Status, Website, Adresse, Notizen, Tags, Custom Fields
  • "Adresse vom Unternehmen uebernehmen" Checkbox: wird angezeigt wenn Unternehmen verlinkt ist; bei aktivierter Checkbox werden Adressfelder ausgeblendet und die Adresse wird aus dem verlinkten Unternehmen uebernommen
  • "Typ"-Feld entfernt (Kontakte sind immer Personen; ORGANIZATION-Typ bleibt intern erhalten)
  • Sticky Footer (Abbrechen / Anlegen|Speichern) via HTML5 form Attribut
  • Adress-Duplikate bereinigt

ContactDetailPage Redesign

  • Header: Subtitle "Position @ Unternehmen" unter dem Namen (z.B. "Geschaeftsfuehrerin @ team neusta SE"), Status-Dot inline
  • Kontaktdaten-Card: Zwei Sub-Spalten (Kommunikation links, Kontext rechts), Adresse als volle Breite darunter
    • Entfernt: Vorname/Nachname (im Header), Firma-Duplikat (nur noch "Unternehmen" als Link)
    • Hinzugefuegt: Mobil als tel:-Link, LinkedIn mit Icon, Geburtsdatum, Quelle, Abteilung
  • Neue Card "Notizen & Tags": Tags als Badges, Notizen-Text, Custom Fields
  • Layout: Rechte Spalte (Aktivitaeten) auf minmax(380px, 40%) verbreitert (min. 1/3 fuer kuenftigen O365-Feed)
  • CSS: .infoColumns (2-spaltig), .addressRow, .subtitle, .nameRow neu

TypeScript

  • npx tsc --noEmit in packages/frontend: 0 Fehler

Aenderungen in dieser Session

1. Projektinitialisierung & Infrastruktur-Definition

Was wurde gemacht:

  1. SSH Keys erstellt

    • Deploy-Key (.keys/deploy_ed25519) fuer Server-Zugriff
    • CI/CD-Key (.keys/cicd_ed25519) fuer Forgejo Actions Pipeline
  2. Infrastruktur-Definition erstellt (docs/INFRASTRUCTURE.md)

    • ProxmoxVE VM-Spezifikation: Ubuntu 24.04 LTS, 4 vCPU, 8 GB RAM, 60 GB SSD
    • Docker-Netzwerk-Architektur mit 3 isolierten Netzwerken
    • Komplette Service-Landschaft definiert
    • Schritt-fuer-Schritt VM-Setup Anleitung
  3. Zugangsdaten-Dokument erstellt (docs/ACCESS.md)

    • Server-IP: 172.20.10.59 (insight-dev-01)
    • Git-Server: 172.20.10.11 (GAIA-GIT)
    • Alle SSH-Keys, Ports, Befehle dokumentiert
  4. Projektstruktur aufgesetzt (packages/core-service, packages/frontend, config, .forgejo)

  5. Basis-Konfigurationsdateien (.gitignore, .env.example, README.md)

2. Forgejo Git-Server Konfiguration

Was wurde auf dem Git-Server (172.20.10.11) gemacht:

  1. Docker Engine 29.3 installiert (fuer Forgejo Actions Runner)
  2. Forgejo Actions aktiviert ([actions] ENABLED = true in app.ini)
  3. Container Registry aktiviert ([packages] ENABLED = true in app.ini)
  4. Forgejo Runner v6.3.1 installiert und registriert
    • Runner-Name: insight-runner
    • Labels: ubuntu-latest (docker://node:20)
    • Laeuft als Systemd-Service (forgejo-runner.service)
  5. Repository Secrets angelegt:
    • SSH_DEPLOY_KEY - CI/CD Private Key
    • DEPLOY_HOST - 172.20.10.59
    • DEPLOY_USER - deploy
    • REGISTRY_USER - gitadmin
    • REGISTRY_PASSWORD - Forgejo Access Token
  6. Branch Protection eingerichtet:
    • main: Kein direkter Push, 1 Approval erforderlich
    • develop: Kein direkter Push, 1 Approval erforderlich
  7. Forgejo Setup-Anleitung erstellt (docs/FORGEJO_SETUP.md)

3. Server-Setup (insight-dev-01)

Was wurde auf dem Entwicklungsserver (172.20.10.59) gemacht:

  1. SSH Public Keys hinterlegt in /home/deploy/.ssh/authorized_keys
    • Deploy-Key (insight-deploy@xinion.lan) - fuer manuellen Zugriff
    • CI/CD-Key (insight-cicd@xinion.lan) - fuer Forgejo Actions Pipeline
  2. SSH-Zugang getestet - Key-basierter Login als deploy funktioniert

4. Docker Compose & Service-Konfiguration

Erstellte Dateien:

  1. docker-compose.yml - Alle Basis-Services:

    • Traefik 3 (API Gateway, Reverse Proxy, Rate Limiting)
    • PostgreSQL 16-alpine (Performance-Tuning: 1GB shared_buffers, 4GB cache)
    • PgBouncer (Connection Pooling, Transaction Mode)
    • Redis 7-alpine (Cache, Sessions, Token-Revocation)
    • step-ca (Interne Certificate Authority fuer mTLS - geplant)
    • Core-Service (NestJS) mit Traefik-Labels
    • Frontend (React) mit Traefik-Labels
    • 3 isolierte Docker-Netzwerke (insight-web, insight-db, insight-cache)
    • Health-Checks fuer alle Services
  2. docker-compose.observability.yml - Monitoring-Stack:

    • Prometheus (Metrics-Sammlung, 30 Tage Retention)
    • Grafana (Dashboards, automatisch provisionierte Datenquellen)
    • Loki (Log-Aggregation)
    • Promtail (Docker Log-Collector)
    • Tempo (Distributed Tracing, OTLP gRPC)
    • cAdvisor (Container-Metriken)
    • PostgreSQL Exporter (DB-Metriken)
  3. Konfigurationsdateien:

    • config/traefik/dynamic/tls.yml - TLS deaktiviert (Alpha/Dev)
    • config/traefik/dynamic/middlewares.yml - Security-Headers, CORS, Compression
    • config/prometheus/prometheus.yml - Scrape-Konfiguration
    • config/loki/loki.yml - Log-Storage-Konfiguration
    • config/promtail/promtail.yml - Docker-Log-Collector
    • config/tempo/tempo.yml - Tracing-Backend
    • config/grafana/provisioning/datasources/datasources.yml - Auto-Provisioning
    • config/postgres/init/01-init-extensions.sql - DB-Extensions (uuid-ossp, pgcrypto, pg_trgm)

5. NestJS Core-Service Implementierung

Projekt-Setup:

  • package.json mit allen Dependencies (NestJS 10, Prisma 6, Passport, JWT, bcrypt, TOTP)
  • tsconfig.json mit strict: true, noImplicitAny, strictNullChecks
  • Dockerfile (Multi-Stage: base, deps, development, build, production)
  • nest-cli.json Konfiguration

Implementierte Module:

  1. Auth-Modul (src/core/auth/)

    • AuthService: Login (E-Mail/Passwort), Token-Refresh, Logout, Token-Revocation
    • AuthController: POST /login, /refresh, /logout
    • JwtStrategy: RS256 Passport-Strategy
    • TotpService: TOTP 2FA (Google Authenticator kompatibel)
    • LoginDto: Validierung mit class-validator
    • Account-Lockout nach 5 Fehlversuchen (15 Min Sperre)
    • Refresh-Token als HttpOnly Cookie (secure/sameSite umgebungsabhaengig)
    • Token-Rotation mit Redis-basierter Familien-Erkennung
  2. Users-Modul (src/core/users/)

    • UsersService: CRUD, Bcrypt Cost 12, Passwort-Hashing
    • UsersController: GET /me, GET /users, POST /users, PATCH /users/:id
    • DTOs: CreateUserDto, UpdateUserDto
    • Paginierung mit Meta-Informationen
  3. Tenants-Modul (src/core/tenants/)

    • TenantsService: CRUD, Member-Management
    • TenantsController: CRUD + POST /:id/members, DELETE /:id/members/:userId
    • DTOs: CreateTenantDto, UpdateTenantDto, AddMemberDto
    • Slug-Validierung (URL-freundlich)
  4. Infrastruktur-Module:

    • PrismaService: PostgreSQL-Verbindung (platform_core)
    • TenantPrismaService: Dynamische Tenant-DB-Verbindungen mit Caching
    • RedisService: Token-Blocklist, Refresh-Token-Familien, generischer Cache
    • HealthController: GET /health (DB + Redis Status)
  5. Common (Guards, Decorators, Filter):

    • @Public() Decorator fuer oeffentliche Routen
    • @Roles() Decorator fuer rollenbasierte Zugriffskontrolle
    • @CurrentUser() Decorator fuer User-Extraktion aus JWT
    • JwtAuthGuard (global) mit Token-Revocation-Check
    • RolesGuard fuer Rollen-Pruefung
    • GlobalExceptionFilter fuer strukturierte Fehlerantworten
  6. Config:

    • validateConfig() mit class-validator fuer Umgebungsvariablen

6. Prisma-Schemas & Migration

  1. core.schema.prisma (platform_core Datenbank):

    • User - Plattform-Benutzer (mit Login-Tracking, 2FA)
    • AuthProvider - Multi-Provider Auth (LOCAL, MS_SSO, M2M)
    • Tenant - Mandanten mit JSON-Settings
    • TenantMembership - User-Tenant-Zuordnung (M:N)
    • Module - Verfuegbare Plattform-Module
    • TenantModule - Module pro Tenant
    • AuditLog - Plattform-weites Audit-Log
  2. tenant.schema.prisma (tenant_{slug} Datenbanken):

    • Contact - CRM-Kontakte (Person/Organisation)
    • Activity - CRM-Aktivitaeten (Notiz, Anruf, E-Mail, Meeting, Task)
    • Referenz-Schema fuer Sprint 2 (CRM-Modul)
  3. Erste Migration erstellt (prisma/migrations/20260308000000_init/)

    • 7 Tabellen, alle Indizes und Foreign Keys
    • migration_lock.toml fuer Prisma
  4. Seed-Script erstellt (prisma/seed.ts)

    • Erstellt Platform-Admin: admin@xinion.de / ChangeMe123!
    • Bcrypt Cost 12, Rolle: PLATFORM_ADMIN

7. React Frontend-Shell

Projekt-Setup:

  • package.json mit React 18, Vite 6, React Router 6, TanStack Query 5, Axios
  • tsconfig.json mit strict TypeScript
  • vite.config.ts mit API-Proxy und Path-Aliases
  • Dockerfile (Multi-Stage: development mit Vite, production mit Nginx)
  • nginx.conf (SPA-Routing, Security-Headers, Caching)

Implementierte Komponenten:

  1. Auth-System (src/auth/)

    • AuthContext + useAuth() Hook: Login, Logout, Silent Refresh
    • LoginPage: E-Mail/Passwort + optionaler TOTP 2FA-Code
    • Access-Token NUR im Memory (kein localStorage!)
    • Automatischer Silent Refresh via HttpOnly Cookie
  2. API-Client (src/api/client.ts)

    • Axios-Instanz mit automatischem Token-Handling
    • Request-Interceptor fuer Authorization-Header
    • Response-Interceptor fuer automatisches Token-Refresh bei 401
  3. App-Shell (src/shell/)

    • App: React Router mit PrivateRoute-Guard
    • AppLayout: Sidebar-Navigation + Outlet
    • DashboardPage: Willkommens-Seite
  4. Admin-Bereich (src/admin/)

    • AdminUsersPage: Benutzer-Tabelle mit Paginierung
    • AdminTenantsPage: Mandanten-Tabelle mit Member-Count
  5. Styling:

    • CSS Custom Properties (Farben, Layout, Schatten, Radien)
    • CSS Modules fuer komponentenspezifische Styles
    • Responsive Sidebar-Layout

8. CI/CD Pipelines

  1. .forgejo/workflows/ci.yml - Continuous Integration:

    • Trigger: Push auf alle Branches + Pull Requests
    • Core-Service: npm ci, Prisma Generate, Lint, Type-Check, Test, Build
    • Frontend: npm ci, Lint, Type-Check, Build
  2. .forgejo/workflows/deploy.yml - Deployment:

    • Trigger: Push auf main/develop
    • Build Docker-Images (Core + Frontend)
    • Push in Forgejo Container Registry
    • SSH-Deploy auf insight-dev-01
    • Health-Check Verifizierung

9. IP-basierte Deployment-Anpassung (HTTP statt HTTPS)

Grund: Kein DNS-Eintrag vorhanden, Zugriff nur ueber IP 172.20.10.59.

Geaenderte Dateien:

  1. auth.controller.ts - Cookie secure/sameSite umgebungsabhaengig

    • secure: true -> secure: process.env.NODE_ENV === 'production'
    • sameSite: 'strict' -> isProduction ? 'strict' : 'lax'
    • Betrifft setRefreshTokenCookie() und logout()
  2. docker-compose.yml - HTTP + IP Umstellung

    • HTTPS-Redirect entfernt
    • TLS-Entrypoint deaktiviert, Port 443 entfernt
    • Alle Host-Rules: insight-dev.xinion.lan -> 172.20.10.59
    • Alle Entrypoints: websecure -> web
    • URL-Defaults auf http://172.20.10.59
    • PostgreSQL Memory reduziert (1GB/4GB/256MB fuer 8GB RAM VM)
    • JWT-Keys Volume-Mount hinzugefuegt: ./keys:/app/keys:ro
  3. config/traefik/dynamic/tls.yml - TLS-Konfiguration deaktiviert

  4. config/traefik/dynamic/middlewares.yml

    • HSTS-Headers entfernt
    • CSP: wss://insight-dev.xinion.lan -> ws://172.20.10.59
    • CORS: https://insight-dev.xinion.lan -> http://172.20.10.59
  5. main.ts - CORS-Fallback auf http://172.20.10.59

  6. env.validation.ts - APP_URL Default auf http://172.20.10.59

  7. .env.example - Alle URLs auf http://172.20.10.59

  8. package-lock.json - Generiert fuer core-service und frontend (npm ci braucht diese)

  9. Dokumentation aktualisiert:

    • docs/INFRASTRUCTURE.md - HTTP statt HTTPS, IP statt DNS
    • docs/ACCESS.md - Ports, URLs, Default-Zugangsdaten
    • README.md - Setup-Anleitung, URLs, Seed-Befehle

Naechste Schritte

  • SSH Deploy Keys auf insight-dev-01 Server hinterlegen
  • docker-compose.yml erstellen (alle Basis-Services)
  • docker-compose.observability.yml erstellen
  • NestJS Core-Service implementieren (Auth, Users, Tenants)
  • Prisma-Schemas erstellen (core + tenant)
  • React Frontend-Shell implementieren
  • CI/CD Pipelines (.forgejo/workflows/) definieren
  • Codebase auf HTTP + IP (172.20.10.59) umstellen
  • Seed-Script erstellen (admin@xinion.de)
  • Prisma-Migration erstellen (init)
  • package-lock.json generieren
  • Dokumentation aktualisieren
  • Commit & Push auf develop
  • LVM-Festplatte auf Server erweitern (60GB -> voll nutzbar)
  • Docker + Docker Compose auf insight-dev-01 installieren
  • Repo klonen, .env + JWT-Keys auf Server erstellen
  • Services starten, Migration + Seed ausfuehren
  • Erster End-to-End Test (Login -> Dashboard)

Offene Fragen / Abhaengigkeiten

  • DNS-Eintrag insight-dev.xinion.lan wird spaeter eingerichtet (dann HTTPS aktivieren)
  • LVM auf Server muss erweitert werden (60GB Disk, nur ~56GB sichtbar)