Commit graph

69 commits

Author SHA1 Message Date
Thomas Reitz
068a7b81d5 fix(crm): fix voucher ID mapping — Lexware API returns 'id' not 'voucherId'
The voucherlist endpoint returns items with 'id' field, but our interface
defined it as 'voucherId', causing undefined IDs when fetching voucher details.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 18:37:23 +01:00
Thomas Reitz
4924875e92 fix(crm): add mandatory voucherStatus=any to Lexware voucherlist API call
The Lexware Office API requires voucherStatus as a mandatory parameter
for the /v1/voucherlist endpoint. Without it, the API returns 400 Bad
Request. Using 'any' fetches vouchers regardless of status.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 12:00:29 +01:00
Thomas Reitz
b4d1f33862 chore(crm): log Lexware API error response body for debugging
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:57:52 +01:00
Thomas Reitz
00f6b9842e fix(crm): link imported Ansprechpartner to CRM company via companyId
When importing contact persons from Lexware, if the parent company
is already in the CRM (detected via linkedMap), the companyId is now
passed to createContact so the contact is properly associated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:20:07 +01:00
Thomas Reitz
332a623d6f fix(crm): fix Lexware import duplicate detection — pageSize 500 exceeded backend max 100
The backend DTO validation enforces @Max(100) on pageSize. The ImportTab
was requesting pageSize=500, causing a 400 Bad Request. This left the
linkedMap empty and showed import buttons for already-imported contacts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:12:32 +01:00
Thomas Reitz
6e77bf43b0 feat(crm): prevent duplicate Lexware imports — show linked status in import list
Import tab now loads all CRM companies/contacts and cross-references
lexwareContactId to detect already-imported entries. Linked contacts show
a green badge and "Öffnen" link instead of import buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:48:32 +01:00
Thomas Reitz
ba4eec951a fix(crm): fix Lexware import 500 — tenantId validation in TenantGuard and service
- TenantGuard: remove PLATFORM_ADMIN bypass, require tenantId for all users
- lexware-contacts.service: add defensive tenantId check in importAsCompany
  and importAsContact with clear BadRequestException message

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:34:46 +01:00
Thomas Reitz
833bc44acd Update 2026-03-11 10:21:14 +01:00
Thomas Reitz
0ed1e77844 feat(crm): add company detail overhaul with industries, account types, relationship types
- Backend: new CRUD services/controllers for Industries, AccountTypes,
  RelationshipTypes, CompanyRelationships with Prisma schema migration
- Frontend: new hooks, API functions, and types for all config entities
- CompanyDetailPage redesign with ActivityFeed, RelationshipsCard
- CompanyFormModal extended with industry, account type, owner fields
- Activities service now supports companyId filter + includeContacts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 09:21:57 +01:00
Thomas Reitz
4e5c26cadd feat(frontend): add tabbed layout to CRM Settings page
- Restructure CRM Settings into 3 tabs: Module | Lexoffice Sync | Weitere Einstellungen
- Extract LexwareSyncContent as reusable component from LexwareSyncPage
- Embed Import/Export directly in Settings "Lexoffice Sync" tab
- Move Industries, AccountTypes, RelationshipTypes configs to "Weitere Einstellungen" tab
- Keep standalone /crm/lexware-sync route as fallback
- Add tab bar styles matching existing design pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 09:07:16 +01:00
Thomas Reitz
55329188f6 feat(frontend): redesign Lexware Import with browsable list + Ansprechpartner
- Replace search-only ImportTab with paginated browsable list of all Lexware contacts
- Add expandable Ansprechpartner (contact persons) section per company
- Individual Ansprechpartner can be imported as CRM contacts
- Add pagination controls for navigating large contact lists
- Search filter still available (min. 3 chars, backend MinLength constraint)
- Clean up useLexwareContacts hook with proper query key

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 07:21:05 +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
6b847cb9f6 fix(frontend): move hooks before conditional return in Lexware components
React hooks must not be called after conditional returns (Rules of Hooks).
Moves all hook calls above the isModuleEnabled check in LexwareSection
and DealVouchersSection to prevent silent component crashes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 22:37:30 +01:00
Thomas Reitz
2381409e6d feat(frontend): add Lexware Office integration UI
Implements complete Lexware Office frontend integration:
- Types: LexwareVoucher, DealVoucher, LexwareContact, VoucherType
- API: lexwareContactsApi + lexwareVouchersApi (16 endpoints)
- Hooks: React Query hooks for search, link/unlink, sync, vouchers
- LexwareSection: reusable component for Company/Contact detail pages
  with status badge, sync/push/refresh buttons, and voucher table
- LexwareSearchModal: search Lexware contacts and link to CRM entities
- DealVouchersSection: link/unlink vouchers on Deal detail page
- CRM Settings: Lexware Office toggle (admin-configurable)
- Company/Contact/Deal detail pages extended with Lexware sections

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 22:20:18 +01:00
Thomas Reitz
9d496d2e53 feat(crm): integrate Lexware Office for vouchers and contact sync
Adds complete Lexware Office integration to CRM service:
- Rate-limited HTTP client (Token Bucket, 2 req/s)
- Bidirectional contact sync (manual import + ERP-push)
- Voucher caching (quotes, orders, invoices, credit notes)
- Deal-voucher linking (m:n join table with audit)
- Cron jobs: voucher refresh (4h), ERP push (30min)
- Distributed locks via Redis for job deduplication
- Health check extended with Lexware status
- Prisma schema: LexwareVoucher, DealVoucher, VoucherType enum
- Companies/Contacts/Deals services extended with Lexware data

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:28:41 +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
a13cca054b docs(crm): document Company entity for frontend developer
Update INSIGHT-CRM.md with complete Company API documentation,
Contact/Deal changes (companyId, position), and frontend integration
suggestions. Update Summarize.md with current test results.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:47:39 +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
56a9ed9647 feat(crm): add Company entity + rename Deals to Vorgaenge
- New Company model with full CRUD under /api/v1/crm/companies
- Contact now has companyId relation + position field
- Deal now has companyId relation
- Company detail includes contacts (top 20) and deals (top 10)
- All endpoints include company in responses
- Swagger tags renamed: Deals -> Vorgaenge (Deals)
- Error messages use "Vorgang" instead of "Deal"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:30:34 +01:00
Thomas Reitz
c9e2c4a44c feat(crm): add PATCH endpoint for pipeline stages + HTTPS router
- New PATCH /pipelines/:id/stages/:stageId endpoint to update
  stage name, color, and sortOrder
- Added HTTPS (websecure) Traefik router for CRM service
- Both requested by frontend developer via INSIGHT-CRM.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:22:33 +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
b3eb533fa7 chore(crm): add package-lock.json for Docker build
npm ci requires package-lock.json to ensure reproducible builds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:20:35 +01:00
Thomas Reitz
094db465cb feat(crm): add standalone dev environment and test token generator
- docker-compose.crm-dev.yml: isolierte Testumgebung (PostgreSQL + Redis + CRM)
- scripts/generate-token.ts: generiert Test-JWTs fuer curl-basiertes API-Testing
- scripts/init-schema.sql: erstellt app_crm Schema beim DB-Start
- keys/: Test-RSA-Schluessel (nur fuer lokale Entwicklung!)
- Fix: multiSchema previewFeature entfernt (deprecated)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:03:59 +01:00
Thomas Reitz
8783d01fc0 feat(crm): scaffold CRM service with full CRUD modules
Eigenstaendiger NestJS-Service unter packages/crm-service/ mit:
- Prisma Schema (app_crm): Contact, Activity, Pipeline, PipelineStage, Deal
- JWT RS256 Auth mit shared Public Key und Token-Revocation
- Multi-Tenancy: TenantGuard + tenantId-Filter auf allen Queries
- CRUD-Module: Contacts, Activities, Pipelines, Deals
- Docker-Integration: docker-compose.crm.yml (Port 3100, Traefik-Route /api/v1/crm)
- Health-Check, Swagger, GlobalExceptionFilter, Pagination

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:54:13 +01:00
Thomas Reitz
8f738cadb5 chore: hide Mandanten tab from admin navigation
Temporarily removed until multi-tenancy is implemented.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:20:54 +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
878f8be45c fix: replace crypto.randomUUID with HTTP-compatible alternative
crypto.randomUUID() is only available in secure contexts (HTTPS).
Since the app runs over HTTP in development, this caused a blank page
crash on the external links admin page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:08:21 +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
79635c31d2 Update 2026-03-09 22:51:42 +01:00
Thomas Reitz
bc156e1657 feat: dynamic SSO configuration via Admin UI
SSO config (Tenant ID, Client ID, Client Secret, Redirect URI) can now
be managed entirely from the Admin SSO page. Config is stored in Redis
(persistent) and the MSAL client is reinitialized on save — no server
restart or console access required.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:51:01 +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
8efaa49930 feat: add user deletion (backend endpoint + frontend with confirmation)
- Backend: DELETE /api/v1/users/:id endpoint (PLATFORM_ADMIN only)
- Frontend: "Löschen" button with confirmation modal
- Cascading deletes handle auth providers, memberships, profiles

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:00:06 +01:00
Thomas Reitz
85574a85aa feat: add user management UI (create, edit, activate/deactivate)
- New UserFormModal component for creating and editing users
- AdminUsersPage: add "Neuer Benutzer" button, actions column
- German role labels, toggle activate/deactivate from table
- Uses React Query mutations with query invalidation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 21:32:11 +01:00
Thomas Reitz
c8499a0979 feat: circular avatar in DOCX export using sharp
Uses sharp to resize and apply a circular SVG mask to the avatar
before embedding it in the Word document, matching the PDF export.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:39:39 +01:00
Thomas Reitz
f4239760df fix: add PNG icons and Arial font to DOCX export
Replaces text labels (Tel., Mobil, Mail, Adr.) with recolored PNG icons
in the Word export contact section. Sets Arial as default document font
to match Helvetica in the PDF export.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:27:32 +01:00
Thomas Reitz
b948027dab feat: recolor PNG contact icons to match accent color at runtime
Uses pngjs to replace all visible pixels in PNG icons with the
configured accent color while preserving alpha transparency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:22:37 +01:00
Thomas Reitz
9a9800e17e feat: use PNG contact icons in PDF export instead of vector drawing
- Add Phone.png, Mobile.png, Mail.png, Address.png icon assets
- Replace hand-drawn vector icons with professional PNG icons
- Icons stored in packages/core-service/assets/icons/ (included in Docker build)
- Also stored in templates/cv/default/ and Icons/ for reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:11:40 +01:00
Thomas Reitz
ea5dfda913 feat: add 'Verhandlungssicher' language level option
Language levels now: Muttersprache, Verhandlungssicher, Fließend, Gut

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:25:18 +01:00
Thomas Reitz
c40d768827 fix: redesign handset icon as solid silhouette with filled crescent handle
Replace disconnected rectangles+stroke with seamless shape:
earpiece and mouthpiece blocks connected by filled crescent arc

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:22:04 +01:00
Thomas Reitz
0c195dc3a9 fix: separate handset icon (landline) and smartphone icon (mobile) in PDF export
- Landline phone: classic telephone handset with earpiece, mouthpiece and curved connector
- Mobile phone: smartphone outline with display and home button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:17:47 +01:00
Thomas Reitz
82af9cb1f0 fix: improve PDF contact icons - smartphone, envelope and map pin shapes
Replaced rough vector shapes with proper recognizable icons:
- Phone: smartphone outline with display area and home button
- Email: envelope with cleaner V-flap proportions
- Location: smooth teardrop map pin using bezier curves

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:14:32 +01:00