mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
fix(admin): storage backend needs api/v1 prefix in controller
Storage backend doesn't use setGlobalPrefix, so controller
needs full path @Controller('api/v1/admin')
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
42c0069553
commit
cdb6e25885
9 changed files with 1955 additions and 11 deletions
|
|
@ -0,0 +1,272 @@
|
|||
---
|
||||
title: '8 neue Matrix Bots, LLM Playground & Demo Mode Cleanup'
|
||||
description: '8 spezialisierte Matrix Bots für verschiedene ManaCore Apps, SvelteKit LLM Playground UI mit allen Ollama-Modellen, und Entfernung des Demo Modes aus 6 Apps für klarere UX'
|
||||
date: 2026-01-30
|
||||
author: 'Till Schneider'
|
||||
category: 'feature'
|
||||
tags:
|
||||
[
|
||||
'matrix-bots',
|
||||
'llm-playground',
|
||||
'ollama',
|
||||
'oidc',
|
||||
'demo-mode',
|
||||
'sveltekit',
|
||||
'better-auth',
|
||||
'shared-vite-config',
|
||||
]
|
||||
featured: false
|
||||
commits: 41
|
||||
readTime: 12
|
||||
---
|
||||
|
||||
Produktiver Tag mit **41 Commits** und Fokus auf Matrix Bot Expansion und Developer Experience:
|
||||
|
||||
- **8 neue Matrix Bots** - Spezialisierte Bots für Planta, ManaDeck, Contacts, Picture, Chat, SkillTree, Presi, Questions
|
||||
- **LLM Playground** - SvelteKit UI für alle Mac Mini Ollama-Modelle
|
||||
- **Demo Mode Cleanup** - Entfernung aus 6 Apps für klarere Login-Flows
|
||||
- **OIDC-Fixes** - Matrix Synapse als Trusted Client
|
||||
|
||||
---
|
||||
|
||||
## Neue Matrix Bots
|
||||
|
||||
8 neue spezialisierte Matrix Bots erstellt, die als NestJS Services laufen:
|
||||
|
||||
### Bot-Übersicht
|
||||
|
||||
| Bot | Port | Funktion |
|
||||
| ---------------------- | ---- | ---------------------------------- |
|
||||
| `matrix-planta-bot` | 3319 | Pflanzenpflege & Gieß-Erinnerungen |
|
||||
| `matrix-manadeck-bot` | 3320 | Kartendecks & Lernkarten |
|
||||
| `matrix-contacts-bot` | 3321 | Kontaktverwaltung |
|
||||
| `matrix-picture-bot` | 3322 | AI-Bildgenerierung |
|
||||
| `matrix-chat-bot` | 3323 | AI-Chat-Konversationen |
|
||||
| `matrix-skilltree-bot` | 3324 | Skill-Tracking & XP |
|
||||
| `matrix-presi-bot` | 3325 | Präsentationsverwaltung |
|
||||
| `matrix-questions-bot` | 3326 | Q&A Research Management |
|
||||
|
||||
### Bot-Struktur
|
||||
|
||||
Alle Bots folgen dem gleichen Pattern:
|
||||
|
||||
```
|
||||
services/matrix-{name}-bot/
|
||||
├── src/
|
||||
│ ├── bot/
|
||||
│ │ ├── {name}.module.ts
|
||||
│ │ └── {name}.service.ts
|
||||
│ ├── health/
|
||||
│ │ └── health.controller.ts
|
||||
│ └── main.ts
|
||||
├── Dockerfile
|
||||
└── package.json
|
||||
```
|
||||
|
||||
### Beispiel-Commands
|
||||
|
||||
**matrix-skilltree-bot:**
|
||||
|
||||
```
|
||||
!skill list - Alle Skills anzeigen
|
||||
!skill add "Coding" - Neuen Skill erstellen
|
||||
!xp add Coding 50 - 50 XP zu Coding hinzufügen
|
||||
!stats - Statistiken anzeigen
|
||||
```
|
||||
|
||||
**matrix-picture-bot:**
|
||||
|
||||
```
|
||||
!generate <prompt> - Bild generieren
|
||||
!style <style> - Stil setzen (realistic, anime, etc.)
|
||||
!variations - Variationen des letzten Bildes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## LLM Playground
|
||||
|
||||
Neue SvelteKit-Anwendung zum Testen aller verfügbaren LLM-Modelle.
|
||||
|
||||
### Features
|
||||
|
||||
| Feature | Beschreibung |
|
||||
| -------------------- | ------------------------------- |
|
||||
| **Model Selection** | Alle Mac Mini Ollama-Modelle |
|
||||
| **Streaming** | SSE-basiertes Token-Streaming |
|
||||
| **Chat History** | Konversations-Kontext |
|
||||
| **Auth Integration** | Shared Auth UI mit ManaCore SSO |
|
||||
|
||||
### Verfügbare Modelle
|
||||
|
||||
```typescript
|
||||
// apps/chat/apps/web/src/lib/config/models.ts
|
||||
export const OLLAMA_MODELS = [
|
||||
'gemma3:4b',
|
||||
'gemma3:12b',
|
||||
'llama3.2:3b',
|
||||
'llama3.2:11b',
|
||||
'mistral:7b',
|
||||
'codellama:13b',
|
||||
'deepseek-coder:6.7b',
|
||||
'phi3:14b',
|
||||
'qwen2.5:7b',
|
||||
];
|
||||
```
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ LLM Playground │────>│ mana-llm │────>│ Ollama │
|
||||
│ (SvelteKit) │ │ (Port 3025) │ │ (Port 11434) │
|
||||
│ Port 5197 │ │ │ │ │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
### Deployment
|
||||
|
||||
- Docker-Konfiguration für Production
|
||||
- Shared-Auth-UI Integration
|
||||
- Vite Config aus `@manacore/shared-vite-config`
|
||||
|
||||
---
|
||||
|
||||
## Demo Mode Cleanup
|
||||
|
||||
Entfernung des Demo Modes aus 6 Apps für klarere User Experience.
|
||||
|
||||
### Betroffene Apps
|
||||
|
||||
| App | Änderung |
|
||||
| --------- | -------------------------------------- |
|
||||
| Calendar | Demo Mode entfernt, Login erforderlich |
|
||||
| Todo | Demo Mode entfernt, Login erforderlich |
|
||||
| Contacts | Demo Mode entfernt, Login erforderlich |
|
||||
| Clock | Demo Mode entfernt, Login erforderlich |
|
||||
| Questions | Demo Mode entfernt, Login erforderlich |
|
||||
| Chat | Demo Mode entfernt, Login erforderlich |
|
||||
|
||||
### Begründung
|
||||
|
||||
- **Klarere UX**: Kein Wechsel zwischen Guest/Auth-Modi
|
||||
- **Einfacherer Code**: Keine Session-Storage-Logik
|
||||
- **Konsistentes Verhalten**: Alle Apps gleich
|
||||
- **SSO-Ready**: Nahtlose Auth über alle Apps
|
||||
|
||||
---
|
||||
|
||||
## OIDC-Verbesserungen
|
||||
|
||||
Fixes für die Matrix Synapse OIDC-Integration.
|
||||
|
||||
### Trusted Client Config
|
||||
|
||||
```typescript
|
||||
// mana-core-auth: Better Auth OIDC Client
|
||||
{
|
||||
clientId: 'synapse',
|
||||
clientSecret: process.env.MATRIX_OIDC_SECRET,
|
||||
redirectUrls: [
|
||||
'https://matrix.mana.how/_synapse/client/oidc/callback',
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
### Fixes
|
||||
|
||||
| Fix | Beschreibung |
|
||||
| ----------------------- | --------------------------------------- |
|
||||
| `redirectUrls` Property | Korrekter Property-Name für Better Auth |
|
||||
| `client_id` Extraction | Aus returnUrl für Login-Flow |
|
||||
| TypeScript Errors | OIDC-Login Controller |
|
||||
| CSP Inline Scripts | Für OIDC Login Page |
|
||||
|
||||
---
|
||||
|
||||
## Shared Vite Config Integration
|
||||
|
||||
Integration von `@manacore/shared-vite-config` in alle Web-Apps.
|
||||
|
||||
### Vorher
|
||||
|
||||
```typescript
|
||||
// Jede App hatte eigene Vite Config
|
||||
export default defineConfig({
|
||||
plugins: [tailwindcss(), sveltekit()],
|
||||
server: { port: 5174 },
|
||||
ssr: { noExternal: ['@manacore/shared-icons', ...] },
|
||||
});
|
||||
```
|
||||
|
||||
### Nachher
|
||||
|
||||
```typescript
|
||||
import { createViteConfig, mergeViteConfig } from '@manacore/shared-vite-config';
|
||||
|
||||
export default defineConfig(
|
||||
mergeViteConfig(createViteConfig({ port: 5174 }), { plugins: [tailwindcss(), sveltekit()] })
|
||||
);
|
||||
```
|
||||
|
||||
### Betroffene Apps
|
||||
|
||||
- calendar-web
|
||||
- Alle Apps via Dockerfile-Updates
|
||||
|
||||
---
|
||||
|
||||
## Matrix Bots Standardisierung
|
||||
|
||||
Standardisierung aller 9+ Matrix Bots mit einheitlicher package.json.
|
||||
|
||||
### Einheitliche Dependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"matrix-bot-sdk": "^0.7.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### TypeScript Fixes
|
||||
|
||||
- Strict null checks behoben
|
||||
- Einheitliche tsconfig
|
||||
|
||||
---
|
||||
|
||||
## Bugfixes
|
||||
|
||||
| Fix | Beschreibung |
|
||||
| ------------------------- | -------------------------------------- |
|
||||
| contacts-web syntax error | +layout.svelte Fix |
|
||||
| calendar-web API calls | Client URL für Browser-Requests |
|
||||
| calendar-web auth store | Initialisierung beim Mount |
|
||||
| matrix-web SSR | Disabled für App-Routes ($state error) |
|
||||
| mana-notify | Email-Benachrichtigungen deaktiviert |
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| --------------------- | ------- | ------------------------------ |
|
||||
| **Matrix Bots** | 8 | 8 neue spezialisierte Bots |
|
||||
| **LLM Playground** | 3 | SvelteKit UI, Auth Integration |
|
||||
| **Demo Mode Cleanup** | 6 | Entfernt aus 6 Apps |
|
||||
| **OIDC** | 8 | Matrix Synapse Integration |
|
||||
| **Shared Config** | 6 | Vite Config in alle Apps |
|
||||
| **Bugfixes** | 10 | Web Apps, Matrix, Auth |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Bot Migration** zu `@manacore/matrix-bot-common`
|
||||
2. **LLM Playground** Production Deployment
|
||||
3. **Voice Support** für Matrix Bots
|
||||
4. **E2EE** für Matrix Client
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
---
|
||||
title: 'Matrix Bot Konsolidierung, Voice Support & Manalink PWA'
|
||||
description: 'Massive Konsolidierung aller 19 Matrix Bots mit @manacore/matrix-bot-common, Voice Input/Output für mana-mana-bot, Manalink PWA Rebrand, und Telegram-zu-Matrix Migration'
|
||||
date: 2026-01-31
|
||||
author: 'Till Schneider'
|
||||
category: 'feature'
|
||||
tags:
|
||||
[
|
||||
'matrix-bots',
|
||||
'voice',
|
||||
'pwa',
|
||||
'manalink',
|
||||
'consolidation',
|
||||
'shared-packages',
|
||||
'mana-media',
|
||||
'telegram',
|
||||
'refactoring',
|
||||
'docker',
|
||||
]
|
||||
featured: true
|
||||
commits: 52
|
||||
readTime: 18
|
||||
---
|
||||
|
||||
Intensiver Tag (und Nacht!) mit **52 Commits** - der Fokus lag auf der Konsolidierung der Matrix Bot Infrastruktur:
|
||||
|
||||
- **@manacore/matrix-bot-common** - Neues Shared Package für alle 19 Matrix Bots
|
||||
- **Voice Support** - 4-Phasen-Implementierung für Voice Input/Output im mana-mana-bot
|
||||
- **Manalink PWA** - Rebrand des Matrix Web Clients mit PWA-Support
|
||||
- **Telegram Removal** - Migration zu Matrix-only Strategie
|
||||
- **mana-media MVP** - Unified Media Processing Platform
|
||||
- **Docker Restructure** - Neues Port-Schema und Naming Convention
|
||||
|
||||
---
|
||||
|
||||
## @manacore/matrix-bot-common
|
||||
|
||||
Neues Shared Package, das gemeinsame Funktionalität für alle Matrix Bots bereitstellt.
|
||||
|
||||
### Komponenten
|
||||
|
||||
```
|
||||
packages/matrix-bot-common/
|
||||
├── src/
|
||||
│ ├── base/
|
||||
│ │ └── BaseMatrixService.ts # Abstrakte Basisklasse
|
||||
│ ├── health/
|
||||
│ │ └── HealthController.ts # Shared Health Endpoint
|
||||
│ ├── utils/
|
||||
│ │ ├── KeywordCommandDetector.ts # Command Detection ohne !
|
||||
│ │ └── UserListMapper.ts # User-Formatierung
|
||||
│ └── index.ts
|
||||
└── package.json
|
||||
```
|
||||
|
||||
### BaseMatrixService
|
||||
|
||||
Abstrakte Basisklasse mit Matrix-Verbindungslogik:
|
||||
|
||||
```typescript
|
||||
export abstract class BaseMatrixService implements OnModuleInit {
|
||||
protected client: MatrixClient;
|
||||
|
||||
async onModuleInit() {
|
||||
this.client = new MatrixClient(this.config.homeserverUrl, this.config.accessToken);
|
||||
await this.client.start();
|
||||
this.client.on('room.message', this.handleMessage.bind(this));
|
||||
}
|
||||
|
||||
protected abstract handleMessage(roomId: string, event: any): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
### KeywordCommandDetector
|
||||
|
||||
Erkennt natürlichsprachliche Befehle ohne `!`-Prefix:
|
||||
|
||||
```typescript
|
||||
const detector = new KeywordCommandDetector({
|
||||
keywords: ['todo', 'aufgabe', 'task'],
|
||||
patterns: [/(?:erinnere mich|remind me)/i],
|
||||
});
|
||||
|
||||
// "Füge Einkaufen zur Todo-Liste" → detected
|
||||
// "Was steht auf meiner Aufgabenliste?" → detected
|
||||
```
|
||||
|
||||
### Migration
|
||||
|
||||
Alle 19 Matrix Bots wurden migriert:
|
||||
|
||||
| Phase | Bots | Änderungen |
|
||||
| ----- | ---- | ---------------------- |
|
||||
| 1 | 5 | HealthController |
|
||||
| 2 | 5 | BaseMatrixService |
|
||||
| 3 | 4 | UserListMapper |
|
||||
| 4 | 5 | KeywordCommandDetector |
|
||||
|
||||
---
|
||||
|
||||
## Voice Support für matrix-mana-bot
|
||||
|
||||
4-Phasen-Implementierung von Voice Input/Output.
|
||||
|
||||
### Phase 1: Voice Input
|
||||
|
||||
```typescript
|
||||
// Sprachnachrichten via mana-stt transkribieren
|
||||
async handleVoiceMessage(event: MatrixEvent): Promise<string> {
|
||||
const audioUrl = event.content.url;
|
||||
const audioBuffer = await this.downloadMedia(audioUrl);
|
||||
const transcription = await this.sttClient.transcribe(audioBuffer);
|
||||
return transcription.text;
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 2: Voice Output (TTS)
|
||||
|
||||
```typescript
|
||||
// Text-zu-Sprache für Antworten
|
||||
async sendVoiceReply(roomId: string, text: string): Promise<void> {
|
||||
const audioBuffer = await this.ttsClient.synthesize(text, {
|
||||
voice: 'de-DE-FlorianNeural',
|
||||
speed: 1.0,
|
||||
});
|
||||
await this.client.sendAudio(roomId, audioBuffer, 'response.mp3');
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3: Smart Voice Formatting
|
||||
|
||||
Intelligente Aufbereitung von Text für Sprachausgabe:
|
||||
|
||||
| Input | Voice Output |
|
||||
| -------- | --------------------------- |
|
||||
| `15:30` | "fünfzehn Uhr dreißig" |
|
||||
| `3.5kg` | "drei Komma fünf Kilogramm" |
|
||||
| URLs | Werden übersprungen |
|
||||
| Markdown | Wird entfernt |
|
||||
|
||||
### Phase 4: Persistent Voice Preferences
|
||||
|
||||
```typescript
|
||||
// User-Präferenzen in Redis speichern
|
||||
interface VoicePreferences {
|
||||
enabled: boolean;
|
||||
voice: string;
|
||||
speed: number;
|
||||
autoTranscribe: boolean;
|
||||
}
|
||||
|
||||
await this.redis.hset(`voice:${userId}`, preferences);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Manalink PWA
|
||||
|
||||
Rebrand des Matrix Web Clients zu "Manalink" mit PWA-Support.
|
||||
|
||||
### PWA-Features
|
||||
|
||||
| Feature | Beschreibung |
|
||||
| ---------------------- | ---------------------- |
|
||||
| **Installierbar** | Add to Home Screen |
|
||||
| **Offline** | Service Worker Caching |
|
||||
| **Push Notifications** | Web Push API |
|
||||
| **App-Icon** | Custom Manalink Icon |
|
||||
|
||||
### Manifest
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Manalink",
|
||||
"short_name": "Manalink",
|
||||
"description": "ManaCore Matrix Client",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"theme_color": "#6366f1",
|
||||
"background_color": "#0f172a"
|
||||
}
|
||||
```
|
||||
|
||||
### UX-Änderungen
|
||||
|
||||
- SSO als primärer Login (manueller Login versteckt)
|
||||
- Vereinfachte Login-Seite
|
||||
- Dark Mode als Default
|
||||
|
||||
---
|
||||
|
||||
## Telegram Removal
|
||||
|
||||
Strategische Entscheidung: Fokus auf Matrix als einzige Chat-Plattform.
|
||||
|
||||
### Entfernte Services
|
||||
|
||||
```
|
||||
services/
|
||||
├── telegram-ollama-bot/ # ENTFERNT
|
||||
├── telegram-project-doc-bot/ # ENTFERNT
|
||||
├── telegram-nutriphi-bot/ # ENTFERNT
|
||||
├── telegram-todo-bot/ # ENTFERNT
|
||||
└── telegram-zitare-bot/ # ENTFERNT
|
||||
```
|
||||
|
||||
### Begründung
|
||||
|
||||
| Aspekt | Telegram | Matrix |
|
||||
| ---------------- | --------- | -------- |
|
||||
| **Self-Hosted** | Nein | Ja |
|
||||
| **E2EE** | Optional | Standard |
|
||||
| **Bot Platform** | Limitiert | Flexibel |
|
||||
| **Integration** | Extern | Native |
|
||||
|
||||
---
|
||||
|
||||
## mana-media MVP
|
||||
|
||||
Unified Media Processing Platform für alle ManaCore Apps.
|
||||
|
||||
### Features
|
||||
|
||||
```
|
||||
services/mana-media/
|
||||
├── src/
|
||||
│ ├── processing/
|
||||
│ │ ├── image.service.ts # Resize, Crop, Format
|
||||
│ │ ├── video.service.ts # Transcode, Thumbnail
|
||||
│ │ └── audio.service.ts # Convert, Normalize
|
||||
│ ├── storage/
|
||||
│ │ └── s3.service.ts # MinIO/S3 Storage
|
||||
│ └── metadata/
|
||||
│ └── exif.service.ts # EXIF Extraction
|
||||
└── Dockerfile
|
||||
```
|
||||
|
||||
### API Endpoints
|
||||
|
||||
| Endpoint | Beschreibung |
|
||||
| --------------------- | ---------------------- |
|
||||
| `POST /process/image` | Bildverarbeitung |
|
||||
| `POST /process/video` | Videokonvertierung |
|
||||
| `GET /metadata/:id` | EXIF/Metadaten abrufen |
|
||||
|
||||
---
|
||||
|
||||
## Docker Restructure
|
||||
|
||||
Neue Port-Schema und Naming Convention für alle Services.
|
||||
|
||||
### Port Ranges
|
||||
|
||||
| Range | Typ |
|
||||
| --------- | --------------------------------- |
|
||||
| 3001-3099 | Core Services (Auth, Search, LLM) |
|
||||
| 3100-3199 | App Backends |
|
||||
| 3300-3399 | Matrix Bots |
|
||||
| 5100-5199 | Web Apps |
|
||||
| 8000-8099 | Infrastructure |
|
||||
|
||||
### Naming Convention
|
||||
|
||||
```yaml
|
||||
# Vorher
|
||||
container_name: chat-backend
|
||||
container_name: todo-backend
|
||||
|
||||
# Nachher
|
||||
container_name: mana-chat-backend
|
||||
container_name: mana-todo-backend
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bot Services Consolidation
|
||||
|
||||
Konsolidierung von SessionService und TranscriptionService.
|
||||
|
||||
### @manacore/bot-services Updates
|
||||
|
||||
```typescript
|
||||
// Vorher: In jedem Bot
|
||||
class SessionService {
|
||||
private sessions = new Map();
|
||||
}
|
||||
|
||||
// Nachher: Shared Package
|
||||
import { SessionService } from '@manacore/bot-services';
|
||||
```
|
||||
|
||||
### Shared Services
|
||||
|
||||
| Service | Funktion |
|
||||
| ---------------------- | ------------------------ |
|
||||
| `SessionService` | User Sessions über Redis |
|
||||
| `TranscriptionService` | STT via mana-stt |
|
||||
| `CreditService` | Credit-Verbrauch tracken |
|
||||
|
||||
---
|
||||
|
||||
## Model Comparison Feature
|
||||
|
||||
Neues Feature im LLM Playground für Modellvergleiche.
|
||||
|
||||
### UI
|
||||
|
||||
```typescript
|
||||
// Gleichzeitig mehrere Modelle abfragen
|
||||
const models = ['gemma3:4b', 'llama3.2:3b', 'mistral:7b'];
|
||||
const responses = await Promise.all(models.map((model) => llmClient.chat(model, prompt)));
|
||||
```
|
||||
|
||||
### Metriken
|
||||
|
||||
| Metrik | Beschreibung |
|
||||
| -------------- | -------------------- |
|
||||
| **Latency** | Time to first token |
|
||||
| **Throughput** | Tokens per second |
|
||||
| **Quality** | Subjektive Bewertung |
|
||||
|
||||
---
|
||||
|
||||
## Grafana & Prometheus Fixes
|
||||
|
||||
Zahlreiche Fixes für das Monitoring-System.
|
||||
|
||||
### Fixes
|
||||
|
||||
| Fix | Beschreibung |
|
||||
| -------------------- | --------------------------- |
|
||||
| VictoriaMetrics Port | 8428 → 9090 |
|
||||
| Backend Ports | Korrekte Scrape Targets |
|
||||
| Missing Services | Neu hinzugefügt |
|
||||
| Home Dashboard | Master Overview als Default |
|
||||
|
||||
---
|
||||
|
||||
## Bugfixes
|
||||
|
||||
| Fix | Beschreibung |
|
||||
| --------------------- | -------------------------------- |
|
||||
| matrix-bot-common ESM | Explicit Imports für Node.js v25 |
|
||||
| bot-services Build | Compile Step hinzugefügt |
|
||||
| Type Errors | Web Apps, mana-media, calendar |
|
||||
| tsconfig Issues | Alle NestJS Backends |
|
||||
| matrix-mana-bot DI | Service Modules als Global |
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| ---------------------- | ------- | ---------------------- |
|
||||
| **matrix-bot-common** | 8 | Neues Shared Package |
|
||||
| **Bot Migration** | 12 | 19 Bots konsolidiert |
|
||||
| **Voice Support** | 4 | 4 Phasen implementiert |
|
||||
| **Manalink PWA** | 2 | Rebrand + PWA |
|
||||
| **Telegram Removal** | 1 | Matrix-only Strategie |
|
||||
| **mana-media** | 2 | MVP implementiert |
|
||||
| **Docker Restructure** | 1 | Neues Port-Schema |
|
||||
| **Grafana/Prometheus** | 8 | Monitoring Fixes |
|
||||
| **Bugfixes** | 14 | Build, Types, ESM |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Matrix E2EE** aktivieren
|
||||
2. **Voice Preferences UI** im Manalink Client
|
||||
3. **mana-media** mit NutriPhi integrieren
|
||||
4. **Matrix Bots CI/CD** Pipeline
|
||||
|
|
@ -0,0 +1,365 @@
|
|||
---
|
||||
title: 'SSD Migration, i18n für Auth Pages & Matrix Bots CI/CD'
|
||||
description: 'PostgreSQL und MinIO auf SSD migriert, mehrsprachige Auth-Pages für alle Apps, automatisierte CI/CD Pipeline für 19 Matrix Bots, und erweiterte Grafana Dashboards'
|
||||
date: 2026-02-01
|
||||
author: 'Till Schneider'
|
||||
category: 'infrastructure'
|
||||
tags:
|
||||
[
|
||||
'ssd',
|
||||
'migration',
|
||||
'i18n',
|
||||
'ci-cd',
|
||||
'github-actions',
|
||||
'matrix-bots',
|
||||
'grafana',
|
||||
'monitoring',
|
||||
'oidc',
|
||||
'production',
|
||||
]
|
||||
featured: false
|
||||
commits: 42
|
||||
readTime: 14
|
||||
---
|
||||
|
||||
Produktiver Tag mit **42 Commits** und Fokus auf Infrastructure und Production Readiness:
|
||||
|
||||
- **SSD Migration** - PostgreSQL und MinIO auf externe SSD verschoben
|
||||
- **i18n für Auth** - Alle Auth-Pages mehrsprachig (DE/EN)
|
||||
- **Matrix Bots CI/CD** - Automatisierte GHCR Deployment Pipeline
|
||||
- **Grafana Dashboards** - Master Overview mit Key Metrics
|
||||
- **OIDC Production** - mana-core-auth vollständig produktionsreif
|
||||
- **node-exporter** - Host System Metrics für Monitoring
|
||||
|
||||
---
|
||||
|
||||
## SSD Migration
|
||||
|
||||
Migration der Datenbanken auf externe SSD für bessere Performance.
|
||||
|
||||
### Migrierte Services
|
||||
|
||||
| Service | Vorher | Nachher |
|
||||
| ------- | ------ | ------- |
|
||||
| PostgreSQL | Docker Volume | `/Volumes/ManaData/postgres` |
|
||||
| MinIO | Docker Volume | `/Volumes/ManaData/minio` |
|
||||
|
||||
### Docker Compose Änderungen
|
||||
|
||||
```yaml
|
||||
services:
|
||||
manacore-postgres:
|
||||
volumes:
|
||||
- /Volumes/ManaData/postgres:/var/lib/postgresql/data
|
||||
|
||||
manacore-minio:
|
||||
volumes:
|
||||
- /Volumes/ManaData/minio:/data
|
||||
```
|
||||
|
||||
### Vorteile
|
||||
|
||||
| Aspekt | HDD (intern) | SSD (extern) |
|
||||
| ------ | ------------ | ------------ |
|
||||
| **Read Speed** | ~100 MB/s | ~500 MB/s |
|
||||
| **Write Speed** | ~100 MB/s | ~450 MB/s |
|
||||
| **IOPS** | ~100 | ~10.000 |
|
||||
| **Latency** | ~10ms | ~0.1ms |
|
||||
|
||||
### Dokumentation
|
||||
|
||||
Neue SSD-Dokumentation unter `docs/MAC_MINI_SSD.md`:
|
||||
|
||||
- Mount-Konfiguration
|
||||
- Backup-Strategie
|
||||
- Performance-Benchmarks
|
||||
|
||||
---
|
||||
|
||||
## i18n für Auth Pages
|
||||
|
||||
Alle Authentifizierungs-Seiten sind jetzt mehrsprachig.
|
||||
|
||||
### Unterstützte Sprachen
|
||||
|
||||
| Sprache | Code | Status |
|
||||
| ------- | ---- | ------ |
|
||||
| Deutsch | `de` | Vollständig |
|
||||
| English | `en` | Vollständig |
|
||||
|
||||
### Betroffene Apps
|
||||
|
||||
- Calendar Web
|
||||
- Chat Web
|
||||
- Clock Web
|
||||
- Contacts Web
|
||||
- NutriPhi Web
|
||||
- Picture Web
|
||||
- Planta Web
|
||||
- Questions Web
|
||||
- SkillTree Web
|
||||
- Todo Web
|
||||
- Zitare Web
|
||||
|
||||
### Implementierung
|
||||
|
||||
```typescript
|
||||
// Locale Detection
|
||||
const locale = navigator.language.startsWith('de') ? 'de' : 'en';
|
||||
|
||||
// i18n Store
|
||||
export const t = derived(locale, ($locale) => {
|
||||
return (key: string) => translations[$locale][key] || key;
|
||||
});
|
||||
```
|
||||
|
||||
### Neue Auth Pages
|
||||
|
||||
Fehlende Auth-Pages für Zitare und Planta hinzugefügt:
|
||||
|
||||
- `/login`
|
||||
- `/register`
|
||||
- `/forgot-password`
|
||||
- `/reset-password`
|
||||
- `/verify-email`
|
||||
|
||||
---
|
||||
|
||||
## Matrix Bots CI/CD
|
||||
|
||||
Automatisierte Build und Deployment Pipeline für alle Matrix Bots.
|
||||
|
||||
### GitHub Actions Workflow
|
||||
|
||||
```yaml
|
||||
# .github/workflows/matrix-bots.yml
|
||||
name: Matrix Bots CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'services/matrix-*-bot/**'
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
bot:
|
||||
- matrix-mana-bot
|
||||
- matrix-todo-bot
|
||||
- matrix-calendar-bot
|
||||
# ... alle 19 Bots
|
||||
steps:
|
||||
- uses: docker/build-push-action@v5
|
||||
with:
|
||||
push: true
|
||||
tags: ghcr.io/manacore/${{ matrix.bot }}:latest
|
||||
```
|
||||
|
||||
### Betroffene Bots
|
||||
|
||||
| Bot | GHCR Image |
|
||||
| --- | ---------- |
|
||||
| matrix-mana-bot | `ghcr.io/manacore/matrix-mana-bot` |
|
||||
| matrix-todo-bot | `ghcr.io/manacore/matrix-todo-bot` |
|
||||
| matrix-calendar-bot | `ghcr.io/manacore/matrix-calendar-bot` |
|
||||
| ... | ... (19 total) |
|
||||
|
||||
### ARM64 Workaround
|
||||
|
||||
QEMU-Emulation für ARM64 deaktiviert aufgrund von CI-Fehlern:
|
||||
|
||||
```yaml
|
||||
platforms: linux/amd64 # ARM64 temporär deaktiviert
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Grafana Dashboards
|
||||
|
||||
Erweiterte Monitoring Dashboards.
|
||||
|
||||
### Master Overview
|
||||
|
||||
Neues Home Dashboard mit Key Metrics:
|
||||
|
||||
| Panel | Metrik |
|
||||
| ----- | ------ |
|
||||
| **Total Requests** | Summe aller HTTP Requests |
|
||||
| **Requests/sec** | Aktuelle Request-Rate |
|
||||
| **Error Rate** | HTTP 5xx Errors |
|
||||
| **Response Time** | P95 Latency |
|
||||
|
||||
### System Overview
|
||||
|
||||
Neugeschrieben mit verfügbaren Metriken:
|
||||
|
||||
- CPU Usage (per Container)
|
||||
- Memory Usage (per Container)
|
||||
- Network I/O
|
||||
- Disk Usage
|
||||
|
||||
### Infinity Datasource
|
||||
|
||||
Plugin für Business Metrics installiert:
|
||||
|
||||
```bash
|
||||
grafana-cli plugins install yesoreyeram-infinity-datasource
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## node-exporter
|
||||
|
||||
Host System Metrics für macOS Docker.
|
||||
|
||||
### Metriken
|
||||
|
||||
| Metrik | Beschreibung |
|
||||
| ------ | ------------ |
|
||||
| `node_cpu_seconds_total` | CPU-Nutzung |
|
||||
| `node_memory_MemTotal_bytes` | Gesamter RAM |
|
||||
| `node_filesystem_size_bytes` | Disk-Größe |
|
||||
| `node_network_receive_bytes_total` | Netzwerk RX |
|
||||
|
||||
### macOS-spezifische Konfiguration
|
||||
|
||||
```yaml
|
||||
node-exporter:
|
||||
image: prom/node-exporter:latest
|
||||
volumes:
|
||||
- /proc:/host/proc:ro
|
||||
- /sys:/host/sys:ro
|
||||
command:
|
||||
- '--path.procfs=/host/proc'
|
||||
- '--path.sysfs=/host/sys'
|
||||
- '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev)($|/)'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## OIDC Production Readiness
|
||||
|
||||
mana-core-auth ist jetzt vollständig produktionsreif.
|
||||
|
||||
### Fixes
|
||||
|
||||
| Fix | Beschreibung |
|
||||
| --- | ------------ |
|
||||
| **EdDSA Signing** | OIDC id_token mit EdDSA statt RS256 |
|
||||
| **JWT Issuer** | BASE_URL als Issuer |
|
||||
| **Token Exchange** | body-parser für form-urlencoded |
|
||||
| **Test Fixes** | Alle Tests grün |
|
||||
|
||||
### OIDC Token Exchange
|
||||
|
||||
```typescript
|
||||
// Vorher: JSON only
|
||||
app.use(express.json());
|
||||
|
||||
// Nachher: JSON + form-urlencoded
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
```
|
||||
|
||||
### Token Endpoint
|
||||
|
||||
```bash
|
||||
# OAuth2 Token Request (form-urlencoded)
|
||||
curl -X POST https://auth.mana.how/oidc/token \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=authorization_code&code=xxx&client_id=synapse"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Resend Verification Email
|
||||
|
||||
Neues Feature auf der Registrierungsseite.
|
||||
|
||||
### UI
|
||||
|
||||
```svelte
|
||||
{#if registrationSuccess && !verified}
|
||||
<div class="alert">
|
||||
<p>Bitte bestätige deine Email-Adresse.</p>
|
||||
<button onclick={resendVerification}>
|
||||
Bestätigungsmail erneut senden
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
```typescript
|
||||
// POST /api/v1/auth/resend-verification
|
||||
await authService.resendVerificationEmail(email);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cloudflared Port Updates
|
||||
|
||||
Alle Service-Ports in Cloudflared aktualisiert.
|
||||
|
||||
### Geänderte Ports
|
||||
|
||||
| Service | Alt | Neu |
|
||||
| ------- | --- | --- |
|
||||
| matrix.mana.how | 8008 | 4000 |
|
||||
| matrix-web | 5178 | 5180 |
|
||||
| element.mana.how | 80 | 8088 |
|
||||
|
||||
---
|
||||
|
||||
## Bugfixes
|
||||
|
||||
| Fix | Beschreibung |
|
||||
| --- | ------------ |
|
||||
| **Matrix SSO** | loginToken Callback Handler |
|
||||
| **Bot Health Checks** | wget installiert in Docker |
|
||||
| **Crypto Module** | E2EE via pnpm override deaktiviert |
|
||||
| **Native Modules** | node:20-slim für Bot Images |
|
||||
| **CORS Origins** | Alle Apps hinzugefügt |
|
||||
| **Questions Locale** | 'de' als Fallback |
|
||||
|
||||
---
|
||||
|
||||
## Test User Seeding
|
||||
|
||||
Neuer Test-User für Development.
|
||||
|
||||
```typescript
|
||||
// scripts/seed-dev.ts
|
||||
await db.insert(users).values({
|
||||
email: 't@t.de',
|
||||
password: await hash('test1234'),
|
||||
verified: true,
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| ------- | ------- | ---------- |
|
||||
| **SSD Migration** | 4 | PostgreSQL + MinIO |
|
||||
| **i18n** | 3 | Alle Auth Pages DE/EN |
|
||||
| **Matrix Bots CI/CD** | 2 | 19 Bots automatisiert |
|
||||
| **Grafana** | 6 | Master Overview, Infinity |
|
||||
| **node-exporter** | 3 | Host Metrics |
|
||||
| **OIDC** | 8 | Production Ready |
|
||||
| **Cloudflared** | 4 | Port Updates |
|
||||
| **Bugfixes** | 12 | Docker, Matrix, Auth |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Cross-Domain SSO** für alle Web Apps
|
||||
2. **Matrix Bots** auf Mac Mini deployen
|
||||
3. **Grafana Alerts** konfigurieren
|
||||
4. **Backup Workflow** mit n8n
|
||||
|
|
@ -0,0 +1,406 @@
|
|||
---
|
||||
title: 'Cross-Domain SSO, mana-media Integration & Matrix Bots Page'
|
||||
description: 'Cross-Subdomain SSO für alle .mana.how Apps, mana-media NutriPhi Integration, neue Bots-Übersichtsseite in Manalink, und mana-llm Production Deployment'
|
||||
date: 2026-02-02
|
||||
author: 'Till Schneider'
|
||||
category: 'feature'
|
||||
tags:
|
||||
[
|
||||
'sso',
|
||||
'cross-domain',
|
||||
'mana-media',
|
||||
'matrix',
|
||||
'bots',
|
||||
'mana-llm',
|
||||
'production',
|
||||
'nutriphi',
|
||||
'calendar',
|
||||
'ux',
|
||||
]
|
||||
featured: true
|
||||
commits: 40
|
||||
readTime: 15
|
||||
---
|
||||
|
||||
Produktiver Tag mit **40 Commits** und Fokus auf nahtlose Authentifizierung über alle Apps:
|
||||
|
||||
- **Cross-Domain SSO** - Single Sign-On für alle .mana.how Subdomains
|
||||
- **mana-media Integration** - NutriPhi mit zentraler Medienverarbeitung
|
||||
- **Matrix Bots Page** - Übersicht aller 19 Bots in Manalink
|
||||
- **mana-llm Production** - LLM Gateway auf Mac Mini deployed
|
||||
- **i18n für Matrix Bots** - Mehrsprachige Bot-Antworten
|
||||
- **Calendar UX** - Tasks versteckt, automatischer Scroll zu Mittag
|
||||
|
||||
---
|
||||
|
||||
## Cross-Domain SSO
|
||||
|
||||
Single Sign-On über alle ManaCore Web Apps.
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Cross-Domain SSO Flow │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ User besucht Session Check Bereits eingeloggt │
|
||||
│ calendar.mana.how ─────────────────────> auth.mana.how │
|
||||
│ │ │ │
|
||||
│ │ Cookie gefunden │ │
|
||||
│ │<──────────────────────────────────────│ │
|
||||
│ │ auf .mana.how │ │
|
||||
│ │ │ │
|
||||
│ ▼ │
|
||||
│ Automatisch eingeloggt │
|
||||
│ (kein Login-Redirect) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Cookie-Konfiguration
|
||||
|
||||
```typescript
|
||||
// mana-core-auth: Cookie Settings
|
||||
{
|
||||
name: 'manacore_session',
|
||||
domain: '.mana.how', // Shared across subdomains
|
||||
secure: true,
|
||||
sameSite: 'lax',
|
||||
httpOnly: true,
|
||||
path: '/',
|
||||
}
|
||||
```
|
||||
|
||||
### Betroffene Apps
|
||||
|
||||
| App | URL | SSO Status |
|
||||
| ---------- | ------------------- | ---------- |
|
||||
| Calendar | calendar.mana.how | ✅ |
|
||||
| Chat | chat.mana.how | ✅ |
|
||||
| Clock | clock.mana.how | ✅ |
|
||||
| Contacts | contacts.mana.how | ✅ |
|
||||
| NutriPhi | nutriphi.mana.how | ✅ |
|
||||
| Picture | picture.mana.how | ✅ |
|
||||
| Planta | planta.mana.how | ✅ |
|
||||
| Questions | questions.mana.how | ✅ |
|
||||
| SkillTree | skilltree.mana.how | ✅ |
|
||||
| Storage | storage.mana.how | ✅ |
|
||||
| Todo | todo.mana.how | ✅ |
|
||||
| Zitare | zitare.mana.how | ✅ |
|
||||
| Manalink | manalink.mana.how | ✅ |
|
||||
| Playground | playground.mana.how | ✅ |
|
||||
|
||||
### get-session Endpoint
|
||||
|
||||
Neuer Endpoint für Session-Validierung:
|
||||
|
||||
```typescript
|
||||
// GET /api/auth/get-session
|
||||
// Returns: { user, session } or null
|
||||
|
||||
const response = await fetch('https://auth.mana.how/api/auth/get-session', {
|
||||
credentials: 'include', // Wichtig für Cross-Domain Cookies
|
||||
});
|
||||
const { user } = await response.json();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## mana-media Integration
|
||||
|
||||
Zentrale Medienverarbeitung mit NutriPhi als erster Integration.
|
||||
|
||||
### NutriPhi Integration
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ NutriPhi │────>│ mana-media │────>│ MinIO │
|
||||
│ (Upload) │ │ (Process) │ │ (Storage) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │
|
||||
│ │ EXIF Extraction
|
||||
│ │ Thumbnail Generation
|
||||
│ │ Resize/Compress
|
||||
│ ▼
|
||||
│ ┌─────────────────┐
|
||||
│ │ PostgreSQL │
|
||||
│ │ (Metadata) │
|
||||
│ └─────────────────┘
|
||||
```
|
||||
|
||||
### Änderungen
|
||||
|
||||
| Änderung | Beschreibung |
|
||||
| --------------- | ---------------------------------- |
|
||||
| `userId` Type | UUID → TEXT (für Matrix User IDs) |
|
||||
| Body Size Limit | 10mb → 50mb (Bilder) |
|
||||
| Dockerfile | Vereinfacht auf Single Build Stage |
|
||||
|
||||
### API
|
||||
|
||||
```typescript
|
||||
// POST /api/v1/media/upload
|
||||
const formData = new FormData();
|
||||
formData.append('file', imageFile);
|
||||
formData.append('context', 'meal');
|
||||
|
||||
const response = await fetch('https://media.mana.how/api/v1/media/upload', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Matrix Bots Page
|
||||
|
||||
Neue Übersichtsseite mit allen 19 Matrix Bots in Manalink.
|
||||
|
||||
### UI
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Manalink - Bots │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐│
|
||||
│ │ 🤖 mana-mana-bot ││
|
||||
│ │ Der zentrale AI-Assistent mit Voice Support ││
|
||||
│ │ Commands: !help, !model, Voice Messages ││
|
||||
│ └─────────────────────────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐│
|
||||
│ │ ✅ matrix-todo-bot ││
|
||||
│ │ Task-Management mit natürlicher Sprache ││
|
||||
│ │ Commands: todo, liste, erledigt ││
|
||||
│ └─────────────────────────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ... (17 weitere Bots) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Bot-Liste
|
||||
|
||||
| Bot | Kategorie | Beschreibung |
|
||||
| -------------------- | ------------ | ---------------------- |
|
||||
| mana-mana-bot | AI | Zentraler AI-Assistent |
|
||||
| matrix-todo-bot | Productivity | Task-Management |
|
||||
| matrix-calendar-bot | Productivity | Termine & Erinnerungen |
|
||||
| matrix-clock-bot | Utility | Timer & Weltzeit |
|
||||
| matrix-contacts-bot | Productivity | Kontaktverwaltung |
|
||||
| matrix-nutriphi-bot | Health | Ernährungs-Tracking |
|
||||
| matrix-picture-bot | AI | Bildgenerierung |
|
||||
| matrix-zitare-bot | Inspiration | Tägliche Zitate |
|
||||
| matrix-skilltree-bot | Gamification | Skill-Tracking |
|
||||
| matrix-planta-bot | Lifestyle | Pflanzenpflege |
|
||||
| matrix-manadeck-bot | Learning | Lernkarten |
|
||||
| matrix-presi-bot | Productivity | Präsentationen |
|
||||
| matrix-questions-bot | Research | Q&A Management |
|
||||
| matrix-chat-bot | AI | AI-Chat |
|
||||
| matrix-ollama-bot | AI | LLM Direct Access |
|
||||
| matrix-tts-bot | Media | Text-to-Speech |
|
||||
| matrix-stt-bot | Media | Speech-to-Text |
|
||||
| matrix-storage-bot | Utility | Dateiverwaltung |
|
||||
| matrix-voice-bot | AI | Voice-to-Voice |
|
||||
|
||||
### Layout
|
||||
|
||||
Single Column Layout für bessere Lesbarkeit auf allen Geräten.
|
||||
|
||||
---
|
||||
|
||||
## mana-llm Production
|
||||
|
||||
LLM Gateway auf Mac Mini deployed.
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```yaml
|
||||
mana-llm:
|
||||
image: ghcr.io/manacore/mana-llm:latest
|
||||
ports:
|
||||
- '3025:3025'
|
||||
environment:
|
||||
- OLLAMA_URL=http://host.docker.internal:11434
|
||||
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### SSE Fix
|
||||
|
||||
Double-Data-Prefix Problem behoben:
|
||||
|
||||
```python
|
||||
# Vorher (falsch)
|
||||
yield f"data: data: {json.dumps(chunk)}\n\n"
|
||||
|
||||
# Nachher (korrekt)
|
||||
yield f"data: {json.dumps(chunk)}\n\n"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## i18n für Matrix Bots
|
||||
|
||||
Mehrsprachige Bot-Antworten basierend auf User-Präferenzen.
|
||||
|
||||
### Unterstützte Sprachen
|
||||
|
||||
| Sprache | Code |
|
||||
| ------- | ---- |
|
||||
| Deutsch | `de` |
|
||||
| English | `en` |
|
||||
|
||||
### Implementierung
|
||||
|
||||
```typescript
|
||||
// bot-services/i18n/index.ts
|
||||
export function t(key: string, locale: string = 'de'): string {
|
||||
return translations[locale]?.[key] || translations['de'][key] || key;
|
||||
}
|
||||
|
||||
// Verwendung
|
||||
const response = t('todo.created', userLocale);
|
||||
// DE: "Aufgabe erstellt!"
|
||||
// EN: "Task created!"
|
||||
```
|
||||
|
||||
### Direct Message Fallback
|
||||
|
||||
Bots antworten jetzt auch in DMs statt nur in Rooms:
|
||||
|
||||
```typescript
|
||||
if (event.sender !== this.client.getUserId()) {
|
||||
// Auch Direct Messages beantworten
|
||||
await this.handleCommand(event);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cross-Bot SSO via Redis
|
||||
|
||||
Single Sign-On über verschiedene Matrix Bots.
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ matrix-todo- │ │ matrix-cal- │
|
||||
│ bot │ │ endar-bot │
|
||||
│ │ │ │
|
||||
└────────┬────────┘ └────────┬────────┘
|
||||
│ │
|
||||
│ Redis Sessions │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ │
|
||||
└───>│ Redis │<───┘
|
||||
│ Sessions │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
### Session Sharing
|
||||
|
||||
```typescript
|
||||
// SessionService mit Redis
|
||||
class SessionService {
|
||||
async getSession(userId: string): Promise<BotSession | null> {
|
||||
const session = await this.redis.get(`bot:session:${userId}`);
|
||||
return session ? JSON.parse(session) : null;
|
||||
}
|
||||
|
||||
async setSession(userId: string, session: BotSession): Promise<void> {
|
||||
await this.redis.set(`bot:session:${userId}`, JSON.stringify(session), 'EX', 86400);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Calendar UX Verbesserungen
|
||||
|
||||
Verbesserte User Experience für die Calendar App.
|
||||
|
||||
### Änderungen
|
||||
|
||||
| Änderung | Beschreibung |
|
||||
| ------------------- | --------------------------- |
|
||||
| **Tasks versteckt** | Standardmäßig ausgeblendet |
|
||||
| **Auto-Scroll** | Scrollt zu 12:00 beim Laden |
|
||||
| **PillNavigation** | Sidebar Mode entfernt |
|
||||
|
||||
### Auto-Scroll
|
||||
|
||||
```typescript
|
||||
onMount(() => {
|
||||
// Scroll to midday (12:00)
|
||||
const hourElement = document.querySelector('[data-hour="12"]');
|
||||
hourElement?.scrollIntoView({ block: 'center' });
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Matrix User Auto-Link
|
||||
|
||||
Automatische Verknüpfung von ManaCore-Accounts mit Matrix-Users bei OIDC Login.
|
||||
|
||||
### Flow
|
||||
|
||||
```
|
||||
1. User loggt sich via OIDC in Matrix ein
|
||||
2. mana-core-auth erhält OIDC Callback
|
||||
3. Matrix User ID wird mit ManaCore Account verknüpft
|
||||
4. Alle Bots erkennen den User automatisch
|
||||
```
|
||||
|
||||
### Database Schema
|
||||
|
||||
```sql
|
||||
ALTER TABLE users ADD COLUMN matrix_user_id TEXT;
|
||||
|
||||
-- Index für schnelle Lookups
|
||||
CREATE INDEX idx_users_matrix_user_id ON users(matrix_user_id);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bugfixes
|
||||
|
||||
| Fix | Beschreibung |
|
||||
| ----------------------- | ----------------------------- |
|
||||
| **mana-llm SSE** | Double data prefix |
|
||||
| **contacts-web** | Runtime URLs statt Build-time |
|
||||
| **shared-ui** | calculateFadeOpacity Export |
|
||||
| **nutriphi Dockerfile** | Fehlende shared packages |
|
||||
| **SessionService** | Async Methods |
|
||||
| **JWT Issuer** | Aligned mit Better Auth |
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| -------------------- | ------- | -------------------- |
|
||||
| **Cross-Domain SSO** | 5 | 14 Apps mit SSO |
|
||||
| **mana-media** | 4 | NutriPhi Integration |
|
||||
| **Matrix Bots Page** | 2 | 19 Bots Übersicht |
|
||||
| **mana-llm** | 2 | Production + SSE Fix |
|
||||
| **i18n Bots** | 2 | DE/EN Support |
|
||||
| **Cross-Bot SSO** | 3 | Redis Sessions |
|
||||
| **Calendar UX** | 3 | Tasks, Auto-Scroll |
|
||||
| **Auth Fixes** | 8 | JWT, Sessions, OIDC |
|
||||
| **Bugfixes** | 11 | Docker, UI, Types |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Photos App** mit mana-media Integration
|
||||
2. **Admin Dashboard** für User-Übersicht
|
||||
3. **STT/TTS APIs** extern verfügbar machen
|
||||
4. **Matrix E2EE** aktivieren
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
---
|
||||
title: 'Photos App, STT/TTS API Keys & Admin Dashboard'
|
||||
description: 'Neue Photos App mit mana-media EXIF-Integration, API Key Authentication für STT/TTS Services, Admin User Data Dashboard für Cross-Project Visualisierung, und vLLM Voxtral Integration'
|
||||
date: 2026-02-11
|
||||
author: 'Till Schneider'
|
||||
category: 'feature'
|
||||
tags:
|
||||
[
|
||||
'photos',
|
||||
'mana-media',
|
||||
'exif',
|
||||
'stt',
|
||||
'tts',
|
||||
'api-keys',
|
||||
'admin',
|
||||
'dashboard',
|
||||
'vllm',
|
||||
'voxtral',
|
||||
'docker',
|
||||
]
|
||||
featured: true
|
||||
commits: 28
|
||||
readTime: 14
|
||||
---
|
||||
|
||||
Nach einer Woche Pause: **28 Commits** mit Fokus auf neue Apps und API-Infrastruktur:
|
||||
|
||||
- **Photos App** - Neue App mit mana-media EXIF-Integration
|
||||
- **STT/TTS API Keys** - API Key Authentication mit Rate Limiting
|
||||
- **Admin Dashboard** - Cross-Project User Data Visualisierung
|
||||
- **vLLM Integration** - Voxtral Transcription für mana-stt
|
||||
- **External APIs** - STT und TTS extern verfügbar
|
||||
|
||||
---
|
||||
|
||||
## Photos App
|
||||
|
||||
Neue ManaCore App für Foto-Management mit automatischer EXIF-Extraktion.
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Photos App Architecture │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌────────────┐ │
|
||||
│ │ Photos Web │────>│ Photos Backend │────>│ mana-media │ │
|
||||
│ │ (SvelteKit) │ │ (NestJS) │ │ (EXIF) │ │
|
||||
│ │ Port 5196 │ │ Port 3026 │ │ │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └────────────┘ │
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌─────────────┐ ┌────────────┐ │
|
||||
│ │ PostgreSQL │ │ MinIO │ │
|
||||
│ │ (Metadata) │ │ (Files) │ │
|
||||
│ └─────────────┘ └────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Features
|
||||
|
||||
| Feature | Beschreibung |
|
||||
| --------------------- | --------------------------------- |
|
||||
| **EXIF Extraction** | Kamera, Datum, GPS, Einstellungen |
|
||||
| **Auto-Organization** | Sortierung nach Datum/Ort |
|
||||
| **Thumbnails** | Automatische Generierung |
|
||||
| **Albums** | Manuelle Organisation |
|
||||
| **Timeline View** | Chronologische Ansicht |
|
||||
|
||||
### mana-media Integration
|
||||
|
||||
```typescript
|
||||
// EXIF-Daten werden automatisch extrahiert
|
||||
interface PhotoMetadata {
|
||||
camera: string;
|
||||
lens: string;
|
||||
focalLength: string;
|
||||
aperture: string;
|
||||
shutterSpeed: string;
|
||||
iso: number;
|
||||
dateTaken: Date;
|
||||
gps?: {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Docker Deployment
|
||||
|
||||
```yaml
|
||||
photos-backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: apps/photos/apps/backend/Dockerfile
|
||||
ports:
|
||||
- '3026:3026'
|
||||
depends_on:
|
||||
- mana-media
|
||||
|
||||
photos-web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: apps/photos/apps/web/Dockerfile
|
||||
ports:
|
||||
- '5196:5196'
|
||||
```
|
||||
|
||||
### Cloudflare Tunnel
|
||||
|
||||
Neue Routes für Photos App:
|
||||
|
||||
- `photos.mana.how` → Photos Web (5196)
|
||||
- `photos-api.mana.how` → Photos Backend (3026)
|
||||
|
||||
---
|
||||
|
||||
## STT/TTS API Key Authentication
|
||||
|
||||
Neue API Key Authentifizierung für Speech Services.
|
||||
|
||||
### API Key Management
|
||||
|
||||
In mana-core-auth wurde ein API Key Management System hinzugefügt:
|
||||
|
||||
```typescript
|
||||
// Auth API: API Key erstellen
|
||||
POST /api/v1/api-keys
|
||||
{
|
||||
"name": "My STT App",
|
||||
"services": ["stt", "tts"],
|
||||
"rateLimit": 100 // requests per minute
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"apiKey": "mana_sk_xxx...",
|
||||
"name": "My STT App",
|
||||
"services": ["stt", "tts"],
|
||||
"rateLimit": 100,
|
||||
"createdAt": "2026-02-11T14:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
```typescript
|
||||
// Per-Key Rate Limiting
|
||||
interface RateLimitConfig {
|
||||
windowMs: 60000; // 1 Minute
|
||||
max: number; // Aus API Key Config
|
||||
}
|
||||
|
||||
// Redis-basiertes Tracking
|
||||
const key = `rate:${apiKey}:${currentMinute}`;
|
||||
await redis.incr(key);
|
||||
await redis.expire(key, 60);
|
||||
```
|
||||
|
||||
### Service Integration
|
||||
|
||||
```bash
|
||||
# STT mit API Key
|
||||
curl -X POST https://stt.mana.how/api/v1/transcribe \
|
||||
-H "Authorization: Bearer mana_sk_xxx" \
|
||||
-F "audio=@recording.mp3"
|
||||
|
||||
# TTS mit API Key
|
||||
curl -X POST https://tts.mana.how/api/v1/synthesize \
|
||||
-H "Authorization: Bearer mana_sk_xxx" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text": "Hallo Welt", "voice": "de-DE-FlorianNeural"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Admin User Data Dashboard
|
||||
|
||||
Neues Admin Dashboard für Cross-Project User Data Visualisierung.
|
||||
|
||||
### Features
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Admin Dashboard - User Data │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ User: till@mana.how │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐│
|
||||
│ │ Calendar: 47 Events, 12 Calendars ││
|
||||
│ │ Last activity: 2 hours ago ││
|
||||
│ └─────────────────────────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐│
|
||||
│ │ Todo: 156 Tasks (23 completed today) ││
|
||||
│ │ Active projects: 8 ││
|
||||
│ └─────────────────────────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐│
|
||||
│ │ Contacts: 234 Contacts, 15 Groups ││
|
||||
│ │ Recent additions: 3 this week ││
|
||||
│ └─────────────────────────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ... (weitere Apps) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
```typescript
|
||||
// GET /api/v1/admin/users/:userId/data
|
||||
{
|
||||
"calendar": {
|
||||
"events": 47,
|
||||
"calendars": 12,
|
||||
"lastActivity": "2026-02-11T12:30:00Z"
|
||||
},
|
||||
"todo": {
|
||||
"tasks": 156,
|
||||
"completed": 89,
|
||||
"projects": 8
|
||||
},
|
||||
"contacts": {
|
||||
"total": 234,
|
||||
"groups": 15
|
||||
},
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Database Fix
|
||||
|
||||
```typescript
|
||||
// Vorher: NodePgDatabase
|
||||
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||
|
||||
// Nachher: PostgresJsDatabase
|
||||
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## vLLM Integration für mana-stt
|
||||
|
||||
Integration von vLLM für Voxtral Transcription.
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ mana-stt Architecture │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────┐ │
|
||||
│ │ Audio Input │ │
|
||||
│ │ (MP3/WAV) │ │
|
||||
│ └────────┬────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ Whisper Model │────>│ vLLM │ │
|
||||
│ │ (ASR) │ │ (Voxtral) │ │
|
||||
│ └─────────────────┘ └─────────────────┘ │
|
||||
│ │ │ │
|
||||
│ │ │ Post-Processing │
|
||||
│ │ │ (Punctuation, Formatting) │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌───────────────────────────────────────────────────────────┐ │
|
||||
│ │ Final Transcript │ │
|
||||
│ └───────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### vLLM Configuration
|
||||
|
||||
```python
|
||||
# CPU Mode Configuration
|
||||
vllm_config = {
|
||||
"model": "mistralai/Voxtral-Mini-3B-2025",
|
||||
"dtype": "float32", # CPU Mode
|
||||
"device": "cpu",
|
||||
"max_model_len": 4096,
|
||||
}
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
```bash
|
||||
# Transcription mit Voxtral Post-Processing
|
||||
curl -X POST https://stt.mana.how/api/v1/transcribe \
|
||||
-H "Authorization: Bearer $API_KEY" \
|
||||
-F "audio=@recording.mp3" \
|
||||
-F "enhance=true" # Voxtral Enhancement aktivieren
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## External STT/TTS APIs
|
||||
|
||||
Speech Services sind jetzt extern verfügbar.
|
||||
|
||||
### Cloudflare Tunnel Routes
|
||||
|
||||
| Service | URL | Port |
|
||||
| ------- | ------------ | ---- |
|
||||
| STT API | stt.mana.how | 3020 |
|
||||
| TTS API | tts.mana.how | 3022 |
|
||||
|
||||
### Port Fix
|
||||
|
||||
TTS API Port korrigiert:
|
||||
|
||||
```yaml
|
||||
# Vorher
|
||||
tts-api:
|
||||
ports:
|
||||
- "3020:3020" # Falsch
|
||||
|
||||
# Nachher
|
||||
tts-api:
|
||||
ports:
|
||||
- "3022:3022" # Korrekt
|
||||
```
|
||||
|
||||
### LaunchD Configuration
|
||||
|
||||
```bash
|
||||
# STT/TTS Services laden .env automatisch
|
||||
launchctl setenv STT_API_KEY $(cat /etc/mana/stt.env | grep API_KEY | cut -d= -f2)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Docker Improvements
|
||||
|
||||
Zahlreiche Docker-Verbesserungen für alle Services.
|
||||
|
||||
### Backend Dockerfiles
|
||||
|
||||
`--ignore-scripts` zu allen Backend Dockerfiles hinzugefügt:
|
||||
|
||||
```dockerfile
|
||||
# Verhindert postinstall-Fehler
|
||||
RUN pnpm install --frozen-lockfile --ignore-scripts
|
||||
```
|
||||
|
||||
### Shared Packages in Dockerfiles
|
||||
|
||||
Fehlende Shared Packages zu allen Dockerfiles hinzugefügt:
|
||||
|
||||
```dockerfile
|
||||
# Vorher
|
||||
COPY packages/shared-utils ./packages/shared-utils
|
||||
|
||||
# Nachher
|
||||
COPY packages/shared-utils ./packages/shared-utils
|
||||
COPY packages/shared-stores ./packages/shared-stores
|
||||
COPY packages/shared-types ./packages/shared-types
|
||||
COPY packages/shared-vite-config ./packages/shared-vite-config
|
||||
```
|
||||
|
||||
### Local Builds
|
||||
|
||||
Einige Services werden jetzt lokal auf dem Mac Mini gebaut statt GHCR Images:
|
||||
|
||||
```yaml
|
||||
# Mac Mini: Local Build
|
||||
mana-auth:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: services/mana-core-auth/Dockerfile
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bugfixes
|
||||
|
||||
| Fix | Beschreibung |
|
||||
| ---------------------- | --------------------------------------- |
|
||||
| **admin DB type** | PostgresJsDatabase statt NodePgDatabase |
|
||||
| **photos Svelte 5** | Valide Event Syntax |
|
||||
| **mana-media paths** | Korrekter Pfad zu main.js |
|
||||
| **storage-web Docker** | Alle shared packages |
|
||||
| **todo click targets** | Verbesserte Klickflächen |
|
||||
| **matrix type safety** | Strict null checks |
|
||||
| **ARM64 CI** | Deaktiviert für storage-backend |
|
||||
|
||||
---
|
||||
|
||||
## Dokumentation
|
||||
|
||||
### mana-stt Architecture
|
||||
|
||||
Neue Dokumentation unter `services/mana-stt/ARCHITECTURE.md`:
|
||||
|
||||
- Whisper Model Details
|
||||
- vLLM Integration
|
||||
- API Endpoints
|
||||
- Performance Benchmarks
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| -------------------- | ------- | ----------------------------- |
|
||||
| **Photos App** | 8 | EXIF, Docker, Cloudflare |
|
||||
| **STT/TTS API Keys** | 3 | Rate Limiting, Auth |
|
||||
| **Admin Dashboard** | 2 | Cross-Project Data |
|
||||
| **vLLM Integration** | 2 | Voxtral, CPU Mode |
|
||||
| **External APIs** | 2 | STT/TTS Tunnel |
|
||||
| **Docker Fixes** | 8 | Shared Packages, Local Builds |
|
||||
| **Bugfixes** | 3 | Types, Paths, UI |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Photos App** Production Deployment
|
||||
2. **Admin Dashboard** erweitern (GDPR Export)
|
||||
3. **vLLM GPU Mode** aktivieren
|
||||
4. **API Key Dashboard** in mana.how
|
||||
|
|
@ -53,6 +53,15 @@
|
|||
}
|
||||
});
|
||||
|
||||
// Auto-focus input when room changes or component mounts
|
||||
$effect(() => {
|
||||
const roomId = matrixStore.currentRoomId;
|
||||
if (roomId && textarea) {
|
||||
// Small delay to ensure DOM is ready
|
||||
setTimeout(() => textarea?.focus(), 50);
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSend() {
|
||||
const trimmed = message.trim();
|
||||
if (!trimmed) return;
|
||||
|
|
@ -416,13 +425,17 @@
|
|||
<div
|
||||
class="mb-2 rounded-xl bg-white dark:bg-zinc-800 border border-black/10 dark:border-white/10 shadow-xl overflow-hidden"
|
||||
>
|
||||
<div class="px-3 py-1.5 text-xs text-muted-foreground border-b border-black/5 dark:border-white/5">
|
||||
<div
|
||||
class="px-3 py-1.5 text-xs text-muted-foreground border-b border-black/5 dark:border-white/5"
|
||||
>
|
||||
Erwähne jemanden
|
||||
</div>
|
||||
{#each mentionResults as member, i}
|
||||
<button
|
||||
class="flex items-center gap-3 w-full px-3 py-2 transition-colors text-left
|
||||
{i === selectedMentionIndex ? 'bg-violet-500/10 dark:bg-violet-500/20' : 'hover:bg-black/5 dark:hover:bg-white/5'}"
|
||||
{i === selectedMentionIndex
|
||||
? 'bg-violet-500/10 dark:bg-violet-500/20'
|
||||
: 'hover:bg-black/5 dark:hover:bg-white/5'}"
|
||||
onclick={() => insertMention(member)}
|
||||
>
|
||||
<!-- Avatar -->
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
let prevMessageCount = $state(0);
|
||||
let hasInitiallyScrolled = $state(false);
|
||||
let currentRoomId = $state<string | null>(null);
|
||||
// Track if user manually scrolled up (to read history)
|
||||
let userScrolledUp = $state(false);
|
||||
|
||||
// Reset state when room changes
|
||||
$effect(() => {
|
||||
|
|
@ -32,6 +34,7 @@
|
|||
prevMessageCount = 0;
|
||||
loadingMore = false;
|
||||
showScrollButton = false;
|
||||
userScrolledUp = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -51,15 +54,16 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Auto-scroll on new messages (if already at bottom)
|
||||
// Auto-scroll on new messages (only if user hasn't manually scrolled up)
|
||||
if (messageCount > prevMessageCount && container && hasInitiallyScrolled) {
|
||||
const isAtBottom =
|
||||
container.scrollHeight - container.scrollTop - container.clientHeight < 100;
|
||||
if (isAtBottom) {
|
||||
if (!userScrolledUp) {
|
||||
// Use double tick to ensure DOM has rendered the new message
|
||||
tick().then(() => {
|
||||
if (container) {
|
||||
container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
tick().then(() => {
|
||||
if (container) {
|
||||
container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -69,9 +73,19 @@
|
|||
function handleScroll() {
|
||||
if (!container) return;
|
||||
|
||||
// Show scroll button if not at bottom
|
||||
// Calculate distance from bottom
|
||||
const distanceFromBottom =
|
||||
container.scrollHeight - container.scrollTop - container.clientHeight;
|
||||
|
||||
// Track if user manually scrolled up (more than 150px from bottom)
|
||||
// Reset when they scroll back to bottom (within 50px)
|
||||
if (distanceFromBottom > 150) {
|
||||
userScrolledUp = true;
|
||||
} else if (distanceFromBottom < 50) {
|
||||
userScrolledUp = false;
|
||||
}
|
||||
|
||||
// Show scroll button if not at bottom
|
||||
showScrollButton = distanceFromBottom > 200;
|
||||
|
||||
// Load more when scrolled to top (only after initial scroll and with messages present)
|
||||
|
|
@ -104,6 +118,7 @@
|
|||
}
|
||||
|
||||
function scrollToBottom() {
|
||||
userScrolledUp = false;
|
||||
container?.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import { UserDataResponse, DeleteUserDataResponse } from './dto/user-data-respon
|
|||
* Used by mana-core-auth aggregation service
|
||||
* Protected by X-Service-Key authentication
|
||||
*/
|
||||
@Controller('admin')
|
||||
@Controller('api/v1/admin')
|
||||
@UseGuards(ServiceAuthGuard)
|
||||
export class AdminController {
|
||||
private readonly logger = new Logger(AdminController.name);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue