Skip to content

Person-IDs im Logger sollen NICHT aufgelöst werde #10

@bwl21

Description

@bwl21

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-Load

Performance 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 Daten

4. 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:

  1. Performance: ✅ Instant loading, no API dependencies
  2. Reliability: ✅ No external dependencies for core functionality
  3. Simplicity: ✅ Easy to understand and maintain
  4. Flexibility: ✅ Users can get person info when needed
  5. Scalability: ✅ Works with thousands of logs
  6. 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:

  1. Predictable: Immer gleiche Anzeige
  2. Fast: Keine API-Calls erforderlich
  3. Reliable: Funktioniert auch bei API-Problemen
  4. Scalable: Performance unabhängig von Anzahl Personen
  5. 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:

  1. Keep Current Implementation:

    • Person-IDs bleiben als "Person ID: 123"
    • System-Einträge zeigen "System"
    • Keine automatische Name-Resolution
  2. Optional Enhancements:

    • Click-to-open in ChurchTools
    • Optional Person-Lookup Tool
    • Enhanced ID-based search
    • Better visual styling for Person-IDs
  3. Performance Maintained:

    • Instant loading ohne API-Dependencies
    • Skaliert mit beliebig vielen Logs
    • Minimaler Memory-Footprint
  4. Documentation:

    • Dokumentiere Design-Entscheidung
    • Erkläre Alternative Ansätze
    • Begründe Performance-Vorteile

📁 Files to Modify

Documentation:

  • docs/DESIGN_DECISIONS.md - Dokumentiere Logger-Design
  • docs/PERFORMANCE.md - Performance-Überlegungen

Optional Enhancements:

  • src/components/loggerSummary/PersonLookupTool.vue - Optional lookup
  • src/components/loggerSummary/LoggerSummaryAdmin.vue - Enhanced styling

🏷️ Labels

  • design-decision - Architectural choice
  • performance - Performance consideration
  • logger-system - Affects Logger module
  • anti-pattern - Prevents problematic implementation
  • documentation - 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

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions