diff --git a/docs/todo.md b/docs/todo.md
index 3284dc52..7b8eebe1 100644
--- a/docs/todo.md
+++ b/docs/todo.md
@@ -97,6 +97,13 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
## ✅ Erledigt
+- [x] **🎂 Anstehende Geburtstage auch im Dashboard**
+ - Die Geburtstags-Sektion gab es bisher nur im Vertrags-Cockpit.
+ Jetzt 1:1 auch auf dem Dashboard (nur Mitarbeiter/Admin,
+ `enabled: !isCustomer`), gleiche `birthdayApi.getUpcoming(7, 30)`-
+ Query + identische Karten-Darstellung (Heute/vergangen/kommend,
+ Link auf die Kundenakte). Kein Backend-Change nötig.
+
- [x] **🔴 Pentest R121 – Audit-Verify: Fehlalarm „manipuliert" bei leerem resourceId**
- `POST /api/audit-logs/verify` meldete ~73% der Einträge als
manipuliert. Kein echtes Tampering, sondern ein Bug in
diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx
index 8f89df43..1cc43f4b 100644
--- a/frontend/src/pages/Dashboard.tsx
+++ b/frontend/src/pages/Dashboard.tsx
@@ -2,11 +2,14 @@ import { useState, useMemo } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { Link, useNavigate } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
-import { customerApi, contractApi, contractTaskApi, appSettingsApi } from '../services/api';
+import { customerApi, contractApi, contractTaskApi, appSettingsApi, birthdayApi } from '../services/api';
import { buildContractLabelParts } from '../utils/contractLabel';
+import { pushHistory } from '../utils/navigation';
+import { formatDate } from '../utils/dateFormat';
import Card from '../components/ui/Card';
import Button from '../components/ui/Button';
import Input from '../components/ui/Input';
+import Badge from '../components/ui/Badge';
import Modal from '../components/ui/Modal';
import {
Users,
@@ -20,6 +23,7 @@ import {
Plus,
Clock,
XCircle,
+ Cake,
} from 'lucide-react';
import type { Contract } from '../types';
@@ -79,6 +83,14 @@ export default function Dashboard() {
staleTime: 0,
});
+ // Anstehende Geburtstage (kommende 30 Tage + vergangene 7) – wie im Cockpit,
+ // nur für Mitarbeiter/Admins.
+ const { data: birthdaysData } = useQuery({
+ queryKey: ['upcoming-birthdays'],
+ queryFn: () => birthdayApi.getUpcoming(7, 30),
+ enabled: !isCustomer,
+ });
+
// Für Kundenportal: Verträge nach eigene/fremd gruppieren
const { ownContracts, representedContracts } = useMemo(() => {
if (!isCustomerPortal || !contractsData?.data) {
@@ -378,6 +390,60 @@ export default function Dashboard() {
)}
+ {/* Anstehende Geburtstage (wie im Cockpit) */}
+ {birthdaysData?.data && birthdaysData.data.length > 0 && (
+
+ Kunden mit Geburtstag in den nächsten 30 Tagen oder den letzten 7 Tagen.
+
+ {formatDate(b.birthDate)} – wird {b.age} Jahre
+ Geburtstage
+