diff --git a/AGENTS.md b/AGENTS.md index 66c3e52..8298067 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -39,6 +39,31 @@ churchtoolsClient.get("/api/endpoint", { params: { param1: "value1" } }) - OpenAPI spec shows `{ data: [...], meta: {...} }` but client unwraps this - Use `response` directly, not `response.data` +## Base URL Pattern ⚠️ + +**Always use centralized `getChurchtoolsBaseUrl()` function for URL building:** + +✅ **Correct** (in `src/services/churchtools.ts`): + +```typescript +import { getChurchtoolsBaseUrl } from '../../services/churchtools' + +const baseUrl = getChurchtoolsBaseUrl() +const url = new URL(baseUrl) +url.searchParams.set('q', 'churchcal') +// ... build URL +``` + +❌ **Wrong** (repeating logic): + +```typescript +const baseUrl = import.meta.env.DEV + ? import.meta.env.VITE_BASE_URL + : window.location.origin +``` + +**Why**: Centralized function ensures consistency across dev/prod and avoids duplication. Works with `npm run dev` (VITE_BASE_URL) and production (window.location.origin). + ## Component Structure Follow this pattern for new modules: diff --git a/CHANGELOG.md b/CHANGELOG.md index fed1f2e..dfb8993 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,33 @@ und dieses Projekt folgt [Semantic Versioning](https://semver.org/spec/v2.0.0.ht ## [Unreleased] +## [1.1.0] - 2026-04-17 + +### ✨ Added + +- **Room Booking Requests Module** - Complete management interface for ChurchTools room bookings + - Dashboard card with booking statistics + - Admin panel with full CRUD operations + - Booking detail view modal + - Conflict details modal with creator information + - Advanced filtering (date range, room, conflict status, booking status) + - Full-text search across booking fields + - Sortable columns + - Bulk operations (approve, reject, delete) + - Automatic email notifications on rejection + - Soft-delete support (statusId 99) + - Recurring series handling with deduplication + - Conflict detection with time-overlap validation + - Type-safe TypeScript composable (`useRoomBookings.ts`) + - Permission integration (`churchresource.administer bookings`) + +### 📚 Documentation + +- `docs/raumbuchungsanfragen/ANFORDERUNG.md` - Requirements specification +- `docs/raumbuchungsanfragen/API_ANALYSE.md` - API analysis and integration patterns +- `docs/raumbuchungsanfragen/IMPLEMENTATION_CHECKLIST.md` - Feature checklist +- `docs/raumbuchungsanfragen/COMPLETION_SUMMARY.md` - Implementation summary + ## [1.0.5] - 2025-09-26 ### 🐛 Fixed diff --git a/docs/ANFORDERUNG_Raumbuchungsanfragen.md b/docs/ANFORDERUNG_Raumbuchungsanfragen.md new file mode 100644 index 0000000..31a3b5c --- /dev/null +++ b/docs/ANFORDERUNG_Raumbuchungsanfragen.md @@ -0,0 +1,258 @@ +# Anforderungsdokument: Raumbuchungsanfragen Management + +## 📋 Übersicht + +Neue Dashboard-Sektion zur Verwaltung von Raumbuchungsanfragen mit Konflikt-Erkennung und Genehmigungsworkflow. + +## 🎯 Motivation & Probleme im bisherigen Prozess + +### Problem 1: Unzureichende Kommunikation bei Ablehnung + +**Aktuell**: Bemerkungen bei Ablehnung einer Ressourcenbuchung werden nicht in der Ablehnungsmail übermittelt +**Folge**: Admin muss zusätzlich noch manuell kommunizieren, warum eine Buchung abgelehnt wurde +**Lösung**: + +- Bemerkungen direkt in die Ablehnungsmail übernehmen +- Hinweis in Mail: "Weitere Details zur Ablehnung finden Sie in der Ressourcen-Buchung" +- Direktlink zur Buchung in der Mail (wenn technisch möglich) + +### Problem 2: Manuelle Konflikt-Erkennung ist fehleranfällig + +**Aktuell**: Admin sieht auf der Startseite eine Liste mit 100+ offenen Einträgen und muss jeden einzeln öffnen, um Konflikte zu erkennen +**Folge**: Zeitaufwendig, fehleranfällig, Konflikte werden leicht übersehen +**Lösung**: Dediziertes Dashboard mit Konflikt-Highlighting auf Listenlevel + +### Problem 3: Filter sind zu breit + +**Aktuell**: + +- Filter "offene Bestätigungen" zeigt ALLE Räume, nicht nur die mit offenen Anfragen +- Konflikte sind in der Filteransicht nicht sichtbar + **Folge**: Admin muss trotzdem weitere Filterung und Klicks machen, um relevante Buchungen zu finden + **Lösung**: +- Nur Räume/Ressourcen anzeigen, für die offene Anfragen existieren +- Konflikte direkt in der Listenansicht sichtbar +- Filterung nach Konflikten (mit/ohne) + +### Problem 4: Batch-Processing nicht möglich + +**Aktuell**: Jede Raumbuchung muss einzeln bestätigt werden, keine Bulk-Aktion +**Folge**: Viele Zeit für repetitive Aktionen (z.B. eine Woche mit unkritischen Buchungen bestätigen) +**Lösung**: Zeilen-Auswahl und Bulk-Operationen (Bestätigen/Ablehnen mehrerer Buchungen gleichzeitig) + +### Problem 5: Unklare Termine für Bucher + +**Aktuell**: Nutzer sehen manchmal nur "unbekannter Termin" im Kalender, weil sie die Berechtigung zum Einsehen haben +**Folge**: Nutzer verstehen nicht, warum ihre Buchung abgelehnt wurde; Konfusion beim Buchen +**Lösung**: + +- Klare Fehlermedlung/Hinweis beim Buchen, wenn Termin nicht sichtbar ist +- Evtl. in Ablehnungsmail erwähnen: "Der geplante Termin war für Sie nicht einsehbar" +- (Ggfs. im Rahmen separater Verbesserung an Buchungsoberfläche) + +## 🎯 Funktionale Anforderungen + +### 1. Raumbuchungsanfragen Übersicht (Dashboard Card) + +- **Anzeige**: Alle offenen Raumbuchungsanfragen +- **Spalten**: + - Raum / Ressource + - Datum / Uhrzeit + - Ersteller / Person (im Auftrag von) + - Status (offen / wartend) + - Konflikte (falls vorhanden) + - Aktionen + +- **Filterung**: + - Nach Status + - Nach Raum/Ressource + - Nach Datum + - Nach Konflikten (nur mit Konflikten / ohne Konflikte / alle) + - Freitext-Suche (durchsucht: Raum, Ersteller, Person, Bemerkungen) + +- **Sortierung**: + - Spalten sind sortierbar (Klick auf Spalten-Header) + - Standardsortierung: Datum aufsteigend + +### 2. Konflikterkennung + +- **Konflikt-Definition**: Überschneidende Buchungen zum gleichen Raum/gleicher Ressource im gleichen Zeitfenster +- **Visuelles Highlighting**: + - Zeile mit Konflikt-Indikator (z.B. rotes Icon/Badge) + - Liste der konfliktierenden Buchungen anzeigen + - Verantwortliche Person aus konfligierenden Buchungen identifizieren + +- **Konflikt-Details**: + - Welche andere Buchung(en) konfligieren + - Wer ist die verantwortliche Person (Ersteller/im Auftrag von) der Konflikt-Buchung(en) + +### 3. Admin-Panel (Verwaltungsbereich) + +- **Detailansicht** für jede Anfrage mit: + - Vollständige Buchungsdetails + - Konflikt-Informationen (falls vorhanden) + - Bemerkungen-Feld + +- **Zeilen-Auswahl**: + - Checkbox in jeder Zeile zur Markierung + - "Select All" Checkbox im Header (mit Status-Anzeige: "3 von 10 ausgewählt") + - Toggle Select All auch für gefilterte Liste + +- **Individuelle Aktionen** (pro Zeile): + - ✅ **Bestätigen**: Anfrage akzeptieren, Status → genehmigt + - ❌ **Ablehnen**: + - Bemerkungsfeld (erforderlich) + - Bestätigungs-Dialog + - E-Mail-Versand triggern + +- **Bulk-Operationen** (für markierte Zeilen): + - ✅ **Mehrere Anfragen bestätigen**: Alle markierten genehmigen + - ❌ **Mehrere Anfragen ablehnen**: Dialog mit gemeinsamer Bemerkung oder individuelle Bemerkungen + - 🗑️ **Löschen**: Markierte Anfragen löschen (nur in bestimmtem Status) + - Bulk-Aktion wird deaktiviert, wenn keine Zeile markiert ist + - Erfolgs-Feedback nach Bulk-Operation (z.B. "3 Anfragen genehmigt") + +### 4. E-Mail-Benachrichtigungen (bei Ablehnung) + +#### Standard-Ablehnung: + +- **Empfänger**: + - Ersteller der Anfrage + - Oder: Person "im Auftrag von" (falls angegeben) +- **Inhalt**: + - Raum/Ressource, Datum, Uhrzeit + - Begründung/Bemerkung vom Admin + - Optional: Alternativ-Zeiten vorschlagen + +#### Ablehnung mit Konflikt: + +- **Empfänger**: + - Ersteller/Person der abgelehnten Anfrage + - **PLUS**: Verantwortliche Person(en) aus konfligierenden Buchung(en) +- **Inhalt**: + - Begründung: "Konflikt mit Buchung von [Name]" + - Details der konfliktierenden Buchung(en) + - Bemerkung vom Admin + +## 🏗️ Technische Struktur + +Folgt dem Muster bestehender Module: + +``` +src/components/room-bookings/ +├── RoomBookingsCard.vue # Dashboard Card +├── RoomBookingsAdmin.vue # Admin Panel +└── useRoomBookings.ts # Composable mit API-Logik +``` + +## 📊 Datenmodelle + +### RoomBooking + +```typescript +{ + id: string + room: string + date: string // ISO-Date + startTime: string + endTime: string + createdBy: string // Person-ID + createdByName: string + onBehalfOf?: string // Person-ID (optional) + onBehalfOfName?: string + status: 'open' | 'approved' | 'rejected' + remarks?: string + conflicts?: ConflictInfo[] +} +``` + +### ConflictInfo + +```typescript +{ + conflictingBookingId: string + room: string + date: string + startTime: string + endTime: string + conflictingPerson: string // Ersteller oder "im Auftrag von" + conflictingPersonId: string + conflictingPersonEmail: string +} +``` + +## 🔌 API-Integration (ChurchTools) + +- [TBD] Endpoint für Raumbuchungsanfragen abrufen +- [TBD] Endpoint für Raumbuchung akzeptieren +- [TBD] Endpoint für Raumbuchung ablehnen +- [TBD] E-Mail-Service Integration (bestehend oder neu) + +## 🎨 UI/UX + +- Nutze **BaseCard** für Dashboard-Ansicht +- Nutze **AdminTable** für Admin-Panel (nach Muster Tags/AutomaticGroups) +- ChurchTools Design Classes (ct-btn, ct-card, ct-select, ct-modal) +- Konflikt-Highlighting: Rot/Orange Badge oder Icon + +## ✅ Akzeptanzkriterien + +### Grundfunktionalität + +- [ ] Dashboard zeigt alle offenen Raumbuchungsanfragen +- [ ] Konflikte werden erkannt und angezeigt + +### Filterung & Sortierung + +- [ ] Filterung nach Status funktioniert +- [ ] Filterung nach Raum/Ressource funktioniert +- [ ] Filterung nach Datum funktioniert +- [ ] Filterung nach Konflikten (mit/ohne) funktioniert +- [ ] Freitext-Suche durchsucht alle relevanten Felder +- [ ] Spalten sind sortierbar +- [ ] Sortierindikatoren sichtbar (Pfeil im Header) + +### Zeilen-Auswahl & Bulk-Operationen + +- [ ] Checkboxes in jeder Zeile funktionieren +- [ ] Select All Checkbox wählt/deselektiert alle Zeilen +- [ ] Select All Checkbox arbeitet mit gefilterten Daten +- [ ] Anzeige: "X von Y ausgewählt" ist korrekt +- [ ] Bulk-Buttons nur aktiv, wenn Zeilen markiert sind +- [ ] Bulk Bestätigung funktioniert +- [ ] Bulk Ablehnung funktioniert +- [ ] Erfolgs-Feedback nach Bulk-Operation angezeigt + +### Individuelle Aktionen + +- [ ] Admin kann einzelne Anfrage bestätigen +- [ ] Admin kann einzelne Anfrage mit Bemerkung ablehnen +- [ ] Bestätigungs-Dialog vor kritischen Aktionen + +### E-Mail-Versand + +- [ ] E-Mail wird an korrekten Empfänger versandt +- [ ] E-Mail enthält vollständige Informationen +- [ ] Konflikt-Info ist in E-Mail enthalten (falls zutreffend) + +### Code-Qualität + +- [ ] Komponenten folgen bestehendem Design-Pattern (BaseCard, AdminTable) +- [ ] TypeScript korrekt typisiert +- [ ] Code lässt sich mit `npm run lint` prüfen +- [ ] Keine Warnings/Errors beim Build + +## 📝 Nächste Schritte + +1. [x] Anforderungsdokument erstellen +2. [ ] Verfeinern & Clarification mit Stakeholder +3. [ ] ChurchTools API-Endpoints identifizieren +4. [ ] E-Mail-Template definieren +5. [ ] Module implementieren +6. [ ] Testen + +--- + +**Status**: Entwurf +**Erstellt**: 2026-04-16 +**Letzte Änderung**: 2026-04-16 diff --git a/docs/API_ANALYSE_Raumbuchungen.md b/docs/API_ANALYSE_Raumbuchungen.md new file mode 100644 index 0000000..5456758 --- /dev/null +++ b/docs/API_ANALYSE_Raumbuchungen.md @@ -0,0 +1,328 @@ +# API-Analyse: Raumbuchungsanfragen (Resource Bookings) + +## 🔍 Findings + +### Bestehende API-Endpoints für Raumbuchungen + +Das ChurchTools System hat bereits eine vollständige **Booking/Resource API** im OpenAPI-Schema (`ct-types.d.ts`): + +#### 1. **Datenmodelle vorhanden** ✅ + +- `BookingBase` - Basis-Buchung mit vollständigen Details +- `BookingCalculated` - Buchung mit berechneten Dates +- `BookingCalculatedWithIncludes` - **Mit Konflikten!** ⭐ +- `BookingConflict` - Konflikt-Informationen (bookingId, startDate, endDate, statusId, title) +- `BookingCreate` - Schema zum Erstellen einer Buchung +- `Resource` - Ressource/Raum-Definition +- `ResourceType` - Typ der Ressource + +#### 2. **Booking-Status & Konflikt-Handling** ✅ + +```typescript +// BookingBase enthält: +- id: number +- resourceId: number +- startDate: ZuluDate +- endDate: ZuluDate +- statusId: number +- title: string +- description: string | null +- createdBy: DomainObjectPerson +- onBehalfOfPid: number | null +- onBehalfOf: DomainObjectPerson (in involvedPersonsDomainObjects) + +// Konflikte sind explizit im Type: +BookingCalculatedWithIncludes: { + booking: BookingCalculated + conflicts?: Array +} + +// BookingConflict: +{ + bookingId: number + startDate: ZuluDate + endDate: ZuluDate + statusId: StatusId + title: string +} +``` + +#### 3. **Status-Handling** ✅ + +Das System hat `StatusId` Typen: + +- Verschiedene Booking-Status sind über `statusId` definiert +- API gibt Status explizit zurück +- Konflikte mit jeweiligem Status einzeln auflisten + +### ✅ Verifizierte API-Endpoints (aus OpenAPI-Doku) + +```typescript +// 1. Alle Bookings abrufen (mit Filtern & Includes) +GET /bookings + params: { + resource_ids[]: number[] // ERFORDERLICH! Array von Resource-IDs + status_ids[]?: number[] // Optional, default: [1, 2] (pending, approved) + // 1=PENDING, 2=APPROVED, 3=CANCELED, 99=DELETED + person_id?: number // Filter: Creator oder "im Auftrag von" + query?: string // Freitext-Suche + include[]: string[] // ["conflicts", "involvedPersonsDomainObjects"] + } + response: { + data: Array<{ + booking: BookingCalculated + conflicts?: Array + involvedPersonsDomainObjects?: { + createdBy?: DomainObjectPerson + onBehalfOf?: DomainObjectPerson + } + }> + meta: { count: number } + } + +// 2. Einzelne Booking abrufen +GET /bookings/{bookingId} + response: { + data: { + booking: BookingCalculated + calculatedDates: { startDate, endDate } + additionalInfos: string[] + } + } + +// 3. Status einer Booking ändern (✅ AKZEPTIEREN/ABLEHNEN) +PUT /bookings/{bookingId}/{answer} + params: { + answer: "accept" | "reject" + } + body: {} // Leerer Body + response: Booking aktualisiert + +// ODER Update via PUT (mehr Flexibilität): +PUT /bookings/{bookingId} + body: { + statusId: 2 // APPROVED (2) oder CANCELED (3) + description?: string + ... weitere Felder + } + +// 4. Konflikte für NEUE Booking berechnen +POST /bookings/conflicts + body: BookingConflictRequestBody { + resourceId: number + startDate: DateString + endDate: DateString + // ... (weitere optionale Felder) + } + response: { data: Array, meta: { count } } + +// 5. Konflikte für BESTEHENDE Booking berechnen (bei Update) +POST /bookings/{bookingId}/conflicts + body: (wie oben) + +// 6. Alle Resources abrufen +GET /resources + response: { data: Array, meta: { count } } + +// 7. Resource Master Data +GET /resources/masterdata + response: { resources: Array, resourceTypes: Array } +``` + +### ⚠️ Wichtige Erkenntnisse + +1. **`resource_ids[]` ist ERFORDERLICH!** + - Bookings können NICHT ohne Resource-IDs abgerufen werden + - Müssen zuerst alle Resources laden, dann für jede Bookings abfragen + - Oder mehrere Queries kombinieren + +2. **Status-IDs sind standardisiert:** + - 1 = PENDING (offene Anfrage) + - 2 = APPROVED/CONFIRMED (genehmigt) + - 3 = CANCELED (abgelehnt) + - 99 = DELETED (gelöscht) + +3. **Update-Endpoints:** + - `PUT /bookings/{bookingId}/{answer}` mit "accept"/"reject" + - `PUT /bookings/{bookingId}` mit statusId im Body (flexibler) + +4. **Include-Parameter:** + - `conflicts` - Zeigt conflicting bookings + - `involvedPersonsDomainObjects` - Zeigt createdBy + onBehalfOf + +5. **Person-Daten sind INCLUDED:** + - Bei `include[]=involvedPersonsDomainObjects` kommt das direkt mit + - Keine separaten `/person` Calls nötig + +## 📊 Datenfluss für Feature + +### 1. **Initiales Laden: Dashboard Card** + +``` +GET /bookings?status_id=pending&include=conflicts,persons +└─ Liefert: Array + - booking.base.resourceId, title, dates + - booking.base.createdBy (ersteller) + - booking.base.onBehalfOf (im Auftrag von) + - conflicts[] (Array, kann leer sein) +``` + +### 2. **Filterung & Sortierung** (Client-side nach Fetch) + +- Nach Status: `filterByStatus(statusId)` +- Nach Konflikt: `filter(b => b.conflicts && b.conflicts.length > 0)` +- Nach Datum/Raum: `filter(b => b.booking.base.resourceId === id)` +- Freitext: `filter(b => title.includes(text))` +- **Sortierung: Spalten-Header Klick → Datensatz nach Feld sortieren** + +### 3. **Bulk-Aktion: Bestätigen** + +```typescript +// Für jede markierte Booking: +PUT / bookings / { bookingId } +body: { + statusId: APPROVED_STATUS_ID +} + +// Dann: GET /bookings (refresh) +``` + +### 4. **Bulk-Aktion: Ablehnen mit Bemerkung** + +```typescript +// Für jede markierte Booking: +PUT /bookings/{bookingId} + body: { + statusId: REJECTED_STATUS_ID, + description: "Admin-Bemerkung" // Optional - müsste übergeben werden + } + +// Dann: Trigger E-Mail an createdBy + onBehalfOf + conflictPersons +``` + +### 5. **E-Mail bei Ablehnung** + +Needed zusätzlich: + +- E-Mail API-Endpoint (existiert wahrscheinlich in ChurchTools) +- Template für Ablehnungsmail +- Person-Daten auflösen (aus Booking: createdBy, onBehalfOf, Konflikt-Creator) + +## ✅ Offene Fragen geklärt + +| Frage | Antwort | +| --------------------- | ----------------------------------------------------------------------- | +| **Status-IDs** | 1=PENDING, 2=APPROVED, 3=CANCELED, 99=DELETED ✅ | +| **include-Parameter** | `conflicts`, `involvedPersonsDomainObjects` ✅ | +| **Person-Daten** | Mit `involvedPersonsDomainObjects` enthalten (createdBy, onBehalfOf) ✅ | +| **Konflikt-Daten** | Mit `include[]=conflicts` in Booking enthalten ✅ | + +## ✅ E-Mail API (Legacy Ajax Endpoint) + +ChurchTools hat einen **Legacy Ajax Endpoint** zum Versenden von E-Mails: + +```typescript +POST /index.php?q=churchdb/ajax +Content-Type: application/x-www-form-urlencoded + +Parameter: +- ids: string // Komma-getrennte Person-IDs (545,892) +- betreff: string // Subject (URL-encoded) +- inhalt: string // HTML-Body (URL-encoded) +- template_id: number // Template-ID (z.B. 11) +- func: "sendEMailToPersonIds" // Funktions-Identifier +- attachments?: string // Optional: Datei-Hashes +- domain_id?: number // Optional +- group_id?: number // Optional +- browsertabId?: string // Session-Info + +Beispiel: +ids=545%2C892&betreff=%5BBG+Korntal%5D+&inhalt=...&template_id=11&func=sendEMailToPersonIds +``` + +**Wichtig:** + +- Dieser Endpoint ist **NICHT** REST API, sondern Legacy AJAX +- Funktioniert nur mit aktiver Session (Cookie + CSRF-Token) +- IDs müssen komma-getrennt sein +- HTML-Content wird direkt versendet +- Mehrere Personen in einer Request (Batch) + +## ⚠️ Noch zu klären + +1. **Person-E-Mail in DomainObjectPerson**: + - Enthalten die `createdBy` und `onBehalfOf` Objekte `id` und `name`? + - Wir verwenden die `id` zum Versenden via `/index.php?q=churchdb/ajax` + - **→ Mit Test-API prüfen** + +2. **Konflikt-Creator auflösen**: + - Konflikt enthält nur `bookingId`, `title`, `startDate`, `endDate` - **KEINE Person-Daten** + - Um E-Mail des Konflikt-Creators zu bekommen: + - `GET /bookings/{conflictBookingId}` mit `include[]=involvedPersonsDomainObjects` + - Dann `id` der createdBy Person extrahieren + - **→ Implementation wird mehrere nested Calls benötigen** + +3. **Template-Verwaltung**: + - Wo sind die Templates definiert? (Template-ID `11` in Beispiel) + - Können wir Templates dynamisch laden? + - Oder müssen wir HTML manuell zusammenstellen? + +4. **Bulk Email-Versand Design**: + - Mehrere Personen (createdBy + onBehalfOf + conflictCreators) in einer Mail versenden + - Ein API-Call mit all den IDs (optimal) + - ODER separate Calls pro Person (einfacher zu implementieren) + +## 🎯 Nächste Schritte + +1. **API-Endpoints testen/validieren**: + - Doku der ChurchTools API checken + - Oder in Live-Instanz mit DevTools testen + - Status-IDs herausfinden + +2. **E-Mail-Integration klären**: + - Welcher Endpunkt? Welche Template-Sprache? + - Lokale Lösung (nodemailer) vs. ChurchTools-API? + +3. **Composable implementieren** (`useRoomBookings.ts`): + - `fetchBookings(filter, sort)` + - `approveBooking(id)` + - `rejectBooking(id, reason)` + - `sendRejectionEmail(booking, reason, conflictPersons)` + +4. **AdminTable Pattern studieren**: + - `/src/components/tags/TagsAdmin.vue` + - `/src/components/automatic-groups/AutomaticGroupsAdmin.vue` + - Checkboxes, Bulk-Buttons, Actions Spalte + +## 📝 API Pattern in diesem Projekt + +**Bestätigte Muster aus existendem Code:** + +```typescript +// ✅ CORRECT (nach AGENTS.md): +const response = await churchtoolsClient.get("/api/endpoint", { param1: "value1" }) +// Client unwraps data - use response directly! + +// ❌ WRONG: +const response = await churchtoolsClient.get("/api/endpoint", { params: { ... } }) + +// Delete-Operationen: +await (churchtoolsClient as any).deleteApi(`/tags/${tagId}`) + +// Pagination: +const response = await churchtoolsClient.get(`/resource?limit=${limit}&page=${page}`) +``` + +**Composable Pattern** (aus `useAutomaticGroups.ts`, `useTags.ts`): + +- Vue 3 Composable mit `ref`, `computed` +- Oder `@tanstack/vue-query` für komplexere Daten +- Async Funktionen für API-Calls +- Error Handling & Logging +- Type-safe mit TypeScript Interfaces + +--- + +**Status**: 📋 Analyse +**Aktuell**: 2026-04-16 +**Nächster Schritt**: API-Endpoints verifizieren & Composable starten diff --git a/docs/IMPLEMENTATION_CHECKLIST.md b/docs/IMPLEMENTATION_CHECKLIST.md new file mode 100644 index 0000000..1cb2d11 --- /dev/null +++ b/docs/IMPLEMENTATION_CHECKLIST.md @@ -0,0 +1,105 @@ +# Implementation Checklist - Raumbuchungsanfragen + +## ✅ Umgesetzt + +- [x] Dashboard Card mit Statistiken +- [x] Admin Panel mit AdminTable +- [x] Zeilen-Auswahl (Checkboxes) +- [x] Bulk Approve / Bulk Reject +- [x] Einzelne Approval/Rejection mit Modal +- [x] Konflikt-Anzeige (Badge ⚠️) +- [x] Freitext-Suche +- [x] Sortierbare Spalten +- [x] Filterung nach Konflikt-Status (mit/ohne) +- [x] Filterung nach Booking-Status (PENDING/APPROVED/CANCELED) +- [x] Konflikte laden & anzeigen +- [x] E-Mail-Versand bei Ablehnung (mit Konflikt-Infos) + +## ❌ Noch zu implementieren + +### 1. Detailansicht (HIGH) + +**Anforderung 3.1**: Detailansicht für jede Anfrage + +- Modal/Panel mit vollständigen Buchungsdetails +- Konflikt-Liste mit Details +- Bemerkungen-Feld anzeigen +- Trigger: Click auf Zeile oder dedizierter "Details" Button + +### 2. Zusätzliche Filter (MEDIUM) + +**Anforderung 1.2**: Filterung nach Datum & Raum + +- Filter nach Raum/Ressource (Dropdown) +- Filter nach Datum (Von/Bis oder "Diese Woche", "Nächste Woche") +- Beide in den `