feat(onboarding, screens): Logging für Screen-Loads ergänzt & Biest-Referenzen entfernt
Some checks failed
Desktop CI — Headless Tests & Build / Compose Desktop — Tests (headless) & Build (push) Failing after 1m2s
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Successful in 6m7s
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Successful in 6m18s
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Failing after 59s
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Successful in 2m0s
Some checks failed
Desktop CI — Headless Tests & Build / Compose Desktop — Tests (headless) & Build (push) Failing after 1m2s
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Successful in 6m7s
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Successful in 6m18s
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Failing after 59s
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Successful in 2m0s
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
parent
8857d52f44
commit
8f6044abe3
|
|
@ -1,10 +1,11 @@
|
||||||
# 🤖 Projekt Agenten & Protokoll (Meldestelle-Biest)
|
# 🤖 Projekt Agenten & Protokoll (Meldestelle)
|
||||||
|
|
||||||
Dieses Dokument definiert die Zusammenarbeit zwischen dem User (Owner) und den spezialisierten KI-Agenten.
|
Dieses Dokument definiert die Zusammenarbeit zwischen dem User (Owner) und den spezialisierten KI-Agenten.
|
||||||
Es dient als zentraler **System-Prompt-Erweiterung** für neue Chat-Sessions.
|
Es dient als zentraler **System-Prompt-Erweiterung** für neue Chat-Sessions.
|
||||||
|
|
||||||
## 🚀 Strategische Ausrichtung
|
## 🚀 Strategische Ausrichtung
|
||||||
Das Projekt **"Meldestelle-Biest"** entwickelt eine ÖTO/FEI-konforme, offline-fähige Turnier-Software.
|
|
||||||
|
Das Projekt **"Meldestelle"** entwickelt eine ÖTO/FEI-konforme, offline-fähige Turnier-Software.
|
||||||
1. **Desktop-First:** Primäres Ziel ist die Compose Desktop App (KMP). UX & Performance sind auf Profis optimiert.
|
1. **Desktop-First:** Primäres Ziel ist die Compose Desktop App (KMP). UX & Performance sind auf Profis optimiert.
|
||||||
2. **Offline-First:** Das System muss autark (ohne Internet) funktionieren. Sync-Logik ist Kernbestandteil.
|
2. **Offline-First:** Das System muss autark (ohne Internet) funktionieren. Sync-Logik ist Kernbestandteil.
|
||||||
3. **Domain-Driven:** 6 Bounded Contexts (SCS) bilden den fachlichen Rahmen.
|
3. **Domain-Driven:** 6 Bounded Contexts (SCS) bilden den fachlichen Rahmen.
|
||||||
|
|
@ -29,7 +30,7 @@ Jede Agenten-Antwort **muss** mit dem entsprechenden Badge beginnen, um den Kont
|
||||||
* **🧹 [Curator]**: Wissens-Management & Dokumentations-Check (ADR, Reference, Journal). Beendet jede Session.
|
* **🧹 [Curator]**: Wissens-Management & Dokumentations-Check (ADR, Reference, Journal). Beendet jede Session.
|
||||||
* [Playbook](docs/04_Agents/Playbooks/Curator.md)
|
* [Playbook](docs/04_Agents/Playbooks/Curator.md)
|
||||||
|
|
||||||
## 2. Der "Biest"-Workflow
|
## 2. Der "Meldestelle"-Workflow
|
||||||
1. **Kontext-Check:** Lies immer zuerst die `MASTER_ROADMAP` in `docs/01_Architecture/`.
|
1. **Kontext-Check:** Lies immer zuerst die `MASTER_ROADMAP` in `docs/01_Architecture/`.
|
||||||
2. **SCS-Rahmen:** Identifiziere, in welchem der 6 Bounded Contexts du arbeitest.
|
2. **SCS-Rahmen:** Identifiziere, in welchem der 6 Bounded Contexts du arbeitest.
|
||||||
3. **Fokus:** Bearbeite immer nur EINE fachliche Aufgabe pro Session.
|
3. **Fokus:** Bearbeite immer nur EINE fachliche Aufgabe pro Session.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Incident Report: Quality Regression during V2 Refactoring & Naming Correction
|
||||||
|
|
||||||
|
**Datum:** 17. April 2026
|
||||||
|
**Status:** KRITISCH / RECOVERY
|
||||||
|
**Beteiligte:** Alle Agenten (Lead Architect, Frontend Expert, Curator)
|
||||||
|
|
||||||
|
## 1. Vorfall-Beschreibung
|
||||||
|
|
||||||
|
Während der geplanten Konsolidierung des Codes (Entfernung des `v2`-Präfixes und Ordners) kam es zu einem erheblichen
|
||||||
|
Verlust an fachlicher Tiefe im Onboarding-Wizard.
|
||||||
|
Obwohl die strukturelle Bereinigung erfolgreich war, wurden essenzielle Validierungs-Logiken, UI-Elemente für das
|
||||||
|
Client-Management und die mDNS-Discovery-Integration nicht vollständig in die neue Struktur übernommen.
|
||||||
|
|
||||||
|
Zudem wurde fälschlicherweise das Projekt-Präfix "Biest" (welches sich nur auf die Server-Hardware-Konfiguration bezog)
|
||||||
|
als Projektname verwendet, was zu berechtigtem Unmut beim User führte.
|
||||||
|
|
||||||
|
## 2. Fehleranalyse
|
||||||
|
|
||||||
|
* **Struktur vor Inhalt:** Der Fokus lag zu stark auf der Paket-Struktur und der Namens-Konsolidierung. Die fachliche
|
||||||
|
Parität wurde nicht penibel genug geprüft.
|
||||||
|
* **Husch-Pfusch:** Die Wiederherstellungsversuche nach der ersten Fehlermeldung waren unvollständig und erreichten
|
||||||
|
nicht den zuvor erarbeiteten Qualitätsstandard (High-Density UI).
|
||||||
|
* **Mangelnde Kommunikation:** Die Fehlinterpretation des Namens "Biest" wurde nicht rechtzeitig korrigiert, obwohl der
|
||||||
|
User mehrfach darauf hinwies.
|
||||||
|
|
||||||
|
## 3. Der "Meldestelle-Qualitäts-Pakt" (NEU)
|
||||||
|
|
||||||
|
Um die Professionalität des Projekts "Meldestelle" zu wahren, werden folgende Regeln verbindlich eingeführt:
|
||||||
|
|
||||||
|
1. **NAMENS-DIREKTIV:** Das Projekt heißt ausschließlich **"Meldestelle"**. Der Begriff "Biest" ist aus allen
|
||||||
|
Software-Komponenten und öffentlichen Dokumenten zu entfernen (außer in rein technischem Bezug auf den
|
||||||
|
MiniForum-Server MS-R1).
|
||||||
|
2. **FEATURE-PARITY GATE:** Vor jedem Löschen oder Verschieben von Code muss eine Liste der fachlichen Features (
|
||||||
|
Validierungen, UI-Details, Edge-Cases) erstellt werden. Diese muss nach dem Refactoring 1:1 nachweisbar sein.
|
||||||
|
3. **UI-HYGIENE:** Keine "Downgrades" im UI. Der High-Density-Standard (Material 3, ListItem, Badges, korrekte Spacings)
|
||||||
|
ist nicht verhandelbar.
|
||||||
|
4. **RECOVERY-PLAN:** Die Abend-Session wird ausschließlich dazu genutzt, den Onboarding-Wizard und die mDNS-Integration
|
||||||
|
auf den Stand vom 16.04.2026 zurückzuführen – jedoch in der neuen, sauberen Paketstruktur.
|
||||||
|
|
||||||
|
## 4. Handover für die Abend-Session
|
||||||
|
|
||||||
|
* [ ] **Wiederherstellung:** Onboarding-Step 2 muss Client-Management (Liste, Rollen, Löschen) enthalten.
|
||||||
|
* [ ] **Discovery:** mDNS-Suche im Client-Modus muss Live-Resultate liefern.
|
||||||
|
* [ ] **Validierung:** Alle Felder im Onboarding benötigen den `OnboardingValidator`.
|
||||||
|
* [ ] **Review:** Lead Architect prüft jede Datei auf "Biest"-Altlasten und korrigiert diese.
|
||||||
|
|
||||||
|
---
|
||||||
|
**🧹 [Curator]**: Vorfall ist protokolliert. Der Fokus für heute Abend liegt zu 100% auf der Wiederherstellung der
|
||||||
|
Integrität und Professionalität.
|
||||||
|
|
@ -78,6 +78,7 @@ fun DesktopMainLayout(
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onLogout: () -> Unit,
|
onLogout: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
println("[Navigation] Rendering Screen: ${currentScreen::class.simpleName} (Details: $currentScreen)")
|
||||||
// Onboarding-Daten (On-the-fly geladen oder Default)
|
// Onboarding-Daten (On-the-fly geladen oder Default)
|
||||||
var onboardingSettings by remember { mutableStateOf(SettingsManager.loadSettings() ?: OnboardingSettings()) }
|
var onboardingSettings by remember { mutableStateOf(SettingsManager.loadSettings() ?: OnboardingSettings()) }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ fun VeranstalterDetail(
|
||||||
onZurVeranstaltung: (Long) -> Unit,
|
onZurVeranstaltung: (Long) -> Unit,
|
||||||
onNeuVeranstaltung: () -> Unit,
|
onNeuVeranstaltung: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
LaunchedEffect(veranstalterId) { println("[Screen] VeranstalterDetail geladen (VstID: $veranstalterId)") }
|
||||||
DesktopTheme {
|
DesktopTheme {
|
||||||
val verein = remember(veranstalterId) { Store.vereine.firstOrNull { it.id == veranstalterId } }
|
val verein = remember(veranstalterId) { Store.vereine.firstOrNull { it.id == veranstalterId } }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,10 @@ import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowForward
|
import androidx.compose.material.icons.automirrored.filled.ArrowForward
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.icons.filled.Settings
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -24,6 +27,7 @@ fun OnboardingScreen(
|
||||||
onSettingsChange: (OnboardingSettings) -> Unit,
|
onSettingsChange: (OnboardingSettings) -> Unit,
|
||||||
onContinue: (OnboardingSettings) -> Unit,
|
onContinue: (OnboardingSettings) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
LaunchedEffect(Unit) { println("[Screen] OnboardingScreen geladen") }
|
||||||
var currentStep by remember { mutableStateOf(0) }
|
var currentStep by remember { mutableStateOf(0) }
|
||||||
val discoveryService: NetworkDiscoveryService = koinInject()
|
val discoveryService: NetworkDiscoveryService = koinInject()
|
||||||
val discoveredServices by remember { mutableStateOf(discoveryService.getDiscoveredServices()) }
|
val discoveredServices by remember { mutableStateOf(discoveryService.getDiscoveredServices()) }
|
||||||
|
|
@ -40,7 +44,7 @@ fun OnboardingScreen(
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
"Willkommen beim Meldestelle-Biest",
|
"Willkommen bei der Meldestelle",
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
fontWeight = FontWeight.SemiBold
|
fontWeight = FontWeight.SemiBold
|
||||||
)
|
)
|
||||||
|
|
@ -116,7 +120,174 @@ fun OnboardingScreen(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// PHASE 2: ROLLENSPEZIFISCH
|
// PHASE 2: ROLLENSPEZIFISCH
|
||||||
Text("Konfiguration für ${settings.networkRole}")
|
Card(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
|
Text("⚙️ Geräte-Konfiguration (${settings.networkRole})", style = MaterialTheme.typography.titleMedium)
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = settings.geraetName,
|
||||||
|
onValueChange = { onSettingsChange(settings.copy(geraetName = it)) },
|
||||||
|
label = { Text("Gerätename") },
|
||||||
|
placeholder = { Text("z.B. Meldestelle-PC-1") },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
isError = settings.geraetName.isNotEmpty() && !OnboardingValidator.isNameValid(settings.geraetName),
|
||||||
|
supportingText = {
|
||||||
|
if (settings.geraetName.isNotEmpty() && !OnboardingValidator.isNameValid(settings.geraetName)) {
|
||||||
|
Text("Mindestens ${OnboardingValidator.MIN_NAME_LENGTH} Zeichen erforderlich.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = settings.sharedKey,
|
||||||
|
onValueChange = { onSettingsChange(settings.copy(sharedKey = it)) },
|
||||||
|
label = { Text("Sicherheitsschlüssel (Sync-Key)") },
|
||||||
|
placeholder = { Text("Mindestens 8 Zeichen") },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
isError = settings.sharedKey.isNotEmpty() && !OnboardingValidator.isKeyValid(settings.sharedKey),
|
||||||
|
supportingText = {
|
||||||
|
if (settings.sharedKey.isNotEmpty() && !OnboardingValidator.isKeyValid(settings.sharedKey)) {
|
||||||
|
Text("Mindestens ${OnboardingValidator.MIN_KEY_LENGTH} Zeichen erforderlich.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (settings.networkRole == NetworkRole.MASTER) {
|
||||||
|
HorizontalDivider(Modifier, DividerDefaults.Thickness, DividerDefaults.color)
|
||||||
|
Text("👥 Erwartete Clients (Richter, Zeitnehmer, etc.)", style = MaterialTheme.typography.titleSmall)
|
||||||
|
Text(
|
||||||
|
"Definiere, welche Geräte sich mit diesem Master synchronisieren dürfen.",
|
||||||
|
style = MaterialTheme.typography.bodySmall
|
||||||
|
)
|
||||||
|
|
||||||
|
settings.expectedClients.forEachIndexed { index, client ->
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text(client.name)
|
||||||
|
Badge { Text(client.role.name) }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trailingContent = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
val newList = settings.expectedClients.toMutableList().apply { removeAt(index) }
|
||||||
|
onSettingsChange(settings.copy(expectedClients = newList))
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Delete,
|
||||||
|
contentDescription = "Löschen",
|
||||||
|
tint = MaterialTheme.colorScheme.error
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors = ListItemDefaults.colors(containerColor = MaterialTheme.colorScheme.surfaceVariant)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var newClientName by remember { mutableStateOf("") }
|
||||||
|
var newClientRole by remember { mutableStateOf(NetworkRole.RICHTER) }
|
||||||
|
var showAddClient by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
if (showAddClient) {
|
||||||
|
Row(
|
||||||
|
Modifier.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = newClientName,
|
||||||
|
onValueChange = { newClientName = it },
|
||||||
|
label = { Text("Gerätename des Clients") },
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Simple Role Selector (nur ein kleiner Button für den Prototyp hier)
|
||||||
|
IconButton(onClick = {
|
||||||
|
val roles = NetworkRole.entries.filter { it != NetworkRole.MASTER }
|
||||||
|
val nextIndex = (roles.indexOf(newClientRole) + 1) % roles.size
|
||||||
|
newClientRole = roles[nextIndex]
|
||||||
|
}) {
|
||||||
|
Icon(Icons.Default.Settings, null)
|
||||||
|
}
|
||||||
|
Text(newClientRole.name, style = MaterialTheme.typography.labelSmall)
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (newClientName.isNotBlank()) {
|
||||||
|
val newList = settings.expectedClients + ExpectedClient(newClientName, newClientRole)
|
||||||
|
onSettingsChange(settings.copy(expectedClients = newList))
|
||||||
|
newClientName = ""
|
||||||
|
showAddClient = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enabled = newClientName.isNotBlank()
|
||||||
|
) {
|
||||||
|
Icon(Icons.Default.Add, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TextButton(onClick = { showAddClient = true }) {
|
||||||
|
Icon(Icons.Default.Add, null)
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Text("Client hinzufügen")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HorizontalDivider(Modifier, DividerDefaults.Thickness, DividerDefaults.color)
|
||||||
|
OutlinedTextField(
|
||||||
|
value = settings.backupPath,
|
||||||
|
onValueChange = { onSettingsChange(settings.copy(backupPath = it)) },
|
||||||
|
label = { Text("Backup-Verzeichnis (Pfad)") },
|
||||||
|
placeholder = { Text("/pfad/zu/den/backups") },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
isError = settings.backupPath.isNotEmpty() && !OnboardingValidator.isBackupPathValid(settings.backupPath)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text("Sync-Intervall: ${settings.syncInterval} Min.", style = MaterialTheme.typography.labelMedium)
|
||||||
|
Slider(
|
||||||
|
value = settings.syncInterval.toFloat(),
|
||||||
|
onValueChange = { onSettingsChange(settings.copy(syncInterval = it.toInt())) },
|
||||||
|
valueRange = 1f..60f,
|
||||||
|
steps = 59
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
HorizontalDivider(Modifier, DividerDefaults.Thickness, DividerDefaults.color)
|
||||||
|
Text("🔍 Verfügbare Master im Netzwerk", style = MaterialTheme.typography.titleSmall)
|
||||||
|
|
||||||
|
if (discoveredServices.isEmpty()) {
|
||||||
|
Box(Modifier.fillMaxWidth().padding(16.dp), contentAlignment = Alignment.Center) {
|
||||||
|
CircularProgressIndicator(modifier = Modifier.size(24.dp))
|
||||||
|
Text("Suche nach Master...", modifier = Modifier.padding(start = 40.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
discoveredServices.forEach { service ->
|
||||||
|
ListItem(
|
||||||
|
headlineContent = { Text(service.name) },
|
||||||
|
supportingContent = { Text("${service.host}:${service.port}") },
|
||||||
|
trailingContent = {
|
||||||
|
Button(onClick = {
|
||||||
|
// Master-Daten in die Settings übernehmen (vereinfacht)
|
||||||
|
onSettingsChange(settings.copy(sharedKey = service.metadata["key"] ?: settings.sharedKey))
|
||||||
|
}) {
|
||||||
|
Text("Verbinden")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors = ListItemDefaults.colors(containerColor = MaterialTheme.colorScheme.primaryContainer)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
"Hinweis: Als Client wird dieses Gerät automatisch versuchen, den Master im Netzwerk zu finden.",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ fun VeranstaltungVerwaltung(
|
||||||
onNavigateToVeranstalter: () -> Unit,
|
onNavigateToVeranstalter: () -> Unit,
|
||||||
onNavigateToZnsImport: () -> Unit
|
onNavigateToZnsImport: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
LaunchedEffect(Unit) { println("[Screen] VeranstaltungVerwaltung geladen") }
|
||||||
DesktopTheme {
|
DesktopTheme {
|
||||||
val allVeranstaltungen = remember { Store.allEvents() }
|
val allVeranstaltungen = remember { Store.allEvents() }
|
||||||
val vereine = Store.vereine
|
val vereine = Store.vereine
|
||||||
|
|
@ -825,6 +826,7 @@ fun VeranstaltungKonfig(
|
||||||
onSaved: (Long, Long) -> Unit, // eventId, veranstalterId
|
onSaved: (Long, Long) -> Unit, // eventId, veranstalterId
|
||||||
onVeranstalterCreated: (Long) -> Unit = {},
|
onVeranstalterCreated: (Long) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
LaunchedEffect(Unit) { println("[Screen] VeranstaltungKonfig geladen (VeranstalterID: $veranstalterId)") }
|
||||||
val znsImporter: ZnsImportProvider = koinInject()
|
val znsImporter: ZnsImportProvider = koinInject()
|
||||||
val znsState = znsImporter.state
|
val znsState = znsImporter.state
|
||||||
|
|
||||||
|
|
@ -983,6 +985,7 @@ fun VeranstaltungProfilScreen(
|
||||||
onTurnierOpen: (Long) -> Unit,
|
onTurnierOpen: (Long) -> Unit,
|
||||||
onNavigateToVeranstalterProfil: (Long) -> Unit,
|
onNavigateToVeranstalterProfil: (Long) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
LaunchedEffect(Unit) { println("[Screen] VeranstaltungProfilScreen geladen (VerID: $veranstaltungId, VstID: $veranstalterId)") }
|
||||||
DesktopTheme {
|
DesktopTheme {
|
||||||
val veranstaltung = Store.eventsFor(veranstalterId).firstOrNull { it.id == veranstaltungId }
|
val veranstaltung = Store.eventsFor(veranstalterId).firstOrNull { it.id == veranstaltungId }
|
||||||
val turniere = remember(veranstaltungId) { TurnierStore.list(veranstaltungId) }
|
val turniere = remember(veranstaltungId) { TurnierStore.list(veranstaltungId) }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user