Commit graph

188 commits

Author SHA1 Message Date
Jens Reinemann
c39bc5e485 feat: foreground service for background message notifications 2026-05-18 13:45:06 +02:00
Jens Reinemann
38394c6350 chore: release v1.7 (12) 2026-05-18 13:23:09 +02:00
Jens Reinemann
cc8bbc3111 docs(knowledge-conduit): update Concept + SKILL 2026-05-18 13:22:08 +02:00
Jens Reinemann
e43c0ebbb5 feat(update): UpToDate-Status mit temporärem Feedback anzeigen
- Neuer UpdateStatus.UpToDate State
- Button zeigt 'Keine Updates gefunden' für 5 Sekunden
- Mindestens 1s Checking-Anzeige (vermeidet Flicker bei schneller Antwort)
- UpdateBanner blendet UpToDate-Status aus
2026-05-18 13:04:12 +02:00
Jens Reinemann
f93b4d0b72 fix(docs): Mermaid-Diagramme in Concept.md verbessern
- Emojis aus Mermaid-Nodes entfernt (verursachten Fragezeichen)
- Pipeline-Diagramm vereinfacht (single flowchart statt verschachtelter Subgraphs)
- Dateistruktur: Subgraph-Labels gekuerzt damit Text nicht verdeckt wird
2026-05-18 13:03:13 +02:00
Jens Reinemann
bfa1f2b649 rename: Genome Engine → Knowledge Conduit
Gesamtes System umbenannt:
- .github/genome/ → .github/knowledge-conduit/
- .github/skills/genome/ → .github/skills/knowledge-conduit/
- genome-extract.py → kc-extract.py
- genome.prompt.md → knowledge-conduit.prompt.md
- genome-distill.prompt.md → kc-distill.prompt.md
- genome-propagate.prompt.md → kc-transfer.prompt.md
- Concept Genome Engine.md → Concept.md
- Alle internen Referenzen aktualisiert
- .gitignore aktualisiert
2026-05-18 13:01:02 +02:00
Jens Reinemann
1492fa879b refactor(ui): Update-Status-Anzeige in Settings überarbeiten
- Einzelne Buttons pro Status statt gemeinsamer 'Auf Updates prüfen'-Button
- Available-Status als prominenter Button mit Icon
- Checking/Downloading als disabled OutlinedButton
- Error-Status mit 'Erneut prüfen'-Button
- Hidden-Status zeigt den Check-Button
2026-05-18 12:48:04 +02:00
Jens Reinemann
ddf9272dda refactor(genome): Terminologie vereinheitlichen – Trait→Capability, Mutation→Improvement, Growth Vector→Insight, Propagation→Transfer
Alle Genome-Engine-Dateien auf lernbasierte Begriffe umgestellt:
- Concept Doc: komplett überarbeitet mit Mermaid-Diagrammen
- genome.prompt.md: neue Dateinamen + Begriffe
- genome-distill.prompt.md: Improvements/Insights statt Mutations/Vectors
- genome-propagate.prompt.md: Transfer statt Propagation, Capability statt Trait
- genome-extract.py: Output-Dateiname + Ausgabetext aktualisiert
- SKILL.md: Beschreibung + Dateitabelle aktualisiert
2026-05-18 12:46:39 +02:00
Jens Reinemann
5eae3a4813 chore: release v1.7 (11) 2026-05-18 12:34:58 +02:00
Jens Reinemann
587c7c5f14 chore(genome): update SKILL.md 2026-05-18 12:33:32 +02:00
Jens Reinemann
292c538d45 fix(ui): close BottomSheet when 'Alle zurücksetzen' is tapped 2026-05-18 12:29:49 +02:00
Jens Reinemann
ad0945ec3c feat(ui): replace filter chips with BottomSheet + sort options
- Filter button with badge next to search bar
- BottomSheet with filter dropdowns (Kategorie, Lagerort, Ablauf)
- Sort options: Name, Ablaufdatum, Menge (asc/desc)
- 'Alle zurücksetzen' button to clear filters + sort
- docs(genome): Konzept nach .github/genome/ verschoben
2026-05-18 12:27:28 +02:00
Jens Reinemann
6a3009569b fix(ui): filter chip label too long – show only selected value 2026-05-18 12:16:35 +02:00
Jens Reinemann
d59663a2fa docs(genome): Konzept aktualisiert + Mermaid-Diagramme, Inkonsistenzen behoben
- genome-engine.md: Script-Name, Pfade, Scope korrigiert, Mermaid-Visualisierungen
- genome-extract.py: dynamisches Pattern statt hardcoded kotlin-conventions
- SKILL.md: vollständige Dateiliste mit korrekten Pfaden
- genome.prompt.md: Referenz auf Konzept-Dokument korrigiert
2026-05-18 12:16:23 +02:00
Jens Reinemann
7ea7729f96 fix: version display format -> three-number (e.g. 1.7.10) without v prefix 2026-05-18 12:16:01 +02:00
Jens Reinemann
461fca7ead chore: release v1.7 (10) 2026-05-18 12:09:11 +02:00
Jens Reinemann
39956cc7d9 feat(publish): Python-basierter publish-apk Workflow 2026-05-18 12:08:12 +02:00
Jens Reinemann
09e01dff00 style: Beton & Stahl Theme - höhere Kontraste, stahlblaue Surfaces 2026-05-18 12:08:06 +02:00
Jens Reinemann
8459705bb1 chore: release v1.7 (9) 2026-05-18 11:46:28 +02:00
Jens Reinemann
23e0a47967 fix(publish): robustes Error-Handling in publish-apk.ps1
- Pre-Checks vor jeder Dateiänderung (Token, Regex-Validierung, SSH-Agent)
- Rollback: build.gradle.kts wird bei Build- oder Upload-Fehler zurückgesetzt
- SCP/SSH mit ConnectTimeout (kein ewiges Hängen bei VPS-Ausfall)
- API-Call mit Retry (2 Versuche, 3s Pause) + Recovery-Hinweis
- Verify + Git: non-fatal (nur Warnung, kein Abbruch)
- versionCode-Validierung: neuer Code muss > aktueller sein
- Set-StrictMode -Version Latest
2026-05-18 11:38:01 +02:00
Jens Reinemann
f3eab7b10d chore: deploy.ps1 entfernt (Logik in publish-apk.ps1) 2026-05-18 11:34:51 +02:00
Jens Reinemann
76ad50e3aa refactor(publish): publish-apk.ps1 übernimmt vollständigen Deploy-Workflow
- publish-apk.ps1: Version-Bump, Build, SCP, API, Verify, git commit/push
  (alle Parameter optional – Standalone-Nutzung ohne Copilot möglich)
- publish.prompt.md: vereinfacht (kein manueller Version-Bump mehr nötig)
- SKILL.md: Parameter-Tabelle aktualisiert
- deploy.ps1 im Root entfernt (Logik lebt jetzt im Skill)
2026-05-18 11:34:42 +02:00
Jens Reinemann
301d60aea4 chore: lokales deploy.ps1 statt GitHub Actions
- deploy.ps1: ein Befehl für vollständigen Release-Workflow
  (version bump + build + SCP + API + git commit/push)
- android-ci.yml entfernt (kein GitHub-Quota-Verbrauch mehr)
- BOLLWERK_ADMIN_TOKEN muss als Env-Var gesetzt sein
2026-05-18 11:29:47 +02:00
Jens Reinemann
ac5f346858 chore: .kotlin/ zu .gitignore hinzufügen 2026-05-18 11:25:14 +02:00
Jens Reinemann
ca1680b3a2 fix(genome): Distillation-Prompt schärfen – Specialized-Definition + Anti-Patterns
- Specialized klar abgegrenzt: nur konkrete Server-Deployments, Renames, Seeding
- 5 häufige Distillation-Fehler dokumentiert (member-added ignorieren, nur Anfang lesen, etc.)
- Erweiterte Evolutions-Muster (GPU-Hardening, Hot-Reload, API statt Restart)
- Zusätzliche Sanitization-Regeln (Server-IPs, Package-Namen)
- Erwartete Conversion-Rate: 15-30% als Orientierung
2026-05-18 11:23:56 +02:00
Jens Reinemann
bb578c5076 chore: version bump 1.6 (7) -> 1.7 (8), CI Deploy-Workflow redesign
- Version 1.7 (versionCode 8) deployed auf bollwerk.online
- android-ci.yml: nur workflow_dispatch, kein auto-Trigger
- Auto-Versionierung: versionCode wird im CI hochgezählt
- CI deployed direkt auf VPS via SCP + API-Call
- VPS: BOLLWERK_ADMIN_TOKEN konfiguriert (einmalig)
Benötigte Secrets in GitHub: BOLLWERK_ADMIN_TOKEN, VPS_SSH_PRIVATE_KEY
2026-05-18 11:09:26 +02:00
Jens Reinemann
5e73eccce6 chore(genome): alle genome-prompts auf Claude Opus 4.6 umgestellt 2026-05-18 10:55:53 +02:00
Jens Reinemann
ea3bd6dc97 fix(sync): robuste WebSocket-Verbindung und Token-Refresh
- Backoff nur nach stabiler Verbindung (>30s) zurücksetzen
  → verhindert rapiden 2s-4s-2s-Reconnect-Oscillation
- VIOLATED_POLICY Close-Reason erkennen → AuthRejected-Event
  → kein endloser Retry mit abgelaufenem Token
- Token-Refresh bei AuthRejected: MainViewModel refresht Access-Token
  und reconnectet WS automatisch; bei Fehlschlag Session-Expired
- executeItemRequest: fehlende 401-Retry-Logik ergänzt (Bug 4)
- SyncService.refreshAccessToken() als neue Interface-Methode
2026-05-18 10:48:46 +02:00
Jens Reinemann
e52f041d31 feat(genome): agent fragt immer nach Quell-Repo, Zeitraum und Ziel-Repo 2026-05-18 10:44:41 +02:00
Jens Reinemann
7dfdb6e505 chore(genome): formatting fixes (whitespace/table alignment) 2026-05-18 10:17:43 +02:00
Jens Reinemann
2071d758b5 fix(genome): improve distillation precision + propagation safety
genome-distill.prompt.md:
- Warnung vor versteckten Evolutions in Multi-Change-Commits
- Anleitung: Commit-Message ignorieren, jeden Hunk einzeln prüfen
- Rename-Churn-Erkennung (A→B→A = Specialized)
- Häufige versteckte Evolutions-Muster dokumentiert
- Analyse-Bericht am Ende mit Churn-Counter

genome-propagate.prompt.md:
- Neue Traits: immer einzeln vom User bestätigen lassen
- Nie automatisch neue Traits anlegen ohne explizite Bestätigung
2026-05-18 10:14:54 +02:00
Jens Reinemann
887cdbd3f7 feat(settings): server-sync UI aufräumen (#108)
- Login-Status + Logout auf eigene ElevatedCard
- Logout-Button als OutlinedButton (Material-Button statt TextLink)
- Letzte Sync direkt unter Verbindungsstatus ohne Divider
- Refresh-IconButton neben Serverstatus entfernt
- Server-URL Reset nur sichtbar wenn nicht-default Adresse
- Manuelle Sync-Buttons entfernt (vollautomatisch)
2026-05-18 10:09:58 +02:00
Jens Reinemann
bdd8cb4b11 feat(#106): category tap on dashboard navigates to inventory with filter
- Change Screen.ItemList from data object to data class with optional categoryId
- DashboardScreen: make CategoryCard clickable with onCategoryClick callback
- ItemListViewModel: read initial categoryId from SavedStateHandle
- BollwerkNavGraph: wire category click to navigate with categoryId
- Add test for initial category filter from navigation args
2026-05-18 10:01:14 +02:00
Jens Reinemann
7ccd2dc1fd refactor(genome): restructure as skill + prompt verbund
- Skill: .github/skills/genome/ (SKILL.md + genome-extract.py)
- Router: .github/prompts/genome.prompt.md (orchestriert alle 3 Phasen)
- Sub-Prompts: genome-distill.prompt.md, genome-propagate.prompt.md
- Output: .github/genome/output/ (gitignored)

Aufruf: /genome → fragt Quell-Repo + Zeitspanne, führt
Extraction → Distillation → Propagation durch.
2026-05-18 09:59:59 +02:00
Jens Reinemann
9cc69678e7 feat(genome): Phase 3 - Propagation Prompt
Matched Growth Vectors auf Ziel-Genome, generiert konkrete Patches
als Checkliste (Critical=an, Evolution≥7=an, <7=aus).
User wählt aus, Agent wendet Patches an.
2026-05-18 09:52:50 +02:00
Jens Reinemann
6318b0efe5 feat(genome): Phase 2 - Distillation Prompt
Klassifiziert Mutations (Critical/Evolution/Specialized),
scored Übertragungswert (1-10), sanitized sensitive Daten,
filtert projektspezifische Änderungen heraus.
2026-05-18 09:51:49 +02:00
Jens Reinemann
8e7352dcc4 feat(security): replace CleartextKeysetHandle with AndroidKeysetManager (#105)
- Extract PrivateKeysetStore interface for testability
- Add AndroidKeystorePrivateKeysetStore (Android Keystore-backed AEAD)
- Refactor E2EEKeyManager to use PrivateKeysetStore
- Add legacy migration: old cleartext key is removed, forcing re-generation
- Update DI module to provide AndroidKeystorePrivateKeysetStore
- Adapt unit tests with FakePrivateKeysetStore + migration test

Private key material no longer appears as cleartext JSON on the JVM heap.
Existing devices with legacy keys will re-generate and re-upload via
EnsureKeyPairUseCase on next app launch.
2026-05-18 09:51:24 +02:00
Jens Reinemann
10cb474906 refactor(genome): rewrite extraction in Python for proper UTF-8 support
PowerShell auf Windows hat Encoding-Probleme mit Git-Output (Umlaute).
Python 3 handhabt UTF-8 nativ korrekt.
2026-05-18 09:49:37 +02:00
Jens Reinemann
24c6fac0f8 feat(messaging): push notifications for incoming messages (#104)
- Add NotificationHelper with channel creation, grouped notifications,
  and deep-link PendingIntent into chat
- Trigger notification from MessageRepositoryImpl on WebSocket NewMessage
- Active-chat suppression in ChatViewModel (no notification for current chat)
- Deep-link from notification tap: MainActivity handles intent extras,
  MainScreen navigates to correct Chat screen
- Add POST_NOTIFICATIONS permission to AndroidManifest
- Add notification icon drawable (ic_notification_message)
- Add unit tests for notification suppression logic
- Fix pre-existing test compilation (SyncServiceImplTest missing authEventBus)
2026-05-18 09:39:39 +02:00
Jens Reinemann
8e75798507 feat(genome): Phase 1 - Extraction Script
Implementiert genome-extract.ps1:
- Trait-Erkennung (Skills/Agents/Prompts/Instructions)
- Verbund-Erkennung für Prompt-Router + Sub-Prompts
- Git-Log-Scanning mit Zeitspanne
- Mutation-Typ-Klassifizierung (content-change/member-added/member-removed)
- Strukturierte Markdown-Ausgabe mit Diffs
2026-05-18 09:32:57 +02:00
Jens Reinemann
5a26d6a85e refactor: rename workflow-*.prompt.md → nextstep-*.prompt.md
Namenskonvention für Genome Engine Verbund-Erkennung:
Router <name>.prompt.md + Sub-Prompts <name>-*.prompt.md
ermöglicht rein pfadbasierte Trait-Zuordnung ohne Content-Parsing.
2026-05-18 09:26:36 +02:00
Jens Reinemann
c771aa9547 feat(messaging): enforce 10 MB mailbox limit per receiver with FIFO eviction (#103)
- Add getUndeliveredStorageBytes() and evictOldestUndelivered() to MessageRepository
- Check mailbox size before saving; evict oldest undelivered messages if over 10 MB
- Return systemMessage in SendMessageResponse when eviction occurs
- App parses systemMessage and displays it in the sender's conversation
- Add SendMessageResponse to shared module for server/app interop
- Update existing tests to use new response format
- Add 3 new tests for eviction behavior
2026-05-18 09:17:15 +02:00
Jens Reinemann
6a8ffa17be feat(messaging): remove non-functional emoji button (#102) 2026-05-18 08:45:34 +02:00
Jens Reinemann
01a6d911ec feat(server): add POST /api/admin/version endpoint for APK deploy without restart
- Add VersionStore that persists versionCode/versionName to data/version.json
- Add POST /api/admin/version secured by BOLLWERK_ADMIN_TOKEN bearer auth
- GET /api/version now reads from VersionStore (fallback to env-vars)
- Update publish-apk.ps1 to use API call instead of SSH+sed+restart
- Update publish SKILL.md and vps-deploy SKILL.md documentation

Closes #100
2026-05-18 08:40:31 +02:00
Jens Reinemann
dad15b9e94 security: WebSocket Auth-Token aus Query-Parameter in Authorization-Header verschieben
- Client: Token als 'Authorization: Bearer' Header statt ?token= Query-Parameter senden
- Server: Token aus Authorization-Header statt Query-Parameter lesen
- Tests: Alle 8 WebSocket-Tests auf Header-Auth umgestellt
- Integration-Tests: WebSocket-Verbindung mit Header aktualisiert

Closes #97
2026-05-18 08:23:10 +02:00
Jens Reinemann
75f46de05e feat(server): seed test users alice and bob on startup 2026-05-18 08:19:58 +02:00
Jens Reinemann
dad2907481 feat: WebSocket-Lifecycle und Sync ab App-Start unabhaengig von Settings-Screen
- MainViewModel: verbindet WebSocket beim App-Start (connectOnStartup) und
  nach Login (via AuthEventBus.loginSuccess). Behandelt alle WebSocket-Events
  (Connected/FullSyncRequired/InventoryUpdated) -> pullSync/pushSync.
  Auto-pushSync wenn Server leer ist und lokale Daten vorhanden (Daten-Recovery).
- AuthEventBus: loginSuccess-Signal ergaenzt (serverUrl + token)
- SyncServiceImpl: emittiert loginSuccess nach erfolgreichem Login
- SettingsViewModel: WebSocket-Lifecycle entfernt (nur noch ConnectionFailed
  fuer UI-Fehlermeldung). Manueller Sync-Button bleibt erhalten.
- WebSocketClientImpl: vollstaendiges Logging, wiederholende User-Benachrichtigung
  bei Verbindungsfehlern (alle MAX_RETRIES Versuche statt nur einmalig)
2026-05-18 01:17:47 +02:00
Jens Reinemann
575c0ad709 feat: automatic forced logout on expired session
When both access and refresh token are invalid (401 on /auth/refresh),
the app now automatically logs out and navigates to Settings (login form).
No data loss - only auth tokens are cleared, local inventory data is intact.

- AuthEventBus: singleton SharedFlow that signals session expiry
- MainViewModel: observes bus, calls logout + disconnect, navigates to Settings
- MainScreen: LaunchedEffect collects navigateToSettings event
- MessageRepositoryImpl: emits session expired when refresh fails
- SyncServiceImpl: emits session expired when refresh fails
2026-05-18 00:55:25 +02:00
Jens Reinemann
a14c40d756 fix: 401 token refresh in MessageRepositoryImpl
fetchUsers() and attemptSendToServer() had no retry logic on 401.
SyncServiceImpl already had this pattern (auto-refresh on 401).

Add private refreshAccessToken(serverUrl) and retry once on 401
in both methods.
2026-05-18 00:44:58 +02:00
Jens Reinemann
ea02029dbe fix: SettingsKey circular init crash on app start
SENSITIVE_KEYS and SENSITIVE_KEY_STRINGS used eager initialization in the
companion object. When E2EEKeyManager.hasKeyPair() was the first access to
SettingsKey, it triggered SettingsKey.<clinit> which tried to resolve
StringKey.E2EEPrivateKeyset - but that class was already 'in initialization
by the current thread' (JVM spec). The JVM returned null, causing NPE in
SENSITIVE_KEY_STRINGS.map { it.key }.

Fix: use by lazy for both properties to defer initialization past <clinit>.
2026-05-18 00:39:32 +02:00