-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Issue: Person-IDs im Logger sollen NICHT aufgelöst werden
🎯 Design Decision / Anti-Pattern Prevention
Das Logger System sollte bewusst KEINE Person-IDs zu Namen auflösen. Diese Entscheidung basiert auf wichtigen technischen und konzeptionellen Überlegungen für ein robustes Logging-System.
🚫 Why NOT to Resolve Person IDs
1. Performance & Scalability Issues
API Load Problems:
// PROBLEMATISCH: Massive API-Calls
const logs = await getLogEntries(1000) // 1000 Log-Einträge
const uniquePersonIds = [...new Set(logs.map(log => log.personId))] // 200 verschiedene Personen
// Resultat: 200 zusätzliche API-Calls nur für Namen!
// Bei großen Log-Mengen: Exponentieller API-LoadPerformance Impact:
- Initial Load: 2-5s → 10-30s (bei vielen verschiedenen Personen)
- Memory Usage: +50-100MB für Person-Cache
- API Rate Limits: Schnell erreicht bei großen Organisationen
- Network Traffic: 10x höher durch Person-Requests
2. Logging System Principles
Logs sollten atomisch und unveränderlich sein:
// RICHTIG: Atomische Log-Einträge
interface LogEntry {
timestamp: Date
personId: number // Unveränderliche Referenz
message: string
source: string
level: LogLevel
}
// FALSCH: Abhängigkeit von externen Daten
interface LogEntryWithResolution {
timestamp: Date
personId: number
personName: string // Kann sich ändern!
personEmail: string // Kann sich ändern!
message: string
// ... externe Abhängigkeiten
}Separation of Concerns:
- Logger: Sammelt und speichert Events
- Person Management: Verwaltet Person-Daten
- UI Layer: Kombiniert Daten für Anzeige
3. Data Consistency Issues
Stale Data Problem:
// Person ändert Namen in ChurchTools
// Logger Cache ist veraltet
const cachedPerson = personCache.get(123) // "Max Mustermann"
// Aber in ChurchTools ist es jetzt "Max Schmidt"
// Logs zeigen inkonsistente Daten!Permission Changes:
// User verliert Berechtigung für Person-Details
// Logs werden plötzlich unvollständig angezeigt
const person = await getPersonDetails(123) // 403 Forbidden
// UI bricht zusammen oder zeigt inkonsistente Daten4. Complexity & Maintenance Burden
Zusätzliche Komplexität:
// Ohne Resolution: Einfach
const displayLog = (log: LogEntry) => {
return `${log.timestamp}: ${log.message} (Person: ${log.personId})`
}
// Mit Resolution: Komplex
const displayLog = async (log: LogEntry) => {
const person = await resolvePerson(log.personId)
const simulatedPerson = log.simulatePersonId
? await resolvePerson(log.simulatePersonId)
: null
// Error handling, caching, loading states, fallbacks...
return buildComplexDisplay(log, person, simulatedPerson)
}Error Handling Explosion:
- API-Fehler für jede Person-Resolution
- Permission-Errors
- Network-Timeouts
- Cache-Invalidierung
- Memory-Management
5. Alternative Solutions sind besser
Option 1: Click-to-Resolve (On-Demand)
<template>
<div class="log-entry">
<span>{{ log.message }}</span>
<span class="person-id">
Person: {{ log.personId }}
<button
@click="showPersonDetails(log.personId)"
class="resolve-button"
title="Person-Details anzeigen"
>
👤
</button>
</span>
</div>
</template>Option 2: External Person Lookup
<template>
<div class="logger-controls">
<input
v-model="personLookupId"
placeholder="Person-ID eingeben"
type="number"
>
<button @click="lookupPerson">Person nachschlagen</button>
</div>
<div v-if="lookedUpPerson" class="person-info">
ID {{ personLookupId }}: {{ lookedUpPerson.name }}
</div>
</template>Option 3: ChurchTools Integration
// Direkter Link zu ChurchTools Person-Seite
const getPersonLink = (personId: number) => {
return `${churchtoolsBaseUrl}/persons/${personId}`
}<template>
<a
:href="getPersonLink(log.personId)"
target="_blank"
class="person-link"
>
Person {{ log.personId }} 🔗
</a>
</template>🎯 Recommended Approach
Keep Logger Simple & Fast:
<!-- LoggerSummaryAdmin.vue -->
<template>
<div class="log-entry">
<!-- Einfache, schnelle Anzeige -->
<div class="log-message">{{ log.message }}</div>
<div class="log-meta">
<span class="timestamp">{{ formatDate(log.timestamp) }}</span>
<span class="source">{{ log.source }}</span>
<!-- Person-ID mit optionalen Actions -->
<span class="person-info">
Person: {{ log.personId }}
<!-- Optional: Quick Actions -->
<div class="person-actions">
<button
@click="openPersonInChurchTools(log.personId)"
title="In ChurchTools öffnen"
class="action-button"
>
🔗
</button>
<button
@click="showPersonQuickInfo(log.personId)"
title="Quick Info anzeigen"
class="action-button"
>
👤
</button>
</div>
</span>
<!-- Simulation Info -->
<span v-if="log.simulatePersonId" class="simulation-info">
Simuliert von: {{ log.simulatePersonId }}
<button
@click="openPersonInChurchTools(log.simulatePersonId)"
class="action-button"
>
🔗
</button>
</span>
</div>
</div>
</template>
<script setup lang="ts">
// Einfache, schnelle Implementierung
const openPersonInChurchTools = (personId: number) => {
const url = `${churchtoolsBaseUrl}/persons/${personId}`
window.open(url, '_blank')
}
// Optional: On-demand Person Info
const showPersonQuickInfo = async (personId: number) => {
try {
const person = await getPersonDetails(personId)
// Zeige in Modal/Tooltip
showPersonModal(person)
} catch (error) {
showError(`Person ${personId} konnte nicht geladen werden`)
}
}
</script>Benefits of This Approach:
- Performance: ✅ Instant loading, no API dependencies
- Reliability: ✅ No external dependencies for core functionality
- Simplicity: ✅ Easy to understand and maintain
- Flexibility: ✅ Users can get person info when needed
- Scalability: ✅ Works with thousands of logs
- Consistency: ✅ Always shows the same data
🔍 Technical Analysis
Current Implementation is Correct:
// LoggerSummaryAdmin.vue - RICHTIG!
const getActorDisplay = (log: LogEntry) => {
if (log.personId === -1) {
return 'System'
} else if (log.personId) {
return `Person ID: ${log.personId}` // ✅ Einfach und korrekt
} else {
return 'Unbekannt'
}
}Why This Works Well:
- Predictable: Immer gleiche Anzeige
- Fast: Keine API-Calls erforderlich
- Reliable: Funktioniert auch bei API-Problemen
- Scalable: Performance unabhängig von Anzahl Personen
- Maintainable: Wenig Code, wenig Fehlerquellen
🎨 UI/UX Improvements (Without Resolution)
Enhanced Person ID Display:
.person-info {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.25rem 0.5rem;
background: var(--color-background-soft);
border-radius: 4px;
font-family: monospace;
}
.person-actions {
display: inline-flex;
gap: 0.25rem;
}
.action-button {
padding: 0.125rem 0.25rem;
border: none;
background: transparent;
cursor: pointer;
border-radius: 2px;
transition: background-color 0.2s;
}
.action-button:hover {
background: var(--color-background-mute);
}Enhanced Search (ID-based):
// Erweiterte Suche nach Person-IDs
const searchLogs = (query: string, logs: LogEntry[]) => {
const numericQuery = parseInt(query)
return logs.filter(log => {
// Text-basierte Suche
const textMatch = [
log.message,
log.source,
log.details
].some(field =>
field?.toLowerCase().includes(query.toLowerCase())
)
// Person-ID Suche
const personMatch = !isNaN(numericQuery) && (
log.personId === numericQuery ||
log.simulatePersonId === numericQuery
)
return textMatch || personMatch
})
}Quick Person Lookup Tool:
<template>
<div class="person-lookup-tool">
<h3>Person nachschlagen</h3>
<div class="lookup-form">
<input
v-model="lookupId"
type="number"
placeholder="Person-ID eingeben"
@keyup.enter="lookupPerson"
>
<button @click="lookupPerson" :disabled="!lookupId">
Nachschlagen
</button>
</div>
<div v-if="lookupResult" class="lookup-result">
<h4>Person {{ lookupId }}:</h4>
<p>{{ lookupResult.firstName }} {{ lookupResult.lastName }}</p>
<p>{{ lookupResult.email }}</p>
<a :href="getPersonLink(lookupId)" target="_blank">
In ChurchTools öffnen 🔗
</a>
</div>
<div v-if="lookupError" class="lookup-error">
{{ lookupError }}
</div>
</div>
</template>🧪 Testing Benefits
Simpler Tests:
describe('Logger Display', () => {
it('should display person ID correctly', () => {
const log = { personId: 123, message: 'Test' }
const display = getActorDisplay(log)
expect(display).toBe('Person ID: 123') // ✅ Einfach zu testen
})
it('should handle system entries', () => {
const log = { personId: -1, message: 'System action' }
const display = getActorDisplay(log)
expect(display).toBe('System') // ✅ Deterministisch
})
})
// KEINE komplexen Tests für:
// - API-Mocking
// - Cache-Verhalten
// - Async Loading States
// - Error Handling
// - Memory Management🎯 Acceptance Criteria
✅ Definition of Done:
-
Keep Current Implementation:
- Person-IDs bleiben als "Person ID: 123"
- System-Einträge zeigen "System"
- Keine automatische Name-Resolution
-
Optional Enhancements:
- Click-to-open in ChurchTools
- Optional Person-Lookup Tool
- Enhanced ID-based search
- Better visual styling for Person-IDs
-
Performance Maintained:
- Instant loading ohne API-Dependencies
- Skaliert mit beliebig vielen Logs
- Minimaler Memory-Footprint
-
Documentation:
- Dokumentiere Design-Entscheidung
- Erkläre Alternative Ansätze
- Begründe Performance-Vorteile
📁 Files to Modify
Documentation:
docs/DESIGN_DECISIONS.md- Dokumentiere Logger-Designdocs/PERFORMANCE.md- Performance-Überlegungen
Optional Enhancements:
src/components/loggerSummary/PersonLookupTool.vue- Optional lookupsrc/components/loggerSummary/LoggerSummaryAdmin.vue- Enhanced styling
🏷️ Labels
design-decision- Architectural choiceperformance- Performance considerationlogger-system- Affects Logger moduleanti-pattern- Prevents problematic implementationdocumentation- Needs documentation
🔗 Related
- Logger System Architecture
- Performance Optimization
- ChurchTools API Usage
- Design Patterns
Reporter: Development Team
Priority: High (Design Decision)
Complexity: Low (Keep current implementation)
Estimated Effort: 1-2 hours (Documentation + optional enhancements)
📝 Design Rationale
Als Entwickler
möchte ich dass der Logger performant und zuverlässig bleibt
damit das System auch bei großen Datenmengen schnell und stabil funktioniert.
Design Principles:
- Separation of Concerns: Logger sammelt Daten, UI kombiniert sie
- Performance First: Keine unnötigen API-Calls im kritischen Pfad
- Reliability: Funktioniert unabhängig von externen Services
- Simplicity: Weniger Code = weniger Bugs
Alternative Solutions:
- On-demand Person-Resolution bei Bedarf
- Direkte Links zu ChurchTools
- Separate Person-Lookup Tools
- Enhanced Search mit ID-basierter Filterung
Metadata
Metadata
Assignees
Labels
No labels