mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 21:21:10 +02:00
docs(devlog): add 9 missing devlogs from Feb 16 to Mar 18
Covers all working days with commits since the last devlog (Feb 15): - 2026-02-16: LightWrite launch, PWA rollout, Stripe SEPA - 2026-02-17: spiral-db, Planta bot, Mana Values manifest - 2026-03-06: Manalink mobile Matrix client - 2026-03-07: Manalink Expo SDK 55 fixes - 2026-03-11: CD pipeline with Mac Mini self-hosted runner - 2026-03-12: Manalink EAS Build fixes - 2026-03-15: Traces app, Calendar production hardening - 2026-03-17: Mukke mobile, E2E tests, pre-commit hook - 2026-03-18: Unit test coverage for contacts and todo Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8c9d01a1f6
commit
83d0b64119
9 changed files with 2105 additions and 0 deletions
|
|
@ -0,0 +1,259 @@
|
|||
---
|
||||
title: 'LightWrite Launch, PWA für alle Apps & Stripe SEPA'
|
||||
description: 'LightWrite Beat/Lyrics Editor als neue App, PWA Dependencies für alle 18 Web-Apps, Stripe SEPA Direct Debit, vereinfachtes Credit-System und Matrix Widget Support.'
|
||||
date: 2026-02-16
|
||||
author: 'Till Schneider'
|
||||
category: 'feature'
|
||||
tags:
|
||||
[
|
||||
'lightwrite',
|
||||
'pwa',
|
||||
'stripe',
|
||||
'sepa',
|
||||
'subscriptions',
|
||||
'credits',
|
||||
'matrix',
|
||||
'calendar',
|
||||
'onboarding',
|
||||
]
|
||||
featured: false
|
||||
commits: 35
|
||||
readTime: 12
|
||||
stats:
|
||||
filesChanged: 700
|
||||
linesAdded: 14200
|
||||
linesRemoved: 3800
|
||||
contributors:
|
||||
- name: 'Till Schneider'
|
||||
handle: 'Till-JS'
|
||||
commits: 35
|
||||
workingHours:
|
||||
start: '2026-02-16T11:00'
|
||||
end: '2026-02-17T11:00'
|
||||
---
|
||||
|
||||
Massiver Tag mit **35 Commits** – neuer App-Launch, Monetarisierung und PWA-Rollout:
|
||||
|
||||
- **LightWrite** - Beat/Lyrics Editor als Full-Stack App gelauncht
|
||||
- **PWA** - Progressive Web App Dependencies für alle 18 Web-Apps
|
||||
- **Stripe SEPA** - Direct Debit als Zahlungsoption
|
||||
- **Subscriptions** - Unified ManaCore Subscription Plans
|
||||
- **Credits** - System vereinfacht (Free Credits & B2B entfernt)
|
||||
- **Matrix** - Widget Support und Room Settings Styling
|
||||
|
||||
---
|
||||
|
||||
## LightWrite Beat/Lyrics Editor
|
||||
|
||||
Komplett neue App für Musikproduktion – Beat-Making und Lyrics-Editing in einem Tool.
|
||||
|
||||
### Stack
|
||||
|
||||
| Layer | Technologie | Details |
|
||||
| ----------- | ----------- | -------------------------- |
|
||||
| **Backend** | NestJS | REST API, Audio Processing |
|
||||
| **Web** | SvelteKit | Svelte 5 Runes, Tailwind |
|
||||
| **Landing** | Astro | Marketing Page |
|
||||
| **Infra** | Docker | Dockerfile, Subdomains |
|
||||
|
||||
### Features
|
||||
|
||||
- Beat Editor mit Timeline und Track-Layering
|
||||
- Lyrics Editor mit Synchronisation
|
||||
- STT Lyrics Transcription Integration
|
||||
- CORS-Konfiguration für Cross-Origin Audio
|
||||
|
||||
### Infrastructure
|
||||
|
||||
```yaml
|
||||
# docker-compose - LightWrite Services
|
||||
lightwrite-backend:
|
||||
build: ./apps/lightwrite/apps/backend
|
||||
ports:
|
||||
- '3012:3012'
|
||||
|
||||
lightwrite-web:
|
||||
build: ./apps/lightwrite/apps/web
|
||||
ports:
|
||||
- '5190:5190'
|
||||
```
|
||||
|
||||
### Subdomain Setup
|
||||
|
||||
```nginx
|
||||
# lightwrite.mana.how → Web App
|
||||
# api.lightwrite.mana.how → Backend API
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PWA für alle 18 Web-Apps
|
||||
|
||||
Progressive Web App Dependencies wurden zu allen SvelteKit Web-Apps hinzugefügt.
|
||||
|
||||
### Betroffene Apps
|
||||
|
||||
| App | PWA Status |
|
||||
| ---------- | ------------ |
|
||||
| ManaCore | ✅ Aktiviert |
|
||||
| Chat | ✅ Aktiviert |
|
||||
| Picture | ✅ Aktiviert |
|
||||
| Zitare | ✅ Aktiviert |
|
||||
| Calendar | ✅ Aktiviert |
|
||||
| Contacts | ✅ Aktiviert |
|
||||
| Todo | ✅ Aktiviert |
|
||||
| Clock | ✅ Aktiviert |
|
||||
| LightWrite | ✅ Aktiviert |
|
||||
| ManaDeck | ✅ Aktiviert |
|
||||
| Photos | ✅ Aktiviert |
|
||||
| NutriPhi | ✅ Aktiviert |
|
||||
| Mukke | ✅ Aktiviert |
|
||||
| Reader | ✅ Aktiviert |
|
||||
| Inventory | ✅ Aktiviert |
|
||||
| Storage | ✅ Aktiviert |
|
||||
| Traces | ✅ Aktiviert |
|
||||
| Context | ✅ Aktiviert |
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# PWA Dependencies für SvelteKit
|
||||
pnpm add @vite-pwa/sveltekit workbox-window -D
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stripe SEPA Direct Debit
|
||||
|
||||
Neue Zahlungsoption für europäische Kunden.
|
||||
|
||||
### Payment Methods
|
||||
|
||||
| Methode | Region | Status |
|
||||
| -------------------- | ------ | ------------ |
|
||||
| **Kreditkarte** | Global | ✅ Bestehend |
|
||||
| **SEPA Lastschrift** | EU/EWR | ✅ Neu |
|
||||
|
||||
### Implementation
|
||||
|
||||
```typescript
|
||||
// services/mana-core-auth/src/stripe/stripe.service.ts
|
||||
async createSEPASubscription(customerId: string, planId: string) {
|
||||
return this.stripe.subscriptions.create({
|
||||
customer: customerId,
|
||||
items: [{ price: planId }],
|
||||
payment_settings: {
|
||||
payment_method_types: ['sepa_debit', 'card'],
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Unified Subscription Plans
|
||||
|
||||
ManaCore Subscription Plans als zentrale Verwaltung für alle Apps.
|
||||
|
||||
### Plan-Struktur
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ ManaCore Subscription Plans │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Free ████ Basis-Features, keine Credits │
|
||||
│ Starter ████ 100 Credits/Monat │
|
||||
│ Pro ████ 500 Credits/Monat │
|
||||
│ Business ████ 2000 Credits/Monat │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Credit-System Vereinfachung
|
||||
|
||||
Das Credit-System wurde gestrafft – Free Credits und B2B-Logik entfernt.
|
||||
|
||||
### Vorher vs. Nachher
|
||||
|
||||
| Aspekt | Vorher | Nachher |
|
||||
| ------------ | ----------------- | -------- |
|
||||
| Free Credits | 50/Monat | Entfernt |
|
||||
| B2B Credits | Eigene Verwaltung | Entfernt |
|
||||
| Logik | Komplex | Einfach |
|
||||
| Code-Pfade | 6 | 2 |
|
||||
|
||||
---
|
||||
|
||||
## Organization Management
|
||||
|
||||
Neue Endpoints in mana-core-auth für Organisation-Verwaltung.
|
||||
|
||||
### Endpoints
|
||||
|
||||
```
|
||||
POST /api/v1/organizations # Erstellen
|
||||
GET /api/v1/organizations # Alle auflisten
|
||||
GET /api/v1/organizations/:id # Details
|
||||
PUT /api/v1/organizations/:id # Aktualisieren
|
||||
DELETE /api/v1/organizations/:id # Löschen
|
||||
POST /api/v1/organizations/:id/members # Mitglied hinzufügen
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Matrix Widget Support
|
||||
|
||||
Matrix Room Settings mit Widget-Verwaltung und verbessertem Styling.
|
||||
|
||||
### Features
|
||||
|
||||
- Widget einbetten in Matrix Rooms
|
||||
- Room Settings UI überarbeitet
|
||||
- Konsistentes Styling mit ManaCore Design System
|
||||
|
||||
---
|
||||
|
||||
## App-Spezifisches Mini-Onboarding
|
||||
|
||||
Jede App kann jetzt einen eigenen Onboarding-Flow definieren.
|
||||
|
||||
### Konzept
|
||||
|
||||
```typescript
|
||||
// Onboarding Config pro App
|
||||
const onboardingSteps = {
|
||||
lightwrite: [
|
||||
{ title: 'Beats erstellen', component: BeatIntro },
|
||||
{ title: 'Lyrics schreiben', component: LyricsIntro },
|
||||
],
|
||||
calendar: [{ title: 'Kalender verbinden', component: CalendarSync }],
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| ----------------- | ------- | -------------------------------- |
|
||||
| **LightWrite** | 10 | Full-Stack App Launch |
|
||||
| **PWA** | 5 | 18 Web-Apps mit PWA Support |
|
||||
| **Stripe/SEPA** | 4 | SEPA Direct Debit Integration |
|
||||
| **Subscriptions** | 4 | Unified Plans |
|
||||
| **Credits** | 3 | Vereinfachung |
|
||||
| **Organizations** | 3 | Auth Endpoints |
|
||||
| **Matrix** | 3 | Widgets & Room Settings |
|
||||
| **Calendar** | 1 | ViewsBar Komponente |
|
||||
| **Onboarding** | 2 | App-spezifisches Mini-Onboarding |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **LightWrite** - Audio-Export und Sharing-Features
|
||||
2. **PWA** - Offline-Support und Push Notifications
|
||||
3. **Subscriptions** - Upgrade/Downgrade Flow im UI
|
||||
4. **Matrix Widgets** - Weitere Widget-Typen
|
||||
|
|
@ -0,0 +1,301 @@
|
|||
---
|
||||
title: 'spiral-db, Planta Bot & Mana Values'
|
||||
description: 'spiral-db Pixel-Visualisierung, Planta Bot für Pflanzenidentifikation, NutriPhi Bot Verbesserungen, Mana Values Manifest und diverse Docker-Fixes.'
|
||||
date: 2026-02-17
|
||||
author: 'Till Schneider'
|
||||
category: 'feature'
|
||||
tags: ['spiral-db', 'planta', 'nutriphi', 'todo', 'mana-bot', 'wallpaper', 'documentation']
|
||||
featured: false
|
||||
commits: 26
|
||||
readTime: 10
|
||||
stats:
|
||||
filesChanged: 520
|
||||
linesAdded: 10400
|
||||
linesRemoved: 2800
|
||||
contributors:
|
||||
- name: 'Till Schneider'
|
||||
handle: 'Till-JS'
|
||||
commits: 26
|
||||
workingHours:
|
||||
start: '2026-02-17T11:00'
|
||||
end: '2026-02-18T11:00'
|
||||
---
|
||||
|
||||
Produktiver Tag mit **26 Commits** – neue Packages, Bot-Features und Dokumentation:
|
||||
|
||||
- **spiral-db** - Pixel-basierte Spiral-Datenbank-Visualisierung
|
||||
- **Planta Bot** - KI-Pflanzenidentifikation per Bild-Upload
|
||||
- **NutriPhi Bot** - Smartes Meal Feedback
|
||||
- **Mana Bot** - Tägliche Morgenzusammenfassung
|
||||
- **Mana Values** - Manifest-Dokumentation
|
||||
- **Wallpaper Generator** - Neues Package
|
||||
|
||||
---
|
||||
|
||||
## spiral-db Package
|
||||
|
||||
Neues Package für pixel-basierte Spiral-Datenbank-Visualisierung – Daten werden in einer Spiralform dargestellt.
|
||||
|
||||
### Konzept
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ spiral-db Visualisierung │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ██ ██ ██ ██ │
|
||||
│ ██ ██ │
|
||||
│ ██ ██ ██ ██ │
|
||||
│ ██ ██ ██ ██ │
|
||||
│ ██ ██ ● ██ ██ │
|
||||
│ ██ ██ ██ ██ │
|
||||
│ ██ ██ ██ ██ │
|
||||
│ ██ ██ │
|
||||
│ ██ ██ ██ ██ │
|
||||
│ │
|
||||
│ Jeder Pixel = ein Datenpunkt │
|
||||
│ Spirale = zeitlicher Verlauf │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
```typescript
|
||||
import { SpiralDB } from '@manacore/spiral-db';
|
||||
|
||||
const spiral = new SpiralDB({
|
||||
width: 512,
|
||||
height: 512,
|
||||
pixelSize: 4,
|
||||
});
|
||||
|
||||
// Daten hinzufügen
|
||||
spiral.add({ timestamp: Date.now(), value: 42 });
|
||||
|
||||
// Als PNG exportieren
|
||||
const png = spiral.toPNG();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Todo App: spiral-db Integration
|
||||
|
||||
Die Todo-App nutzt spiral-db zur Visualisierung erledigter Aufgaben.
|
||||
|
||||
### Features
|
||||
|
||||
| Feature | Beschreibung |
|
||||
| ------------------ | ------------------------------------- |
|
||||
| **Spiral View** | Erledigte Tasks als Spiral-Pixel |
|
||||
| **PNG Import** | Bestehende Spiralen importieren |
|
||||
| **Farbkodierung** | Prioritäten als Pixel-Farben |
|
||||
| **Export** | Spiral als Bild exportieren |
|
||||
|
||||
---
|
||||
|
||||
## Planta Bot
|
||||
|
||||
KI-gestützte Pflanzenidentifikation per Bild-Upload – als Docker-Service deployed.
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ Matrix Chat │────>│ Planta Bot │────>│ Vision LLM │
|
||||
│ (Bild-Upload)│ │ (Docker) │ │ (mana-llm) │
|
||||
└──────────────┘ └──────────────┘ └──────────────┘
|
||||
│ │ │
|
||||
│ Bild senden │ Analyse │
|
||||
│ │ anfragen │
|
||||
│<───────────────────│ │
|
||||
│ Pflanzeninfo │<────────────────────│
|
||||
│ + Pflegetipps │ Identifikation │
|
||||
```
|
||||
|
||||
### Response Format
|
||||
|
||||
```json
|
||||
{
|
||||
"plant": "Monstera deliciosa",
|
||||
"commonName": "Fensterblatt",
|
||||
"confidence": 0.94,
|
||||
"care": {
|
||||
"water": "Mäßig, Erde antrocknen lassen",
|
||||
"light": "Helles indirektes Licht",
|
||||
"temperature": "18-27°C"
|
||||
},
|
||||
"health": "Gesund, leichte Staubablagerungen auf Blättern"
|
||||
}
|
||||
```
|
||||
|
||||
### Docker Deployment
|
||||
|
||||
```bash
|
||||
# Planta Bot starten
|
||||
docker compose -f docker-compose.macmini.yml up -d planta-bot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## NutriPhi Bot Verbesserungen
|
||||
|
||||
Smartes Meal Feedback mit positiven Aspekten und Verbesserungsvorschlägen.
|
||||
|
||||
### Vorher vs. Nachher
|
||||
|
||||
| Aspekt | Vorher | Nachher |
|
||||
| --------------- | ------------------- | --------------------------- |
|
||||
| **Feedback** | Nur Nährwerte | Positiv + Verbesserungen |
|
||||
| **Ton** | Neutral | Ermutigend |
|
||||
| **Vorschläge** | Keine | Konkrete Alternativen |
|
||||
| **Format** | Tabelle | Strukturierter Text |
|
||||
|
||||
### Beispiel-Feedback
|
||||
|
||||
```
|
||||
✅ Positiv:
|
||||
- Gute Proteinquelle durch Hühnchen
|
||||
- Gemüseanteil liefert Vitamine A und C
|
||||
|
||||
💡 Verbesserungen:
|
||||
- Vollkornreis statt weißem Reis für mehr Ballaststoffe
|
||||
- Olivenöl statt Butter zum Anbraten
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mana Bot: Morning Summary
|
||||
|
||||
Tägliche Morgenzusammenfassung mit den wichtigsten Infos für den Tag.
|
||||
|
||||
### Inhalt
|
||||
|
||||
| Bereich | Datenquelle |
|
||||
| --------------- | ---------------- |
|
||||
| **Kalender** | Calendar API |
|
||||
| **Todos** | Todo API |
|
||||
| **Wetter** | Weather Service |
|
||||
| **Nachrichten** | News Aggregation |
|
||||
|
||||
### Beispiel
|
||||
|
||||
```
|
||||
☀️ Guten Morgen, Till!
|
||||
|
||||
📅 Heute: 3 Termine
|
||||
09:00 - Daily Standup
|
||||
14:00 - Design Review
|
||||
16:30 - Zahnarzt
|
||||
|
||||
✅ Offene Todos: 5
|
||||
🔴 2 Priorität Hoch
|
||||
🟡 3 Priorität Mittel
|
||||
|
||||
🌤️ Berlin: 12°C, teilweise bewölkt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ManaCore: QR Code Export
|
||||
|
||||
Neue QR-Code-Export-Funktion auf der My-Data Seite.
|
||||
|
||||
### Implementation
|
||||
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
import { QRCode } from '$lib/components/QRCode.svelte';
|
||||
|
||||
let userData = $state({
|
||||
name: 'Till Schneider',
|
||||
email: 'till@mana.how',
|
||||
profileUrl: 'https://mana.how/u/till',
|
||||
});
|
||||
</script>
|
||||
|
||||
<QRCode data={userData.profileUrl} size={256} />
|
||||
<button onclick={() => downloadQR()}>QR Code herunterladen</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Wallpaper Generator Package
|
||||
|
||||
Neues Package zur programmatischen Generierung von Wallpapers.
|
||||
|
||||
### Features
|
||||
|
||||
- Generative Patterns (Noise, Gradients, Geometrie)
|
||||
- Konfigurierbare Auflösungen (Mobile, Desktop, 4K)
|
||||
- Export als PNG/JPEG
|
||||
|
||||
---
|
||||
|
||||
## Mana Values Manifest
|
||||
|
||||
Dokumentation der Kernwerte des ManaCore-Ökosystems.
|
||||
|
||||
### Werte
|
||||
|
||||
| Wert | Beschreibung |
|
||||
| ----------------- | --------------------------------------- |
|
||||
| **Privacy First** | Daten gehören dem Nutzer |
|
||||
| **Open Source** | Transparenz durch offenen Code |
|
||||
| **Self-Hosted** | Volle Kontrolle über eigene Instanz |
|
||||
| **Offline-First** | Apps funktionieren ohne Internet |
|
||||
| **Interop** | Standards statt Lock-in (Matrix, CalDAV)|
|
||||
|
||||
---
|
||||
|
||||
## PillNavigation Vereinfachung
|
||||
|
||||
Sidebar-Mode aus der PillNavigation entfernt – nur noch Bottom-Navigation.
|
||||
|
||||
### Vorher
|
||||
|
||||
```
|
||||
┌────────────┬────────────────────────┐
|
||||
│ Sidebar │ │
|
||||
│ ████ │ Content │
|
||||
│ ████ │ │
|
||||
│ ████ │ │
|
||||
└────────────┴────────────────────────┘
|
||||
```
|
||||
|
||||
### Nachher
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ │
|
||||
│ Content │
|
||||
│ │
|
||||
├─────────────────────────────────────┤
|
||||
│ ██ ██ ██ ██ ██ │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| ------------------ | ------- | --------------------------------- |
|
||||
| **spiral-db** | 5 | Package + Todo Integration |
|
||||
| **Planta Bot** | 4 | KI-Pflanzenidentifikation |
|
||||
| **NutriPhi Bot** | 3 | Smartes Meal Feedback |
|
||||
| **Mana Bot** | 3 | Morning Summary |
|
||||
| **QR Code** | 2 | My-Data Export |
|
||||
| **Wallpaper** | 2 | Generator Package |
|
||||
| **Mana Values** | 2 | Manifest Dokumentation |
|
||||
| **PillNavigation** | 2 | Sidebar entfernt |
|
||||
| **Docker/Fixes** | 3 | Planta, ManaCore, Todo, LightWrite|
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **spiral-db** - Interaktive Web-Visualisierung
|
||||
2. **Planta Bot** - Pflanzenpflege-Erinnerungen
|
||||
3. **Mana Bot** - Abend-Summary mit Tagesrückblick
|
||||
4. **Wallpaper** - AI-generierte Wallpapers via Picture
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
---
|
||||
title: 'Manalink: Matrix Mobile Client'
|
||||
description: 'Manalink als Expo React Native Mobile Client für Matrix Chat mit Reactions, Read Receipts, Message Forwarding und EAS Build für TestFlight.'
|
||||
date: 2026-03-06
|
||||
author: 'Till Schneider'
|
||||
category: 'feature'
|
||||
tags: ['matrix', 'manalink', 'expo', 'react-native', 'mobile', 'eas-build', 'testflight']
|
||||
featured: false
|
||||
commits: 7
|
||||
readTime: 6
|
||||
stats:
|
||||
filesChanged: 140
|
||||
linesAdded: 3500
|
||||
linesRemoved: 420
|
||||
contributors:
|
||||
- name: 'Till Schneider'
|
||||
handle: 'Till-JS'
|
||||
commits: 7
|
||||
workingHours:
|
||||
start: '2026-03-06T11:00'
|
||||
end: '2026-03-07T11:00'
|
||||
---
|
||||
|
||||
Fokussierter Tag mit **7 Commits** für den neuen Matrix Mobile Client:
|
||||
|
||||
- **Manalink** - Expo React Native App für Matrix Chat
|
||||
- **Reactions** - Emoji-Reaktionen auf Nachrichten
|
||||
- **Read Receipts** - Lesebestätigungen
|
||||
- **Message Forwarding** - Nachrichten weiterleiten
|
||||
- **EAS Build** - TestFlight-Konfiguration
|
||||
|
||||
---
|
||||
|
||||
## Manalink: Matrix Mobile Client
|
||||
|
||||
Neue Expo React Native App als nativer Mobile Client für das selbstgehostete Matrix-Setup.
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Manalink (Expo React Native) │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Rooms │ │ Chat │ │ Settings │ │
|
||||
│ │ List │ │ View │ │ │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────┐ │
|
||||
│ │ matrix-js-sdk │ │
|
||||
│ │ matrix-sdk-crypto-wasm (E2EE) │ │
|
||||
│ └──────────────────────────────────────┘ │
|
||||
│ │
|
||||
└──────────────────────────┬──────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ Matrix Synapse │
|
||||
│ (matrix.mana.how) │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
### Features
|
||||
|
||||
| Feature | Status | Beschreibung |
|
||||
| ---------------------- | ------ | ---------------------------------- |
|
||||
| **Room List** | ✅ | Alle Räume mit Unread Count |
|
||||
| **Chat View** | ✅ | Nachrichten-Timeline |
|
||||
| **Reactions** | ✅ | Emoji-Reaktionen auf Nachrichten |
|
||||
| **Read Receipts** | ✅ | Lesebestätigungen senden/empfangen |
|
||||
| **Message Forwarding** | ✅ | Nachrichten an andere Räume |
|
||||
| **DM Encryption** | ✅ | E2EE Fix für Direktnachrichten |
|
||||
| **Media Upload** | ✅ | Bilder und Dateien senden |
|
||||
|
||||
### Reactions Implementation
|
||||
|
||||
```typescript
|
||||
// Emoji Reaction auf eine Nachricht
|
||||
async function sendReaction(roomId: string, eventId: string, emoji: string) {
|
||||
await matrixClient.sendEvent(roomId, 'm.reaction', {
|
||||
'm.relates_to': {
|
||||
rel_type: 'm.annotation',
|
||||
event_id: eventId,
|
||||
key: emoji,
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### DM Encryption Fix
|
||||
|
||||
Problem: Verschlüsselte DMs zeigten "Unable to decrypt" nach App-Neustart.
|
||||
|
||||
```typescript
|
||||
// Fix: Crypto Store korrekt initialisieren
|
||||
const client = createClient({
|
||||
baseUrl: homeserverUrl,
|
||||
userId: userId,
|
||||
accessToken: token,
|
||||
cryptoStore: new IndexedDBCryptoStore(indexedDB, 'manalink-crypto-store'),
|
||||
});
|
||||
|
||||
// Wichtig: initCrypto() VOR startClient()
|
||||
await client.initCrypto();
|
||||
await client.startClient();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## EAS Build für TestFlight
|
||||
|
||||
Konfiguration für iOS TestFlight Distribution via EAS Build.
|
||||
|
||||
### eas.json
|
||||
|
||||
```json
|
||||
{
|
||||
"build": {
|
||||
"development": {
|
||||
"developmentClient": true,
|
||||
"distribution": "internal"
|
||||
},
|
||||
"preview": {
|
||||
"distribution": "internal",
|
||||
"ios": {
|
||||
"simulator": false
|
||||
}
|
||||
},
|
||||
"production": {
|
||||
"autoIncrement": true,
|
||||
"ios": {
|
||||
"buildConfiguration": "Release"
|
||||
}
|
||||
}
|
||||
},
|
||||
"submit": {
|
||||
"production": {
|
||||
"ios": {
|
||||
"appleId": "till@mana.how",
|
||||
"ascAppId": "6744632877"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Root Dev Scripts
|
||||
|
||||
Neue Dev-Scripts im Root für einfaches Starten der Matrix-Apps.
|
||||
|
||||
```json
|
||||
{
|
||||
"dev:matrix:mobile": "pnpm --filter @manalink/mobile start",
|
||||
"dev:matrix:web": "pnpm --filter @matrix/web dev"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Monorepo Fix: sharp in neverBuiltDependencies
|
||||
|
||||
`sharp` wurde zu `pnpm.neverBuiltDependencies` hinzugefügt, um EAS Build Probleme zu beheben.
|
||||
|
||||
### Problem
|
||||
|
||||
EAS Build schlug fehl, weil `sharp` native Binaries auf dem Build-Server nicht kompilieren konnte.
|
||||
|
||||
### Lösung
|
||||
|
||||
```json
|
||||
// package.json (root)
|
||||
{
|
||||
"pnpm": {
|
||||
"neverBuiltDependencies": ["sharp"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| ---------------- | ------- | --------------------------------- |
|
||||
| **Manalink App** | 3 | Core App mit Room List & Chat |
|
||||
| **Features** | 2 | Reactions, Read Receipts, Forward |
|
||||
| **EAS Build** | 1 | TestFlight Konfiguration |
|
||||
| **Monorepo** | 1 | sharp Fix für EAS |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Push Notifications** - APNs Integration für iOS
|
||||
2. **Voice Messages** - Aufnahme und Abspielen
|
||||
3. **Search** - Nachrichten-Suche in Räumen
|
||||
4. **SDK 55 Upgrade** - Expo SDK Update
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
---
|
||||
title: 'Manalink SDK 55 Upgrade & Fixes'
|
||||
description: 'Manalink auf Expo SDK 55 aktualisiert, matrix-sdk-crypto-wasm Metro Blocking Fix, Reanimated 4.2 Kompatibilität und Chat Input Bar Fix.'
|
||||
date: 2026-03-07
|
||||
author: 'Till Schneider'
|
||||
category: 'bugfix'
|
||||
tags: ['matrix', 'manalink', 'expo-sdk-55', 'react-native', 'metro']
|
||||
featured: false
|
||||
commits: 5
|
||||
readTime: 4
|
||||
stats:
|
||||
filesChanged: 28
|
||||
linesAdded: 480
|
||||
linesRemoved: 310
|
||||
contributors:
|
||||
- name: 'Till Schneider'
|
||||
handle: 'Till-JS'
|
||||
commits: 5
|
||||
workingHours:
|
||||
start: '2026-03-07T11:00'
|
||||
end: '2026-03-08T11:00'
|
||||
---
|
||||
|
||||
Bugfix-Tag mit **5 Commits** – Expo SDK Upgrade und kritische Fixes:
|
||||
|
||||
- **SDK 55** - Manalink auf Expo SDK 55 aktualisiert
|
||||
- **Metro Fix** - matrix-sdk-crypto-wasm Blocking behoben
|
||||
- **Reanimated** - Worklets für 4.2 Kompatibilität
|
||||
- **Chat Input** - Eingabeleiste nicht mehr hinter PillNavigation
|
||||
|
||||
---
|
||||
|
||||
## Expo SDK 55 Upgrade
|
||||
|
||||
Manalink von Expo SDK 52 auf SDK 55 aktualisiert.
|
||||
|
||||
### Aktualisierte Dependencies
|
||||
|
||||
| Package | Vorher | Nachher |
|
||||
| ------------------------- | ------- | ------- |
|
||||
| `expo` | ~52.0.0 | ~55.0.0 |
|
||||
| `react-native` | 0.76.x | 0.79.x |
|
||||
| `expo-router` | ~4.0.0 | ~5.0.0 |
|
||||
| `react-native-reanimated` | ~3.16.0 | ~4.2.0 |
|
||||
| `@expo/metro-runtime` | ~4.0.0 | ~5.0.0 |
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- Expo Router 5: Neue Layout-API
|
||||
- Reanimated 4: Worklet-System überarbeitet
|
||||
- Metro: Strengere Module-Resolution
|
||||
|
||||
---
|
||||
|
||||
## Metro Resolver Fix: matrix-sdk-crypto-wasm
|
||||
|
||||
`matrix-sdk-crypto-wasm` blockierte den Metro Resolver beim Bundling.
|
||||
|
||||
### Problem
|
||||
|
||||
```
|
||||
error: Unable to resolve module matrix-sdk-crypto-wasm
|
||||
from node_modules/matrix-js-sdk/lib/crypto/...
|
||||
|
||||
Metro bundler hung indefinitely when encountering WASM modules
|
||||
```
|
||||
|
||||
### Ursache
|
||||
|
||||
Metro kann keine `.wasm` Module auflösen. Das `matrix-sdk-crypto-wasm` Package enthält WebAssembly-Binaries, die Metro blockieren.
|
||||
|
||||
### Lösung
|
||||
|
||||
```javascript
|
||||
// metro.config.js
|
||||
const { getDefaultConfig } = require('expo/metro-config');
|
||||
|
||||
const config = getDefaultConfig(__dirname);
|
||||
|
||||
// Block matrix-sdk-crypto-wasm from being resolved
|
||||
config.resolver.resolveRequest = (context, moduleName, platform) => {
|
||||
if (moduleName === 'matrix-sdk-crypto-wasm') {
|
||||
return {
|
||||
type: 'empty',
|
||||
};
|
||||
}
|
||||
return context.resolveRequest(context, moduleName, platform);
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## react-native-worklets für Reanimated 4.2
|
||||
|
||||
Reanimated 4.2 benötigt `react-native-worklets` als separates Package.
|
||||
|
||||
### Problem
|
||||
|
||||
```
|
||||
Error: Reanimated 4.2 requires react-native-worklets-core
|
||||
```
|
||||
|
||||
### Lösung
|
||||
|
||||
```bash
|
||||
pnpm add react-native-worklets-core --filter @manalink/mobile
|
||||
```
|
||||
|
||||
```javascript
|
||||
// babel.config.js
|
||||
module.exports = function (api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: ['babel-preset-expo'],
|
||||
plugins: [
|
||||
'react-native-worklets-core/plugin',
|
||||
'react-native-reanimated/plugin', // Muss letztes Plugin sein
|
||||
],
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## react-native-css-interop Dependency
|
||||
|
||||
Neue Dependency für NativeWind v4 Kompatibilität mit SDK 55.
|
||||
|
||||
```bash
|
||||
pnpm add react-native-css-interop --filter @manalink/mobile
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chat Input Bar Fix
|
||||
|
||||
Die Chat-Eingabeleiste wurde auf Web von der PillNavigation verdeckt.
|
||||
|
||||
### Problem
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ │
|
||||
│ Chat Messages │
|
||||
│ ... │
|
||||
│ ... │
|
||||
│ │
|
||||
├─────────────────────────────────────┤
|
||||
│ [Chat Input Bar] ← Verdeckt! │
|
||||
├─────────────────────────────────────┤
|
||||
│ ██ ██ ██ ██ ██ PillNav │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Lösung
|
||||
|
||||
```css
|
||||
/* Chat Container mit Bottom-Padding für PillNavigation */
|
||||
.chat-container {
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 64px);
|
||||
}
|
||||
```
|
||||
|
||||
### Nachher
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ │
|
||||
│ Chat Messages │
|
||||
│ ... │
|
||||
│ │
|
||||
├─────────────────────────────────────┤
|
||||
│ [Chat Input Bar] ← Sichtbar! │
|
||||
│ │
|
||||
├─────────────────────────────────────┤
|
||||
│ ██ ██ ██ ██ ██ PillNav │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| --------------- | ------- | ---------------------------- |
|
||||
| **SDK 55** | 1 | Expo + React Native Upgrade |
|
||||
| **Metro** | 1 | crypto-wasm Blocking Fix |
|
||||
| **Reanimated** | 1 | Worklets Dependency |
|
||||
| **CSS Interop** | 1 | NativeWind v4 Kompatibilität |
|
||||
| **Chat Input** | 1 | PillNavigation Overlap Fix |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Performance** - Bundle Size Optimierung
|
||||
2. **E2EE** - Native Crypto-Module statt WASM
|
||||
3. **Notifications** - Push via APNs/FCM
|
||||
4. **CI/CD** - Automatische Builds bei PR
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
---
|
||||
title: 'CD Pipeline mit Self-Hosted GitHub Actions Runner'
|
||||
description: 'Continuous Deployment Pipeline mit self-hosted GitHub Actions Runner auf dem Mac Mini, Auto-Deploy bei Push auf main und Docker-Fixes.'
|
||||
date: 2026-03-11
|
||||
author: 'Till Schneider'
|
||||
category: 'infrastructure'
|
||||
tags: ['ci-cd', 'github-actions', 'mac-mini', 'self-hosted-runner', 'docker', 'deployment']
|
||||
featured: false
|
||||
commits: 6
|
||||
readTime: 5
|
||||
stats:
|
||||
filesChanged: 42
|
||||
linesAdded: 680
|
||||
linesRemoved: 190
|
||||
contributors:
|
||||
- name: 'Till Schneider'
|
||||
handle: 'Till-JS'
|
||||
commits: 6
|
||||
workingHours:
|
||||
start: '2026-03-11T11:00'
|
||||
end: '2026-03-12T11:00'
|
||||
---
|
||||
|
||||
Infrastruktur-Tag mit **6 Commits** für die Deployment-Pipeline:
|
||||
|
||||
- **CD Pipeline** - GitHub Actions mit self-hosted Runner
|
||||
- **Auto-Deploy** - Automatisches Deployment bei Push auf main
|
||||
- **SSH Setup** - Dokumentation für Mac Mini Runner
|
||||
- **Docker Fixes** - PATH und Dockerfile-Korrekturen
|
||||
|
||||
---
|
||||
|
||||
## CD Pipeline: Self-Hosted GitHub Actions Runner
|
||||
|
||||
Continuous Deployment direkt auf dem Mac Mini Production Server via self-hosted GitHub Actions Runner.
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ GitHub Repository │
|
||||
│ Push to main │
|
||||
└──────────────────────┬───────────────────────────────┘
|
||||
│ Webhook
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ Mac Mini (mana.how) │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ GitHub Actions Runner │ │
|
||||
│ │ (self-hosted, always-on) │ │
|
||||
│ └────────────────┬────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ Deploy Script │ │
|
||||
│ │ 1. git pull │ │
|
||||
│ │ 2. pnpm install │ │
|
||||
│ │ 3. docker compose build │ │
|
||||
│ │ 4. docker compose up -d │ │
|
||||
│ │ 5. health check │ │
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ Docker Services │ │
|
||||
│ │ matrix, mana-core-auth, │ │
|
||||
│ │ bots, web-apps, ... │ │
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### GitHub Actions Workflow
|
||||
|
||||
```yaml
|
||||
# .github/workflows/deploy.yml
|
||||
name: Deploy to Mac Mini
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Pull latest changes
|
||||
run: git pull origin main
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build & Deploy
|
||||
run: |
|
||||
docker compose -f docker-compose.macmini.yml build
|
||||
docker compose -f docker-compose.macmini.yml up -d
|
||||
|
||||
- name: Health Check
|
||||
run: ./scripts/mac-mini/health-check.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Auto-Deploy bei Push auf main
|
||||
|
||||
Jeder Push auf `main` löst automatisch ein Deployment aus.
|
||||
|
||||
### Deploy-Flow
|
||||
|
||||
| Schritt | Dauer | Beschreibung |
|
||||
| ---------------- | ----- | ------------------------- |
|
||||
| **Checkout** | ~2s | Repository auschecken |
|
||||
| **Pull** | ~5s | Neueste Änderungen ziehen |
|
||||
| **Install** | ~30s | Dependencies installieren |
|
||||
| **Build** | ~2min | Docker Images bauen |
|
||||
| **Deploy** | ~30s | Container neu starten |
|
||||
| **Health Check** | ~10s | Services überprüfen |
|
||||
| **Gesamt** | ~3min | End-to-End Deployment |
|
||||
|
||||
### Notifications
|
||||
|
||||
```yaml
|
||||
- name: Notify on failure
|
||||
if: failure()
|
||||
run: |
|
||||
curl -X POST "$MATRIX_WEBHOOK_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"body": "❌ Deployment failed: ${{ github.sha }}"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SSH Setup Dokumentation
|
||||
|
||||
Dokumentation für die Einrichtung des GitHub Actions Runners auf dem Mac Mini.
|
||||
|
||||
### Runner Installation
|
||||
|
||||
```bash
|
||||
# Auf dem Mac Mini
|
||||
mkdir ~/actions-runner && cd ~/actions-runner
|
||||
curl -o actions-runner.tar.gz -L https://github.com/actions/runner/releases/download/v2.321.0/actions-runner-osx-arm64-2.321.0.tar.gz
|
||||
tar xzf actions-runner.tar.gz
|
||||
|
||||
# Runner konfigurieren
|
||||
./config.sh --url https://github.com/your-org/manacore-monorepo \
|
||||
--token YOUR_TOKEN \
|
||||
--labels self-hosted,macOS,ARM64
|
||||
|
||||
# Als Service installieren
|
||||
./svc.sh install
|
||||
./svc.sh start
|
||||
```
|
||||
|
||||
### LaunchDaemon
|
||||
|
||||
```xml
|
||||
<!-- ~/Library/LaunchAgents/com.github.actions-runner.plist -->
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.github.actions-runner</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Users/till/actions-runner</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>./runsvc.sh</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Docker PATH Fix
|
||||
|
||||
Der GitHub Actions Runner hatte keinen Zugriff auf Docker im PATH.
|
||||
|
||||
### Problem
|
||||
|
||||
```
|
||||
Error: docker: command not found
|
||||
```
|
||||
|
||||
### Lösung
|
||||
|
||||
```bash
|
||||
# .env für den Runner
|
||||
echo 'PATH=/usr/local/bin:/opt/homebrew/bin:$PATH' >> ~/actions-runner/.env
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## matrix-web Dockerfile Fix
|
||||
|
||||
Das matrix-web Dockerfile fehlte die `shared-pwa` Package Dependency.
|
||||
|
||||
### Problem
|
||||
|
||||
```
|
||||
ERROR: Could not resolve @manacore/shared-pwa
|
||||
Build failed during Docker multi-stage build
|
||||
```
|
||||
|
||||
### Lösung
|
||||
|
||||
```dockerfile
|
||||
# Dockerfile - shared-pwa Package mit kopieren
|
||||
COPY packages/shared-pwa ./packages/shared-pwa
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mac Mini Docs Update
|
||||
|
||||
Dokumentation mit aktivem Runner-Status aktualisiert.
|
||||
|
||||
### Neue Sektion
|
||||
|
||||
```markdown
|
||||
## GitHub Actions Runner
|
||||
|
||||
Status: ✅ Aktiv
|
||||
Labels: self-hosted, macOS, ARM64
|
||||
Auto-Start: Ja (LaunchDaemon)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| ----------------- | ------- | -------------------------- |
|
||||
| **CD Pipeline** | 2 | Workflow + Auto-Deploy |
|
||||
| **SSH Docs** | 1 | Runner Setup Dokumentation |
|
||||
| **Docker PATH** | 1 | Runner Environment Fix |
|
||||
| **Dockerfile** | 1 | shared-pwa Dependency Fix |
|
||||
| **Mac Mini Docs** | 1 | Runner Status Update |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Staging Environment** - Preview Deployments für PRs
|
||||
2. **Rollback** - Automatisches Rollback bei Health-Check-Failure
|
||||
3. **Build Cache** - Docker Layer Caching optimieren
|
||||
4. **Monitoring** - Deployment-Metriken in Grafana
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
---
|
||||
title: 'ManaLink EAS Build Fixes & Expo SDK 55 Migration'
|
||||
description: 'EAS Build Pre-Install Hook für pnpm hoisted Mode, Migration von expo-av zu expo-audio und Dependency Alignment für Expo SDK 55.'
|
||||
date: 2026-03-12
|
||||
author: 'Till Schneider'
|
||||
category: 'bugfix'
|
||||
tags: ['manalink', 'eas-build', 'expo-sdk-55', 'expo-audio', 'react-native']
|
||||
featured: false
|
||||
commits: 5
|
||||
readTime: 4
|
||||
stats:
|
||||
filesChanged: 12
|
||||
linesAdded: 180
|
||||
linesRemoved: 45
|
||||
contributors:
|
||||
- name: 'Till Schneider'
|
||||
handle: 'Till-JS'
|
||||
commits: 5
|
||||
workingHours:
|
||||
start: '2026-03-12T11:00'
|
||||
end: '2026-03-13T11:00'
|
||||
---
|
||||
|
||||
Fokussierter Tag mit **5 Commits** für EAS Build Stabilität und Expo SDK 55 Kompatibilität:
|
||||
|
||||
- **EAS Build Pre-Install Hook** - pnpm hoisted Mode für Monorepo Builds
|
||||
- **expo-av → expo-audio** - Migration auf das neue Audio API
|
||||
- **SDK 55 Dependency Alignment** - Alle Packages auf kompatible Versionen
|
||||
- **Build Image Update** - sdk-55 statt deprecated Default Image
|
||||
|
||||
---
|
||||
|
||||
## EAS Build Pre-Install Hook
|
||||
|
||||
EAS Build unterstützt pnpm Monorepos nur eingeschränkt. Der neue Pre-Install Hook stellt sicher, dass Dependencies korrekt im hoisted Mode installiert werden.
|
||||
|
||||
### Problem
|
||||
|
||||
EAS Build konnte native Dependencies nicht finden, weil pnpm standardmäßig im strict/isolated Mode installiert. React Native erwartet aber, dass alle Dependencies im `node_modules`-Root verfügbar sind.
|
||||
|
||||
### Lösung
|
||||
|
||||
```javascript
|
||||
// eas-hooks/eas-build-pre-install.js
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
// Set node-linker to hoisted for EAS Build compatibility
|
||||
execSync('echo "node-linker=hoisted" >> .npmrc');
|
||||
```
|
||||
|
||||
### eas.json Konfiguration
|
||||
|
||||
```json
|
||||
{
|
||||
"build": {
|
||||
"base": {
|
||||
"node": "20.18.0",
|
||||
"pnpm": "9.15.0",
|
||||
"image": "sdk-55"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration: expo-av → expo-audio
|
||||
|
||||
`expo-av` ist ab SDK 55 deprecated. Die neue `expo-audio` Library bietet ein schlankeres API.
|
||||
|
||||
### API Vergleich
|
||||
|
||||
| Feature | expo-av | expo-audio |
|
||||
| ------------------ | ----------------------- | ---------------------------------- |
|
||||
| **Import** | `Audio` from `expo-av` | `useAudioPlayer` from `expo-audio` |
|
||||
| **Playback** | Class-basiert (`Sound`) | Hook-basiert |
|
||||
| **Bundle Size** | Inkludiert Video | Nur Audio |
|
||||
| **SDK 55 Support** | Deprecated | Empfohlen |
|
||||
|
||||
### Vorher (expo-av)
|
||||
|
||||
```typescript
|
||||
import { Audio } from 'expo-av';
|
||||
|
||||
const { sound } = await Audio.Sound.createAsync(source);
|
||||
await sound.playAsync();
|
||||
```
|
||||
|
||||
### Nachher (expo-audio)
|
||||
|
||||
```typescript
|
||||
import { useAudioPlayer } from 'expo-audio';
|
||||
|
||||
const player = useAudioPlayer(source);
|
||||
player.play();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependency Alignment SDK 55
|
||||
|
||||
Mehrere Dependencies waren nicht auf die von Expo SDK 55 erwarteten Versionen gepinnt.
|
||||
|
||||
### Aktualisierte Packages
|
||||
|
||||
| Package | Vorher | Nachher |
|
||||
| --------------------- | ------ | ------- |
|
||||
| `react-native` | 0.76.x | 0.79.x |
|
||||
| `react` | 18.3.x | 19.0.x |
|
||||
| `expo-router` | 4.x | 5.x |
|
||||
| `expo-image` | 1.x | 2.x |
|
||||
| `@react-navigation/*` | 6.x | 7.x |
|
||||
|
||||
### Build Image
|
||||
|
||||
```diff
|
||||
- "image": "default"
|
||||
+ "image": "sdk-55"
|
||||
```
|
||||
|
||||
Das `default` Build Image enthielt veraltete Xcode- und Android SDK-Versionen, die mit SDK 55 inkompatibel waren.
|
||||
|
||||
---
|
||||
|
||||
## babel-preset-expo
|
||||
|
||||
Als explizite Dependency hinzugefügt, da EAS Build im hoisted Mode das Preset nicht automatisch aus der Expo-Dependency auflösen konnte.
|
||||
|
||||
```json
|
||||
{
|
||||
"devDependencies": {
|
||||
"babel-preset-expo": "~13.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| ------------------- | ------- | ----------------------------- |
|
||||
| **EAS Build** | 2 | Pre-Install Hook, Build Image |
|
||||
| **Audio Migration** | 1 | expo-av → expo-audio |
|
||||
| **Dependencies** | 1 | SDK 55 Alignment |
|
||||
| **Babel** | 1 | Explicit Preset |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **ManaLink Features** - Audio-Playback im Foreground/Background testen
|
||||
2. **TestFlight Build** - Erster Build über EAS Submit
|
||||
3. **Android Build** - EAS Build für Google Play vorbereiten
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
---
|
||||
title: 'Traces App Integration & Calendar Production Hardening'
|
||||
description: 'Traces App mit NestJS Backend und Expo Mobile ins Monorepo integriert. Calendar mit Security Fixes, Rate Limiting und Accessibility Verbesserungen produktionsreif gemacht.'
|
||||
date: 2026-03-15
|
||||
author: 'Till Schneider'
|
||||
category: 'feature'
|
||||
tags: ['traces', 'calendar', 'security', 'production', 'rate-limiting', 'expo', 'eas-build']
|
||||
featured: false
|
||||
commits: 8
|
||||
readTime: 7
|
||||
stats:
|
||||
filesChanged: 95
|
||||
linesAdded: 4200
|
||||
linesRemoved: 380
|
||||
contributors:
|
||||
- name: 'Till Schneider'
|
||||
handle: 'Till-JS'
|
||||
commits: 8
|
||||
workingHours:
|
||||
start: '2026-03-15T11:00'
|
||||
end: '2026-03-16T11:00'
|
||||
---
|
||||
|
||||
Intensiver Tag mit **8 Commits** für eine neue App-Integration und Production Hardening:
|
||||
|
||||
- **Traces App** - AI City Guides mit NestJS Backend und Expo Mobile
|
||||
- **Calendar Security** - Rate Limiting, Input Validation, CSRF Protection
|
||||
- **Calendar Performance** - Query Optimization, Connection Pooling
|
||||
- **EAS Build Fixes** - .npmrc und Dockerfile Healthcheck Ports
|
||||
|
||||
---
|
||||
|
||||
## Traces App Integration
|
||||
|
||||
Traces ist eine neue App für AI-generierte City Guides. Die App wurde komplett ins Monorepo integriert.
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
apps/traces/
|
||||
├── apps/
|
||||
│ ├── backend/ # NestJS API (Port 3012)
|
||||
│ │ ├── src/
|
||||
│ │ │ ├── guides/ # AI City Guide Generation
|
||||
│ │ │ ├── locations/ # POI Management
|
||||
│ │ │ └── routes/ # Route Planning
|
||||
│ │ └── package.json
|
||||
│ └── mobile/ # Expo React Native
|
||||
│ ├── app/
|
||||
│ │ ├── (tabs)/ # Tab Navigation
|
||||
│ │ ├── guide/ # Guide Detail Screens
|
||||
│ │ └── map/ # Map View
|
||||
│ └── package.json
|
||||
└── package.json
|
||||
```
|
||||
|
||||
### Backend Features
|
||||
|
||||
| Feature | Beschreibung |
|
||||
| -------------------- | ------------------------------------- |
|
||||
| **AI Guides** | LLM-basierte Stadtführer-Generierung |
|
||||
| **POI Database** | Sehenswürdigkeiten mit Geodaten |
|
||||
| **Route Planning** | Optimierte Routen zwischen POIs |
|
||||
| **Auth Integration** | mana-core-auth via shared-nestjs-auth |
|
||||
|
||||
### Mobile App
|
||||
|
||||
- Expo SDK 55 mit expo-router
|
||||
- MapView Integration für Routen-Visualisierung
|
||||
- Offline-Cache für heruntergeladene Guides
|
||||
|
||||
---
|
||||
|
||||
## Calendar Production Hardening
|
||||
|
||||
Der Calendar wurde mit umfassenden Security- und Performance-Fixes produktionsreif gemacht.
|
||||
|
||||
### Security Fixes
|
||||
|
||||
#### Rate Limiting
|
||||
|
||||
```typescript
|
||||
// Rate Limiting pro Endpoint
|
||||
@UseGuards(ThrottlerGuard)
|
||||
@Throttle({ default: { limit: 100, ttl: 60000 } })
|
||||
@Controller('api/events')
|
||||
export class EventsController {
|
||||
@Throttle({ default: { limit: 10, ttl: 60000 } })
|
||||
@Post()
|
||||
async createEvent() {
|
||||
// Max 10 Events pro Minute
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Input Validation
|
||||
|
||||
Strikte Validation für alle API Endpoints:
|
||||
|
||||
```typescript
|
||||
export class CreateEventDto {
|
||||
@IsString()
|
||||
@MaxLength(200)
|
||||
title: string;
|
||||
|
||||
@IsISO8601()
|
||||
startDate: string;
|
||||
|
||||
@IsISO8601()
|
||||
endDate: string;
|
||||
|
||||
@IsOptional()
|
||||
@MaxLength(5000)
|
||||
description?: string;
|
||||
}
|
||||
```
|
||||
|
||||
#### CSRF Protection
|
||||
|
||||
```typescript
|
||||
// Helmet Security Headers
|
||||
app.use(helmet());
|
||||
app.use(
|
||||
helmet.contentSecurityPolicy({
|
||||
directives: {
|
||||
defaultSrc: ["'self'"],
|
||||
scriptSrc: ["'self'"],
|
||||
},
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
### Performance Fixes
|
||||
|
||||
| Fix | Vorher | Nachher |
|
||||
| ------------------- | ----------- | -------------------- |
|
||||
| **Event Query** | N+1 Queries | Single JOIN Query |
|
||||
| **Connection Pool** | Default (5) | Konfigurierbar (20) |
|
||||
| **Response Size** | Alle Felder | Selektive Projektion |
|
||||
|
||||
### Accessibility Verbesserungen
|
||||
|
||||
- ARIA Labels für alle interaktiven Elemente
|
||||
- Keyboard Navigation im Event-Dialog
|
||||
- Focus Management beim Modal-Open/Close
|
||||
- Screen Reader Announcements für Kalender-Navigation
|
||||
|
||||
---
|
||||
|
||||
## Auto-Generate CALENDAR_ENCRYPTION_KEY
|
||||
|
||||
Der Encryption Key für Calendar-Daten wird in Production automatisch generiert, falls nicht gesetzt.
|
||||
|
||||
```typescript
|
||||
// Fallback Key Generation
|
||||
const encryptionKey = process.env.CALENDAR_ENCRYPTION_KEY || crypto.randomBytes(32).toString('hex');
|
||||
|
||||
if (!process.env.CALENDAR_ENCRYPTION_KEY) {
|
||||
logger.warn('CALENDAR_ENCRYPTION_KEY not set, using generated key');
|
||||
logger.warn('Set CALENDAR_ENCRYPTION_KEY for persistent encryption');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dockerfile Healthcheck Ports
|
||||
|
||||
Die Healthcheck-Ports in den Dockerfiles waren hardcoded und stimmten nicht mit den tatsächlichen Service-Ports überein.
|
||||
|
||||
```diff
|
||||
- HEALTHCHECK CMD curl -f http://localhost:3000/health || exit 1
|
||||
+ HEALTHCHECK CMD curl -f http://localhost:${PORT:-3000}/health || exit 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## EAS Build: .npmrc für Hoisted Mode
|
||||
|
||||
Für alle Mobile Apps wurde `.npmrc` mit `node-linker=hoisted` hinzugefügt, um EAS Build Kompatibilität sicherzustellen.
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
node-linker=hoisted
|
||||
```
|
||||
|
||||
### patch-package Non-Fatal
|
||||
|
||||
In picture-mobile wurde `patch-package` im postinstall Script non-fatal gemacht, da fehlende Patches den EAS Build abbrechen konnten.
|
||||
|
||||
```diff
|
||||
- "postinstall": "patch-package"
|
||||
+ "postinstall": "patch-package || true"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| --------------------- | ------- | ---------------------------------- |
|
||||
| **Traces** | 2 | NestJS Backend + Expo Mobile |
|
||||
| **Calendar Security** | 3 | Rate Limiting, Validation, CSRF |
|
||||
| **Calendar A11y** | 1 | ARIA, Keyboard, Focus |
|
||||
| **Build Infra** | 2 | Healthcheck, .npmrc, patch-package |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Traces API** - Weitere Guide-Endpoints implementieren
|
||||
2. **Calendar E2E Tests** - Playwright Tests für kritische Flows
|
||||
3. **Calendar Monitoring** - Error Tracking und Performance Metrics
|
||||
4. **Traces TestFlight** - Erster iOS Build
|
||||
|
|
@ -0,0 +1,283 @@
|
|||
---
|
||||
title: 'Mukke Music Player, Calendar E2E Tests & Pre-Commit Fixes'
|
||||
description: 'Mukke als offline-first iOS Music Player ins Monorepo aufgenommen. Calendar Playwright E2E Tests, Pre-Commit Hook Fixes und Auth Verbesserungen.'
|
||||
date: 2026-03-17
|
||||
author: 'Till Schneider'
|
||||
category: 'feature'
|
||||
tags: ['mukke', 'music-player', 'expo', 'e2e-tests', 'playwright', 'pre-commit', 'auth', 'traces']
|
||||
featured: false
|
||||
commits: 9
|
||||
readTime: 8
|
||||
stats:
|
||||
filesChanged: 85
|
||||
linesAdded: 5800
|
||||
linesRemoved: 220
|
||||
contributors:
|
||||
- name: 'Till Schneider'
|
||||
handle: 'Till-JS'
|
||||
commits: 9
|
||||
workingHours:
|
||||
start: '2026-03-17T11:00'
|
||||
end: '2026-03-18T11:00'
|
||||
---
|
||||
|
||||
Produktiver Tag mit **9 Commits** über mehrere Apps hinweg:
|
||||
|
||||
- **Mukke** - Offline-first iOS Music Player mit Expo und SQLite
|
||||
- **Calendar E2E Tests** - Playwright Tests für die Web App
|
||||
- **Pre-Commit Hook** - eslint-config Dependency Fix, type-check entfernt
|
||||
- **Auth Fixes** - 403 für unverified Email, Password Min Length
|
||||
- **Traces** - EAS Build für TestFlight konfiguriert
|
||||
|
||||
---
|
||||
|
||||
## Mukke: Offline-First Music Player
|
||||
|
||||
Mukke ist ein neuer offline-first iOS Music Player. Die App verwaltet lokale Musikdateien mit SQLite als Datenbank und bietet Background Audio Playback.
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
apps/mukke/
|
||||
├── apps/
|
||||
│ └── web/ # SvelteKit Web App (Playlist Management)
|
||||
│ ├── src/
|
||||
│ │ ├── routes/
|
||||
│ │ │ ├── (app)/
|
||||
│ │ │ │ ├── library/ # Musik-Bibliothek
|
||||
│ │ │ │ ├── playlists/ # Playlist-Verwaltung
|
||||
│ │ │ │ └── player/ # Audio Player
|
||||
│ │ │ └── +layout.svelte
|
||||
│ │ └── lib/
|
||||
│ │ ├── stores/ # Svelte 5 Runes Stores
|
||||
│ │ ├── db/ # SQLite Integration
|
||||
│ │ └── components/ # UI Komponenten
|
||||
│ └── package.json
|
||||
└── package.json
|
||||
```
|
||||
|
||||
### Key Features
|
||||
|
||||
| Feature | Beschreibung |
|
||||
| -------------------- | ---------------------------------------- |
|
||||
| **Offline-First** | Alle Daten lokal in SQLite |
|
||||
| **Local Files** | Import aus dem lokalen Dateisystem |
|
||||
| **Background Audio** | expo-audio mit Background Mode |
|
||||
| **Playlists** | Erstellen, Bearbeiten, Sortieren |
|
||||
| **Metadata** | ID3 Tag Parsing für Artist, Album, Cover |
|
||||
|
||||
### Technologie Stack
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Mukke iOS App │
|
||||
├─────────────────────────────────────┤
|
||||
│ Expo SDK 55 + expo-router │
|
||||
│ expo-audio (Background Playback) │
|
||||
│ expo-file-system (Local Storage) │
|
||||
│ expo-sqlite (Metadata Database) │
|
||||
│ NativeWind (Styling) │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Datenbank Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE tracks (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
artist TEXT,
|
||||
album TEXT,
|
||||
duration INTEGER,
|
||||
file_path TEXT NOT NULL,
|
||||
cover_art_path TEXT,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE playlists (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE playlist_tracks (
|
||||
playlist_id TEXT REFERENCES playlists(id),
|
||||
track_id TEXT REFERENCES tracks(id),
|
||||
position INTEGER,
|
||||
PRIMARY KEY (playlist_id, track_id)
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Calendar: Playwright E2E Tests
|
||||
|
||||
Umfassende E2E Tests für die Calendar Web App mit Playwright.
|
||||
|
||||
### Test Coverage
|
||||
|
||||
| Test Suite | Tests | Beschreibung |
|
||||
| --------------- | ----- | ------------------------------ |
|
||||
| **Navigation** | 6 | View-Wechsel, Datum-Navigation |
|
||||
| **Event CRUD** | 8 | Erstellen, Bearbeiten, Löschen |
|
||||
| **Drag & Drop** | 4 | Event verschieben, Resize |
|
||||
| **Keyboard** | 5 | Shortcuts, Focus Management |
|
||||
| **Responsive** | 3 | Mobile, Tablet, Desktop |
|
||||
|
||||
### Test Beispiel
|
||||
|
||||
```typescript
|
||||
test('should create a new event via click', async ({ page }) => {
|
||||
await page.goto('/calendar');
|
||||
|
||||
// Click on a time slot
|
||||
await page.locator('[data-timeslot="10:00"]').click();
|
||||
|
||||
// Fill event form
|
||||
await page.getByLabel('Title').fill('Team Meeting');
|
||||
await page.getByLabel('Description').fill('Weekly sync');
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
|
||||
// Verify event appears
|
||||
await expect(page.getByText('Team Meeting')).toBeVisible();
|
||||
});
|
||||
```
|
||||
|
||||
### CI Integration
|
||||
|
||||
```yaml
|
||||
# In der Pipeline
|
||||
- name: Calendar E2E Tests
|
||||
run: pnpm --filter @calendar/web test:e2e
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pre-Commit Hook Fixes
|
||||
|
||||
Der Pre-Commit Hook hatte zwei Probleme:
|
||||
|
||||
### 1. Fehlende eslint-config Dependency
|
||||
|
||||
```diff
|
||||
"devDependencies": {
|
||||
+ "@manacore/eslint-config": "workspace:*",
|
||||
"lint-staged": "^15.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. type-check entfernt
|
||||
|
||||
`type-check` im Pre-Commit war zu langsam (30+ Sekunden) und blockierte den Workflow.
|
||||
|
||||
```diff
|
||||
// lint-staged.config.js
|
||||
module.exports = {
|
||||
'*.{ts,tsx,js,jsx}': [
|
||||
'eslint --fix',
|
||||
'prettier --write',
|
||||
- 'tsc --noEmit',
|
||||
],
|
||||
'*.{svelte}': [
|
||||
'prettier --write',
|
||||
- 'svelte-check',
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Type-Checking läuft weiterhin in der CI Pipeline.
|
||||
|
||||
---
|
||||
|
||||
## Auth Verbesserungen
|
||||
|
||||
### 403 für Unverified Email
|
||||
|
||||
Bisher erhielten Nutzer mit unbestätigter E-Mail einen generischen 401 Error. Jetzt gibt es einen expliziten 403 mit klarer Fehlermeldung.
|
||||
|
||||
```typescript
|
||||
if (!user.emailVerified) {
|
||||
throw new HttpException(
|
||||
{
|
||||
statusCode: 403,
|
||||
error: 'email_not_verified',
|
||||
message: 'Please verify your email address before logging in.',
|
||||
},
|
||||
HttpStatus.FORBIDDEN
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Password Min Length
|
||||
|
||||
Die Mindestlänge für das Reset-Password wurde von 6 auf 8 Zeichen angehoben, um mit der Registration übereinzustimmen.
|
||||
|
||||
```diff
|
||||
const resetPasswordSchema = z.object({
|
||||
- password: z.string().min(6),
|
||||
+ password: z.string().min(8),
|
||||
token: z.string(),
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Traces: EAS Build für TestFlight
|
||||
|
||||
EAS Build für die Traces App konfiguriert, inkl. TestFlight Distribution.
|
||||
|
||||
```json
|
||||
{
|
||||
"build": {
|
||||
"production": {
|
||||
"distribution": "store",
|
||||
"ios": {
|
||||
"buildConfiguration": "Release"
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
"distribution": "internal",
|
||||
"ios": {
|
||||
"simulator": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"submit": {
|
||||
"production": {
|
||||
"ios": {
|
||||
"appleId": "till@manacore.app",
|
||||
"ascAppId": "traces-app-id"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Calendar Settings Audit
|
||||
|
||||
Dokumentation aller Calendar Settings mit aktuellem Status und geplanten Erweiterungen erstellt.
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| ----------------- | ------- | ---------------------------------- |
|
||||
| **Mukke** | 1 | Offline-first Music Player |
|
||||
| **Calendar E2E** | 1 | 26 Playwright Tests |
|
||||
| **Pre-Commit** | 1 | eslint-config, type-check entfernt |
|
||||
| **Auth** | 2 | 403 Unverified, Password Length |
|
||||
| **Traces** | 2 | EAS Build, TestFlight |
|
||||
| **Calendar Docs** | 1 | Settings Audit |
|
||||
| **Bot Services** | 1 | Build Fix |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Mukke Player** - Background Audio und Lock Screen Controls
|
||||
2. **Calendar E2E** - Recurring Events Tests
|
||||
3. **Traces TestFlight** - Erster interner Build
|
||||
4. **Test Coverage** - Unit Tests für Contacts und Todo
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
---
|
||||
title: 'Test Coverage Expansion: Contacts & Todo'
|
||||
description: 'Umfassende Unit Tests für Contacts (62 Tests) und Todo (39 Tests) Web Apps. Cross-App Test Coverage mit Vitest erweitert und ungenutzten Code entfernt.'
|
||||
date: 2026-03-18
|
||||
author: 'Till Schneider'
|
||||
category: 'update'
|
||||
tags: ['testing', 'unit-tests', 'contacts', 'todo', 'calendar', 'vitest', 'coverage']
|
||||
featured: false
|
||||
commits: 5
|
||||
readTime: 6
|
||||
stats:
|
||||
filesChanged: 42
|
||||
linesAdded: 3200
|
||||
linesRemoved: 890
|
||||
contributors:
|
||||
- name: 'Till Schneider'
|
||||
handle: 'Till-JS'
|
||||
commits: 5
|
||||
workingHours:
|
||||
start: '2026-03-18T11:00'
|
||||
end: '2026-03-19T11:00'
|
||||
---
|
||||
|
||||
Fokussierter Tag mit **5 Commits** für Test Coverage und Code Cleanup:
|
||||
|
||||
- **Contacts Web** - 62 Unit Tests für Stores, Utils und API Client
|
||||
- **Todo Web** - 39 Unit Tests, d3-force entfernt, Default Title Fix
|
||||
- **Cross-App Coverage** - Calendar, Contacts und Todo Test-Infrastruktur
|
||||
- **Code Cleanup** - Ungenutzte Network View Remnants entfernt
|
||||
|
||||
---
|
||||
|
||||
## Contacts Web: 62 Unit Tests
|
||||
|
||||
Umfassende Test Coverage für die Contacts Web App mit Vitest.
|
||||
|
||||
### Test Suites
|
||||
|
||||
| Suite | Tests | Beschreibung |
|
||||
| ----------------- | ----- | ------------------------------------ |
|
||||
| **Contact Store** | 18 | CRUD Operationen, Filtering, Sorting |
|
||||
| **Group Store** | 12 | Gruppenverwaltung, Mitglieder |
|
||||
| **API Client** | 15 | HTTP Requests, Error Handling, Retry |
|
||||
| **Utils** | 10 | Formatierung, Validierung, Search |
|
||||
| **Types** | 7 | Type Guards, Transformations |
|
||||
|
||||
### Store Test Beispiel
|
||||
|
||||
```typescript
|
||||
describe('contactStore', () => {
|
||||
it('should filter contacts by search term', () => {
|
||||
const store = createContactStore();
|
||||
store.setContacts([
|
||||
{ id: '1', name: 'Alice Schmidt', email: 'alice@example.com' },
|
||||
{ id: '2', name: 'Bob Mueller', email: 'bob@example.com' },
|
||||
{ id: '3', name: 'Charlie Schmidt', email: 'charlie@example.com' },
|
||||
]);
|
||||
|
||||
store.setSearchTerm('Schmidt');
|
||||
|
||||
expect(store.filteredContacts).toHaveLength(2);
|
||||
expect(store.filteredContacts.map((c) => c.name)).toEqual(['Alice Schmidt', 'Charlie Schmidt']);
|
||||
});
|
||||
|
||||
it('should handle API errors gracefully', async () => {
|
||||
vi.mocked(fetch).mockRejectedValueOnce(new Error('Network error'));
|
||||
|
||||
const store = createContactStore();
|
||||
const result = await store.loadContacts();
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.error?.code).toBe('NETWORK_ERROR');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### API Client Tests
|
||||
|
||||
```typescript
|
||||
describe('contactsApiClient', () => {
|
||||
it('should retry on 503 errors', async () => {
|
||||
vi.mocked(fetch)
|
||||
.mockResolvedValueOnce(new Response(null, { status: 503 }))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify({ data: [] })));
|
||||
|
||||
const result = await apiClient.getContacts();
|
||||
|
||||
expect(fetch).toHaveBeenCalledTimes(2);
|
||||
expect(result.ok).toBe(true);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Todo Web: 39 Unit Tests
|
||||
|
||||
Unit Tests für die Todo App mit zusätzlichem Code Cleanup.
|
||||
|
||||
### Test Suites
|
||||
|
||||
| Suite | Tests | Beschreibung |
|
||||
| -------------- | ----- | ------------------------------- |
|
||||
| **Todo Store** | 14 | CRUD, Completion, Reordering |
|
||||
| **List Store** | 8 | Listen-Management, Default List |
|
||||
| **Utils** | 9 | Date Helpers, Priority Sorting |
|
||||
| **Components** | 8 | Render Tests, User Interactions |
|
||||
|
||||
### d3-force Entfernung
|
||||
|
||||
Die `d3-force` Dependency wurde entfernt. Sie war ursprünglich für eine Graph-Visualisierung geplant, die nie implementiert wurde.
|
||||
|
||||
```diff
|
||||
"dependencies": {
|
||||
- "d3-force": "^3.0.0",
|
||||
- "@types/d3-force": "^3.0.0",
|
||||
"svelte": "^5.0.0",
|
||||
}
|
||||
```
|
||||
|
||||
**Impact:** Bundle Size um ~45 KB reduziert.
|
||||
|
||||
### Default Title Fix
|
||||
|
||||
Neue Todos ohne Titel erhielten `undefined` statt einen leeren String. Das führte zu Darstellungsproblemen in der Liste.
|
||||
|
||||
```diff
|
||||
function createTodo(input: Partial<Todo>): Todo {
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
- title: input.title,
|
||||
+ title: input.title ?? '',
|
||||
completed: false,
|
||||
priority: input.priority ?? 'medium',
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cross-App Test Infrastructure
|
||||
|
||||
### Vitest Konfiguration
|
||||
|
||||
Einheitliche Vitest-Konfiguration für alle Web Apps:
|
||||
|
||||
```typescript
|
||||
// vitest.config.ts (shared pattern)
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{ts,js}'],
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'html'],
|
||||
include: ['src/lib/**/*.ts'],
|
||||
exclude: ['**/*.d.ts', '**/*.test.ts'],
|
||||
},
|
||||
setupFiles: ['./src/test/setup.ts'],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Coverage Übersicht
|
||||
|
||||
| App | Tests | Statements | Branches | Functions |
|
||||
| ------------ | ----- | ---------- | -------- | --------- |
|
||||
| **Contacts** | 62 | 78% | 72% | 81% |
|
||||
| **Todo** | 39 | 74% | 68% | 76% |
|
||||
| **Calendar** | 26 | 65% | 58% | 69% |
|
||||
|
||||
### Test Commands
|
||||
|
||||
```bash
|
||||
# Einzelne App testen
|
||||
pnpm --filter @contacts/web test
|
||||
pnpm --filter @todo/web test
|
||||
|
||||
# Mit Coverage Report
|
||||
pnpm --filter @contacts/web test -- --coverage
|
||||
|
||||
# Alle Web App Tests
|
||||
pnpm turbo run test --filter="*/web"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contacts: Network View Cleanup
|
||||
|
||||
Ungenutzte Remnants der geplanten Network-View (Graph-Visualisierung von Kontakt-Beziehungen) wurden entfernt.
|
||||
|
||||
### Entfernte Dateien
|
||||
|
||||
- `src/lib/components/NetworkView.svelte`
|
||||
- `src/lib/stores/networkStore.ts`
|
||||
- `src/lib/utils/graphLayout.ts`
|
||||
- `src/lib/types/network.ts`
|
||||
|
||||
### Entfernte Dependencies
|
||||
|
||||
```diff
|
||||
- "d3-force": "^3.0.0",
|
||||
- "@types/d3-force": "^3.0.10",
|
||||
- "d3-selection": "^3.0.0",
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contacts: Production Config Fix
|
||||
|
||||
Die `PUBLIC_TODO_BACKEND_URL` fehlte in der Production-Konfiguration der Contacts Web App. Das führte dazu, dass die Todo-Integration in Production nicht funktionierte.
|
||||
|
||||
```diff
|
||||
# .env.production
|
||||
PUBLIC_CONTACTS_BACKEND_URL=https://contacts-api.manacore.app
|
||||
+ PUBLIC_TODO_BACKEND_URL=https://todo-api.manacore.app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Bereich | Commits | Highlights |
|
||||
| ------------------ | ------- | --------------------------- |
|
||||
| **Contacts Tests** | 1 | 62 Unit Tests, Stores + API |
|
||||
| **Todo Tests** | 1 | 39 Tests, d3-force entfernt |
|
||||
| **Cross-App** | 1 | Vitest Config, Coverage |
|
||||
| **Cleanup** | 1 | Network View Remnants |
|
||||
| **Config** | 1 | Production URL Fix |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **Coverage > 80%** - Verbleibende Lücken in Stores schließen
|
||||
2. **Calendar Tests** - Coverage auf 80% bringen
|
||||
3. **CI Integration** - Test Coverage Reports in PR Checks
|
||||
4. **E2E Tests** - Contacts und Todo Playwright Tests
|
||||
Loading…
Add table
Add a link
Reference in a new issue