Commit graph

42 commits

Author SHA1 Message Date
Thomas Reitz
5f50ba1315 feat(frontend): Profil-Topbar — Avatar, Theme-Schalter und Logout nach oben rechts
Sidebar-Bottom-Bereich (Profil, Abmelden, Theme-Toggle) vollstaendig entfernt
und durch eine sticky Topbar im Hauptinhaltsbereich ersetzt:
- Theme-Schalter: kompakte Icon-Button-Gruppe (☀ hell / ☾ dunkel / ⚙ system)
- Benutzer-Avatar + Name klickbar → /profile
- Logout-Icon-Button (SVG, Tooltip "Abmelden")
Sidebar zeigt nur noch Logo, Navigation und Admin-Link.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 13:46:33 +01:00
Thomas Reitz
0f63c28110 fix: WeatherWidget Ort mittig darunter; +30 Sprüche des Tages (65 gesamt) 2026-03-13 13:38:45 +01:00
Thomas Reitz
baa0cafd40 fix: WeatherWidget auf volle Spaltenbreite (gleich wie Forecast-Karte) 2026-03-13 13:34:16 +01:00
Thomas Reitz
ceea82a2ac feat: Dashboard Home-Tab mit Analoguhr, 3-Tage-Prognose, Spruch des Tages + kompakte Widgets
- Analoge SVG-Uhr (AnalogClock.tsx) aktualisiert jede Sekunde via setInterval
- useWeather: 3-Tage-Prognose via Open-Meteo daily-Parameter (weather_code, tempMax, tempMin)
- Dashboard Home-Tab: 3-Spalten-Layout (Uhr+Wetter links | Aufgaben+Mails mitte | Messe+Agenda rechts)
- Spruch des Tages rechts im Header (deterministisch nach Tagesdatum, 35 dt. Zitate)
- WeatherWidget aus dem Header in die linke Spalte verschoben
- Kompaktes Aufgaben-Widget: Top 8 offene Aufgaben (CRM + O365), direkt erledigbar
- Kompaktes E-Mail-Widget: Posteingang der letzten 3 Tage, direkter Öffnen-Link
- „Alle →" Buttons schalten auf den jeweiligen Tab um

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 13:30:45 +01:00
Thomas Reitz
138742d385 feat: O365-Profil automatisch beim Login synchronisieren
- Neuer Hook useO365ProfileSync: läuft einmalig pro Browser-Session,
  überschreibt INSIGHT-Profil-Felder mit O365-Daten (firstName, lastName,
  phone, mobile, city, street, postalCode) — kein UI-Feedback, kein Fehler
  bricht die UX auf.
- AppLayout ruft useO365ProfileSync() auf, sodass die Synchronisation
  beim Laden der App (nach Login) automatisch startet.
- ProfilePage: "↓ O365 übernehmen"-Button überschreibt jetzt alle Felder
  wo O365 Daten hat (nicht mehr nur leere Felder) — konsistent mit dem
  Auto-Sync-Verhalten.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 12:50:25 +01:00
Thomas Reitz
403c581e57 fix: Agenda-Breite im Home-Sidebar füllt volle 300px
- DayAgenda: fullWidth-Prop ergänzt (setzt .agendaFull → width: 100%)
- Im Kalender-Tab bleibt die Agenda bei 260px (flex-shrink: 0)
- HomeSidebar übergibt fullWidth, sodass die Agenda den Sidebar
  lückenlos ausfüllt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 12:32:38 +01:00
Thomas Reitz
653464c89b feat: Kompakter Messe-Ticker im Home-Sidebar mit Detail-Popup
- EventCountdownTiles aus homeMain entfernt
- Neuer CompactMesseTicker im Sidebar: kleine klickbare Zeilen
  mit farbiger linker Linie (blau=bevorstehend, grün=läuft)
- Klick öffnet MesseDetailModal: Name, Status-Chip, Countdown,
  Fortschrittsbalken (bei laufenden Messen), Datum, Ort/Stand,
  Beschreibung, Website-Link
- HomeDayAgendaWidget → HomeSidebar: zeigt Ticker + Tages-Agenda
  in einer Spalte; Sidebar auf 300px verbreitert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 12:27:07 +01:00
Thomas Reitz
3b15c8ab9b feat: Aufgaben-Tab im Dashboard (O365 + CRM bidirektional)
- GraphService: graphPost/graphPatch Helfer; getAllTasksFlat (inkl.
  Body für CRM-Sync-Marker), createM365Task, completeM365Task
- Office365Controller: GET tasks/flat, POST tasks, PATCH tasks/:listId/:taskId/complete
- ActivitiesService/Controller: GET /crm/activities/open-tasks
  (TASK + FOLLOWUP, nicht erledigt)
- Frontend types: M365TaskFlat + CrmOpenTask Interfaces
- Frontend api/hooks: getTasksFlat, createTask, completeTask,
  getOpenTasks; neue Hooks useOffice365TasksFlat, useCrmOpenTasks,
  usePushTaskToO365, useCompleteO365Task, useCompleteCrmTask
- DashboardTasksTab: vereinheitlichte Aufgabenliste mit Farbcodierung
  (O365 blau, CRM orange, Synced grün), Push-Button, Erledigen-Button
- Bidirektionaler Sync via [INSIGHT_CRM:{activityId}] Marker im O365
  Task Body; Erledigen eines Synced-Tasks aktualisiert beide Systeme
- DashboardPage: Tasks-Tab auf DashboardTasksTab umgestellt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 12:01:04 +01:00
Thomas Reitz
fbf0b33a1f feat(dashboard): E-Mail Lesefenster + Kalender Umbau
E-Mail Tab:
- Klick auf E-Mail öffnet Detail-Modal (Lesefenster wie Outlook)
- Modal zeigt: Betreff, Absender, Datum, Anhang-Info, Body-Vorschau
- CRM-Bereich: gefundener Kontakt mit "Im CRM öffnen" + "Als Aktivität"
  speichern; kein Kontakt → "Kontakt anlegen" navigiert zu /crm/contacts
- "In Outlook öffnen" Link im Footer des Modals

Kalender Tab:
- WeekView: nur Arbeitstage Mo–Fr (5-Spalten-Grid statt 7)
- Neue Ansicht "Agenda": 14-Tage-Listenansicht (eigener Toggle-Button)
- Tages-Agenda nur bei Monat- und Wochenansicht sichtbar (nicht Agenda-View)
- Home-Tab: Tages-Agenda des heutigen Tages als Widget rechts
  (nur sichtbar wenn M365 verbunden)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 11:36:30 +01:00
Thomas Reitz
f2ed8d0a93 fix(dashboard): Kalender-Toggle immer sichtbar, E-Mail Breite auf 70% angepasst 2026-03-13 11:20:01 +01:00
Thomas Reitz
53666122d0 fix(dashboard): E-Mail Bereich auf 50% Breite begrenzen, Textumbruch aktivieren 2026-03-13 11:16:28 +01:00
Thomas Reitz
76e8dff577 feat(dashboard): Kalender-Tab mit Monats-/Wochenansicht und Tages-Agenda
- Graph API: getCalendarEventsForRange() für beliebigen Datumsbereich,
  GET /crm/office365/calendar/range?startDate=&endDate= Endpoint
  (vor bestehenden calendar-Route definiert um Routing-Konflikt zu vermeiden)
- Graph API: wellKnownName aus mailFolders $select entfernt (400-Fehler auf
  Exchange-Tenants die das OData-Property nicht unterstützen)
- Frontend: DashboardCalendarTab mit MonthView (6×7 Grid), WeekView (7 Spalten)
  und DayAgenda (rechts 1/3), Navigation vor/zurück + Heute-Button,
  deterministisches Event-Coloring, Klick öffnet Termin in Outlook Online
- Frontend: DashboardEmailTab Ordner-Sortierung auf Display-Name-Basis
  (wellKnownName optional, isInboxFolder() erkennt Posteingang/Inbox)
- Frontend: M365MailFolder.wellKnownName als optional markiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:54:32 +01:00
Thomas Reitz
b6b182a349 fix(dashboard): E-Mail Tab lädt sofort mit well-known Inbox-ID als Fallback
Vorher: activeFolderId war null bis Ordnerliste geladen → E-Mail-Query nie gestartet
Jetzt: Default-Ordner-ID = 'inbox' (Graph API Well-Known-Name) → sofortiger Abruf
Zusätzlich: Fehler-/Leer-Zustand in der Ordner-Sidebar anzeigen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:32:04 +01:00
Thomas Reitz
01dc8bb41c feat(dashboard): E-Mail Tab mit Outlook-Postfach, Ordner-Navigation und Aktivitäten-Speicherung
- GraphService: getMailFolders() + getMailsByFolder(folderId, days) Methoden
- Office365Controller: GET /crm/office365/folders und /folders/:id/messages?days=X Endpoints
- ContactsController/Service: GET /crm/contacts/lookup?email=xxx für CRM-Kontakt-Abgleich
- Frontend types: M365MailFolder + CrmContactLookup Interfaces
- Frontend API: office365Api.getMailFolders/getMailsInFolder + contactsApi.lookupByEmail
- Frontend Hooks: useOffice365MailFolders, useOffice365MailsInFolder, useContactByEmail
- DashboardEmailTab: Ordner-Sidebar, Zeitfilter (1/7/14 Tage/alle), E-Mail-Liste
  mit Outlook-Link, CRM-Badge bei bekannten Absendern, Aktivitäten-Modal mit Kommentar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:16:05 +01:00
Thomas Reitz
f6dd072f23 feat(dashboard): 5 Tabs — Home, E-Mail, Kalender, Aufgaben, Kontakte
Tab-Leiste auf Dashboard-Seite. Home zeigt bisherigen Inhalt,
restliche Tabs als Platzhalter (Inhalt folgt).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 09:49:12 +01:00
Thomas Reitz
ad9c48bcb6 feat(crm): Office365-Übersichtsseite + Graph API Bugfixes
- Neuer Office365-Menüpunkt mit 4 Tabs (E-Mails, Kalender, Kontakte, Aufgaben)
- CRM-Service: Office365Controller mit globalen Graph-Endpoints
- Fix: $search + $orderby Kombination in Graph API nicht erlaubt
- M365Contact Interface + attendees/hasAttachments Typen ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 06:59:52 +01:00
Thomas Reitz
237e0772e6 feat(crm): Kanban-Board mit Drag & Drop (Phase 3.0)
- Neue KanbanPage (/crm/kanban) mit @dnd-kit/core + @dnd-kit/sortable
- Columns pro Pipeline-Stage mit Deal-Karten
- Cross-Column Drag & Drop — stageId per PATCH /crm/deals/:id aktualisiert
- Optimistisches Update: sofortiges visuelles Feedback, Rollback bei Fehler
- Toggle-Button für abgeschlossene Vorgänge (WON/LOST)
- Pipeline-Selektor, Gesamt-Wert pro Spalte (offene Deals)
- NavLink "Kanban" in AppLayout.tsx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 22:29:01 +01:00
Thomas Reitz
27507f1372 feat(crm): move Import-Wizard into CRM-Settings tab
Import ist kein eigener Nav-Eintrag mehr, sondern ein Tab
in den CRM-Einstellungen. /crm/import redirectet auf /crm/settings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 21:00:19 +01:00
Thomas Reitz
fdab2d5bcb feat(crm): Phase 2.2-2.4 frontend — Forecast, Import, Enrichment
Phase 2.3 Forecast:
- probability field on PipelineStage (types, edit UI, add-stage form)
- ForecastPage with pipeline filter, period selector, summary cards, table
- forecastApi + useForecast hook
- /crm/forecast route + "Prognose" nav link

Phase 2.2 CSV/Excel Import:
- 3-step wizard ImportPage (Upload → Mapping → Result)
- Entity type selection, auto-mapping, duplicate strategy, preview table
- importApi (preview + execute) + useImportPreview/useImportExecute hooks
- /crm/import route + "Import" nav link

Phase 2.4 Data Enrichment:
- "Anreichern" button on CompanyDetailPage with suggestions modal
- Per-field accept with PATCH update
- enrichmentApi (enrich, getConfig, setConfig) + hooks
- NorthDataConfig in CRM Settings "Integrationen" tab
- API-Key management UI

All changes pass TypeScript strict mode (npx tsc --noEmit).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 19:37:54 +01:00
Thomas Reitz
405ab5f038 feat: add SSL/Domain admin page for custom HTTPS configuration
- Backend: 4 new endpoints in SettingsController (GET/POST/DELETE /settings/ssl, POST /settings/ssl/check-dns)
- Certificate validation via Node.js crypto.X509Certificate (PEM format, expiry, SAN match)
- DNS resolution check via dns.promises.resolve4
- Auto-generates Traefik dynamic config (ssl-domain.yml) with custom domain routing + HTTP->HTTPS redirect
- Frontend: AdminSslPage with DNS name input, cert/key upload, status display
- Docker: Core-service gets access to traefik-certs volume and dynamic config directory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:13:49 +01:00
Thomas Reitz
a85634a906 feat: add trade event (Messe-Timer) feature with admin CRUD and dashboard tiles
Backend: TradeEvent Prisma model, NestJS CRUD module with date validation
and tenant isolation. Frontend: Admin Events page with create/edit/delete
modals, dashboard countdown tiles showing upcoming/ongoing/ended events
with progress bars, and useEventCountdown hook for live timer updates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:33:19 +01:00
Thomas Reitz
4f05026bc8 feat(frontend): add Lexware Office Import/Export admin page
New admin page under /crm/lexware-sync with two tabs:
- Import: Search Lexware contacts and import as CRM company or contact
- Export: List CRM companies/contacts and push to Lexware Office
Accessible via CRM Settings page (admin-only).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 23:00:42 +01:00
Thomas Reitz
411a6bbbcb feat(crm): add CRM Settings page with module visibility toggles
- New CrmSettingsContext with localStorage persistence (later swappable to API)
- CrmSettingsPage: toggle switches per CRM module (Kontakte, Unternehmen,
  Vorgänge, Pipelines), only accessible for PLATFORM_ADMIN/TENANT_ADMIN
- CrmModuleGuard: route protection for disabled modules (redirect to dashboard)
- Sidebar: NavLinks conditionally rendered based on module settings
- "Einstellungen" NavLink in CRM section (admin-only, gear icon)
- CRM section hidden when all modules disabled and user is not admin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:22:16 +01:00
Thomas Reitz
36f571f5c3 feat(crm): add Company module + extend Contact/Deal with company relation
- New Company CRUD: CompaniesPage (list/search/pagination), CompanyFormModal,
  CompanyDetailPage (contacts + deals tables)
- Sidebar: "Unternehmen" NavLink between Kontakte and Vorgänge
- ContactsPage: Company column, ContactFormModal: company search + position field,
  ContactDetailPage: company link + position display
- DealsPage: Company column, DealFormModal: company search dropdown,
  DealDetailPage: company link in info card
- Types/API/Hooks extended with Company entity, cross-entity query invalidation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:10:58 +01:00
Thomas Reitz
0b78160f33 feat(crm): inline stage editing, DealDetail optimization, rename Deals to Vorgänge
- PipelinesPage: Stages können jetzt per Doppelklick oder Stift-Icon
  inline bearbeitet werden (Name, Farbe) via PATCH endpoint
- DealDetailPage: Nutzt jetzt deal.pipeline.stages direkt statt
  separatem usePipeline() API-Call (Backend liefert alle Stages mit)
- UI-Texte: "Deals" → "Vorgänge", "Deal" → "Vorgang" in allen
  user-facing Strings (Sidebar, Seiten, Modals, Fehlermeldungen)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:38:58 +01:00
Thomas Reitz
c739dce161 feat: CRM Frontend-Modul mit Kontakte, Deals, Pipelines und Aktivitäten
Komplette CRM-Frontend-Integration in die bestehende React-GUI:

- Types, API-Client und React Query Hooks für alle CRM-Entitäten
- Kontakte: Liste mit Suche/Filter, Detail mit Aktivitäten-Timeline, Create/Edit Modal
- Deals: Liste mit Pipeline/Stage/Status-Filter, Detail mit Fortschrittsbalken, Create/Edit Modal
- Pipelines: Verwaltungsseite mit klappbaren Cards und Stage-Management
- Aktivitäten: Formular-Modal für Notizen, Anrufe, E-Mails, Meetings, Aufgaben
- CRM-Navigation in Sidebar (aufklappbar, mit Inline-SVG-Icons)
- Routen in App.tsx für alle CRM-Seiten
- Vite-Proxy für lokale CRM-API-Entwicklung

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:13:02 +01:00
Thomas Reitz
43877bbb4a docs(crm): update Summarize.md with deployment status and test results
All CRM endpoints tested successfully on insight-dev-01.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 18:08:00 +01:00
Thomas Reitz
96834c541c fix: enlarge brand/logo section in sidebar
- Increase min-height from 56px to 68px
- Logo maxHeight 32px → 44px, maxWidth 140px → 160px
- Brand title font-size 1.25rem → 1.5rem
- More padding in brand area

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:17:14 +01:00
Thomas Reitz
ca3938a933 fix: move theme toggle below profile section in sidebar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:16:24 +01:00
Thomas Reitz
3bedda2b9d feat: dark mode, collapsible sidebar, branding customization
- Add Light/Dark/System theme toggle with ThemeContext and CSS variables
- Sidebar fully collapsible (icons-only mode, persisted in localStorage)
- Anwendungen section collapsible with chevron toggle
- Admin "Anpassungen" page: logo upload, sidebar color picker with presets
- Backend branding endpoints (GET/POST /settings/branding) stored in Redis
- Optional custom icon upload for external links (click icon field)
- Backend favicon proxy with HTML parsing for reliable icon loading
- Dark mode CSS variables for all components
- Login page SSO button and error styles use CSS variables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:47:51 +01:00
Thomas Reitz
0f9b3d4f36 feat: backend favicon proxy with HTML parsing, collapsible sidebar sections
- Add GET /settings/favicon?url= endpoint that parses HTML for <link rel="icon"> tags
- Falls back to /favicon.ico if no icon link found in HTML
- Caches favicon URLs in Redis (24h TTL)
- Frontend uses backend proxy for reliable favicon loading (fixes Atlassian etc.)
- Anwendungen section in sidebar is now collapsible with chevron toggle

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:29:19 +01:00
Thomas Reitz
0a52606012 fix: use direct favicon.ico, open links in app mode (popup window)
- Favicon loaded directly from website's /favicon.ico instead of
  Google's service (which was unreliable/blocked on internal networks)
- Letter-initial fallback when favicon can't be loaded
- External links open in popup window (app mode) instead of new tab

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:23:11 +01:00
Thomas Reitz
65c5c7b7dd feat: use website favicons instead of manual icon upload
External links now automatically show the favicon of the target website
using Google's favicon service. No manual icon upload needed — just
enter label and URL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:19:34 +01:00
Thomas Reitz
f89e06c09d fix: use proper gear icon for admin section in sidebar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:11:48 +01:00
Thomas Reitz
1a87356048 feat: restructure admin area with separate layout, external links management
- Admin section moved to dedicated area with horizontal tab navigation
- Sidebar now shows gear icon link to Administration (PLATFORM_ADMIN only)
- External links management page for configuring sidebar shortcuts
- External links displayed in sidebar for all authenticated users
- Backend: Redis-based CRUD endpoints for external link configuration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:04:43 +01:00
Thomas Reitz
eba738fdc5 feat: add SSO configuration page in admin section
New admin page at /admin/sso with:
- Live SSO status indicator (active/not configured)
- Step-by-step Azure App Registration guide
- Required values table (Tenant ID, Client ID, Client Secret)
- API permissions list (openid, profile, email, User.Read)
- Redirect URI with copy button
- Environment variables template
- Technical reference (endpoints, security info)

Accessible via sidebar: Administration → SSO-Konfiguration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:39:55 +01:00
Thomas Reitz
45cf644f81 feat: add Microsoft Entra ID (Azure AD) SSO integration
Backend-driven Authorization Code Flow with @azure/msal-node:
- EntraIdService: MSAL ConfidentialClientApplication, auth URL generation, token exchange
- SsoController: /auth/sso/microsoft (initiate) + /auth/sso/microsoft/callback (callback)
- AuthService.loginViaSso(): User provisioning (find by OID, auto-link by email, or create new)
- CSRF protection via state parameter stored in Redis
- SSO status endpoint for frontend feature detection

Frontend:
- "Mit Microsoft anmelden" button on login page (shown only when SSO is configured)
- SsoCallbackPage: handles redirect from backend, sets token, loads user profile
- AuthContext.loginWithToken(): new method for SSO token handling

Configuration:
- AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_REDIRECT_URI env vars
- docker-compose.yml updated to pass Azure vars to core service

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:31:34 +01:00
Thomas Reitz
c8703ef3e0 feat: add profile page tabs and fix German umlauts throughout app
- Add tab navigation to profile page (Persönliche Informationen, Experten Profil, Passwort ändern)
- Experten Profil tab as placeholder for future content
- 2FA section remains always visible below tabs
- Fix all German umlauts (ae→ä, oe→ö, ue→ü, ss→ß) in frontend and backend
- Fix validation messages, error messages, comments, and UI text

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 07:56:55 +01:00
Thomas Reitz
6fa86714db feat: add profile picture upload, sidebar hint, and fix 2FA bugs
- Bug fix: include twoFactorEnabled in login response so ProfilePage
  shows correct 2FA status after login (not always "Aktivieren")
- Bug fix: restructure 2FA enable/disable handlers to separate API call
  from state updates, preventing false error messages on success
- New: avatar field in User model (Base64 data-URL in PostgreSQL TEXT)
- New: UserAvatar component with initials fallback
- New: client-side image resize to 200x200px before upload
- New: avatar upload/remove on ProfilePage with preview
- New: avatar display + "Zum Profil" hint in sidebar
- Increase JSON body size limit to 1mb for avatar uploads

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 06:51:27 +01:00
Thomas Reitz
779d90ca43 feat: add user profile page with 2FA management and password change
Backend:
- POST /auth/2fa/setup - generate TOTP secret + QR code (temp Redis storage)
- POST /auth/2fa/enable - verify TOTP code and activate 2FA
- POST /auth/2fa/disable - deactivate 2FA (requires password)
- PATCH /users/me - update own profile (firstName, lastName)
- POST /users/me/change-password - change own password

Frontend:
- New ProfilePage with 3 sections: personal info, password, 2FA
- QR code display for Authenticator app setup
- Clickable user info in sidebar navigates to /profile
- AuthContext extended with twoFactorEnabled + refreshUser

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 20:24:44 +01:00
Thomas Reitz
10f291cdda feat: implement Sprint 1 Alpha - full stack with Docker, NestJS, React
Docker Infrastructure:
- docker-compose.yml with Traefik 3, PostgreSQL 16, PgBouncer, Redis 7, step-ca
- docker-compose.observability.yml with Prometheus, Grafana, Loki, Tempo, Promtail
- Traefik dynamic config (TLS, security headers, CORS, compression)
- PostgreSQL init script (uuid-ossp, pgcrypto, pg_trgm extensions)
- Grafana auto-provisioned datasources (Prometheus, Loki, Tempo)

NestJS Core-Service:
- Auth module: Login (email/password), TOTP 2FA, JWT RS256, token refresh/revocation
- Users module: CRUD, bcrypt cost 12, pagination, role-based access
- Tenants module: CRUD, member management, slug validation
- Prisma schemas: core (Users, AuthProviders, Tenants, Modules, AuditLog)
                  tenant (Contacts, Activities - CRM reference for Sprint 2)
- TenantPrismaService: Dynamic per-tenant DB connections with caching
- RedisService: Token blocklist, refresh token families, generic cache
- Global JwtAuthGuard with @Public() decorator, RolesGuard, GlobalExceptionFilter
- Health endpoint with DB + Redis status checks
- Swagger API documentation (dev only)
- Multi-stage Dockerfile (dev + production)

React Frontend:
- Vite 6 + React 18 + TypeScript strict
- AuthContext with silent refresh (access token in memory, NOT localStorage)
- Login page with TOTP 2FA support
- App shell with sidebar navigation
- Admin pages: Users + Tenants management tables
- API client with automatic token refresh interceptor
- Multi-stage Dockerfile (dev + nginx production)

CI/CD Pipelines:
- ci.yml: Lint, type-check, test, build on all branches
- deploy.yml: Docker build, push to Forgejo registry, SSH deploy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:33:36 +01:00
Thomas Reitz
5f54bde55e chore: project initialization with infrastructure definition and structure
- Generate SSH deployment key (Ed25519) for server access
- Define complete server infrastructure (ProxmoxVE VM, Docker, networking)
- Create ACCESS.md with all connection details and SSH instructions
- Create INFRASTRUCTURE.md with VM setup guide and service architecture
- Set up project directory structure per briefing specification
- Add .env.example with all required environment variables
- Add .gitignore for Node.js/Docker/TypeScript project
- Create comprehensive README.md for developer onboarding
- Add Summarize.md changelog
- Include concept and briefing documents

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 10:22:55 +01:00