mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 22:41:09 +02:00
style: auto-format codebase with Prettier
Applied formatting to 1487+ files using pnpm format:write - TypeScript/JavaScript files - Svelte components - Astro pages - JSON configs - Markdown docs 13 files still need manual review (Astro JSX comments)
This commit is contained in:
parent
0241f5554c
commit
d36b321d9d
3952 changed files with 661498 additions and 739751 deletions
|
|
@ -6,18 +6,19 @@ This document tracks critical dependencies across all projects and their target
|
|||
|
||||
### High Priority - Version Mismatches
|
||||
|
||||
| Package | Target Version | Current Versions | Notes |
|
||||
|---------|---------------|------------------|-------|
|
||||
| `@supabase/supabase-js` | **2.81.1** | 2.38.4 - 2.81.1 | Significant spread, alignment critical |
|
||||
| `typescript` | **5.9.2** | 5.3.3 - 5.9.2 | Update all to latest |
|
||||
| `react` | **19.1.0** | 18.3.1 - 19.1.0 | Mixed versions |
|
||||
| `expo` | **54.x** | 52.0.39 - 54.0.21 | Manacore needs update |
|
||||
| `expo-router` | **6.x** | 4.0.19 - 6.0.14 | Manacore needs update |
|
||||
| `astro` | **5.16.0** | 5.3.0 - 5.16.0 | Memoro landing needs update |
|
||||
| Package | Target Version | Current Versions | Notes |
|
||||
| ----------------------- | -------------- | ----------------- | -------------------------------------- |
|
||||
| `@supabase/supabase-js` | **2.81.1** | 2.38.4 - 2.81.1 | Significant spread, alignment critical |
|
||||
| `typescript` | **5.9.2** | 5.3.3 - 5.9.2 | Update all to latest |
|
||||
| `react` | **19.1.0** | 18.3.1 - 19.1.0 | Mixed versions |
|
||||
| `expo` | **54.x** | 52.0.39 - 54.0.21 | Manacore needs update |
|
||||
| `expo-router` | **6.x** | 4.0.19 - 6.0.14 | Manacore needs update |
|
||||
| `astro` | **5.16.0** | 5.3.0 - 5.16.0 | Memoro landing needs update |
|
||||
|
||||
### Current Status by Project
|
||||
|
||||
#### Supabase Versions
|
||||
|
||||
```
|
||||
maerchenzauber:
|
||||
- backend: 2.50.3
|
||||
|
|
@ -38,6 +39,7 @@ memoro:
|
|||
```
|
||||
|
||||
#### Expo/React Native Versions
|
||||
|
||||
```
|
||||
maerchenzauber:
|
||||
- expo: 54.0.21 ✅
|
||||
|
|
@ -61,6 +63,7 @@ memoro:
|
|||
```
|
||||
|
||||
#### NestJS Versions (Backends)
|
||||
|
||||
```
|
||||
maerchenzauber: NestJS 10.0.0
|
||||
manadeck: NestJS 11.0.1
|
||||
|
|
@ -141,17 +144,20 @@ After updating dependencies, verify:
|
|||
## Breaking Changes to Watch
|
||||
|
||||
### Supabase 2.38 → 2.81
|
||||
|
||||
- Auth session handling may have changed
|
||||
- Check `onAuthStateChange` listeners
|
||||
- Verify RLS policies still work
|
||||
|
||||
### Expo SDK 52 → 54
|
||||
|
||||
- Check expo-router migration guide
|
||||
- New navigation patterns in 6.x
|
||||
- Screen options changes
|
||||
- Layout changes
|
||||
|
||||
### NestJS 10 → 11
|
||||
|
||||
- Decorator changes
|
||||
- Module resolution changes
|
||||
- Check middleware compatibility
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ The manacore-monorepo uses a comprehensive CI/CD pipeline with the following fea
|
|||
Configure the following secrets in your GitHub repository (`Settings > Secrets and variables > Actions`):
|
||||
|
||||
#### Docker Registry
|
||||
|
||||
```
|
||||
DOCKER_USERNAME=your-docker-username
|
||||
DOCKER_PASSWORD=your-docker-password
|
||||
|
|
@ -94,6 +95,7 @@ DOCKER_REGISTRY=wuesteon
|
|||
```
|
||||
|
||||
#### Staging Environment
|
||||
|
||||
```
|
||||
STAGING_HOST=staging.manacore.app
|
||||
STAGING_USER=deploy
|
||||
|
|
@ -117,6 +119,7 @@ STAGING_JWT_PRIVATE_KEY=<private-key>
|
|||
```
|
||||
|
||||
#### Production Environment
|
||||
|
||||
```
|
||||
PRODUCTION_HOST=api.manacore.app
|
||||
PRODUCTION_USER=deploy
|
||||
|
|
@ -126,12 +129,14 @@ PRODUCTION_API_URL=https://api.manacore.app
|
|||
```
|
||||
|
||||
#### Turbo Cache (Optional)
|
||||
|
||||
```
|
||||
TURBO_TOKEN=<vercel-token>
|
||||
TURBO_TEAM=<team-name>
|
||||
```
|
||||
|
||||
#### Code Coverage (Optional)
|
||||
|
||||
```
|
||||
CODECOV_TOKEN=<codecov-token>
|
||||
```
|
||||
|
|
@ -147,6 +152,7 @@ The CI/CD pipeline consists of 6 GitHub Actions workflows:
|
|||
**Triggers**: Pull requests to `main` or `develop`
|
||||
|
||||
**Steps**:
|
||||
|
||||
1. Detect changed projects
|
||||
2. Run format check
|
||||
3. Run linting
|
||||
|
|
@ -163,6 +169,7 @@ The CI/CD pipeline consists of 6 GitHub Actions workflows:
|
|||
**Triggers**: Push to `main` branch
|
||||
|
||||
**Steps**:
|
||||
|
||||
1. Full validation (all projects)
|
||||
2. Build all projects
|
||||
3. Build and push Docker images
|
||||
|
|
@ -173,6 +180,7 @@ The CI/CD pipeline consists of 6 GitHub Actions workflows:
|
|||
**Triggers**: Manual or automated from main CI
|
||||
|
||||
**Steps**:
|
||||
|
||||
1. SSH to staging server
|
||||
2. Pull latest Docker images
|
||||
3. Update environment configuration
|
||||
|
|
@ -186,6 +194,7 @@ The CI/CD pipeline consists of 6 GitHub Actions workflows:
|
|||
**Triggers**: Manual only
|
||||
|
||||
**Steps**:
|
||||
|
||||
1. Validate deployment request
|
||||
2. Request manual approval
|
||||
3. Create database backup
|
||||
|
|
@ -201,6 +210,7 @@ The CI/CD pipeline consists of 6 GitHub Actions workflows:
|
|||
**Triggers**: PRs, pushes to main, weekly schedule
|
||||
|
||||
**Steps**:
|
||||
|
||||
1. Run all tests with coverage
|
||||
2. Collect coverage reports
|
||||
3. Upload to Codecov
|
||||
|
|
@ -212,6 +222,7 @@ The CI/CD pipeline consists of 6 GitHub Actions workflows:
|
|||
**Triggers**: Weekly schedule, manual
|
||||
|
||||
**Steps**:
|
||||
|
||||
1. Check for outdated dependencies
|
||||
2. Run security audit
|
||||
3. Create issue for critical vulnerabilities
|
||||
|
|
@ -259,6 +270,7 @@ FROM node:20-alpine AS production
|
|||
```
|
||||
|
||||
**Key Features**:
|
||||
|
||||
- Non-root user (`nestjs`)
|
||||
- Health checks
|
||||
- Resource limits
|
||||
|
|
@ -269,6 +281,7 @@ FROM node:20-alpine AS production
|
|||
Template: `docker/templates/Dockerfile.sveltekit`
|
||||
|
||||
**Key Features**:
|
||||
|
||||
- SSR support
|
||||
- Static asset optimization
|
||||
- Non-root user
|
||||
|
|
@ -279,6 +292,7 @@ Template: `docker/templates/Dockerfile.sveltekit`
|
|||
Template: `docker/templates/Dockerfile.astro`
|
||||
|
||||
**Key Features**:
|
||||
|
||||
- Nginx-based serving
|
||||
- Gzip compression
|
||||
- Security headers
|
||||
|
|
@ -311,12 +325,14 @@ Two environments are provided:
|
|||
**URL**: `https://staging.manacore.app`
|
||||
|
||||
**Characteristics**:
|
||||
|
||||
- Automatic deployment from `main` branch
|
||||
- Separate database instances
|
||||
- Full feature parity with production
|
||||
- Verbose logging enabled
|
||||
|
||||
**Access**:
|
||||
|
||||
```bash
|
||||
ssh deploy@staging.manacore.app
|
||||
cd ~/manacore-staging
|
||||
|
|
@ -330,6 +346,7 @@ docker compose ps
|
|||
**URL**: `https://api.manacore.app`
|
||||
|
||||
**Characteristics**:
|
||||
|
||||
- Manual deployment with approval
|
||||
- High availability configuration
|
||||
- Performance optimized
|
||||
|
|
@ -337,6 +354,7 @@ docker compose ps
|
|||
- Backup procedures
|
||||
|
||||
**Access**:
|
||||
|
||||
```bash
|
||||
ssh deploy@api.manacore.app
|
||||
cd ~/manacore-production
|
||||
|
|
@ -378,6 +396,7 @@ Production requires manual trigger and approval:
|
|||
Go to GitHub Actions > CD - Production Deployment > Run workflow
|
||||
|
||||
**Required Inputs**:
|
||||
|
||||
- Service: `all` or specific service name
|
||||
- Environment: `production`
|
||||
- Confirm: Type `deploy`
|
||||
|
|
@ -391,6 +410,7 @@ Approve in: GitHub > Settings > Environments > production-approval
|
|||
#### Step 3: Automated Deployment
|
||||
|
||||
Once approved:
|
||||
|
||||
1. Creates database backup
|
||||
2. Tags current deployment
|
||||
3. Pulls latest images
|
||||
|
|
@ -471,6 +491,7 @@ export PRODUCTION_USER=deploy
|
|||
```
|
||||
|
||||
**What the script does**:
|
||||
|
||||
1. Confirms rollback with user
|
||||
2. Checks for previous deployment backup
|
||||
3. Stops current services
|
||||
|
|
@ -545,6 +566,7 @@ docker system prune -a
|
|||
Automated backups are created before each production deployment.
|
||||
|
||||
**Manual backup**:
|
||||
|
||||
```bash
|
||||
# Create backup
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
|
|
@ -563,6 +585,7 @@ Set up external monitoring tools to ping health endpoints:
|
|||
- Chat Backend: `https://api.manacore.app/api/health`
|
||||
|
||||
Recommended tools:
|
||||
|
||||
- UptimeRobot
|
||||
- Pingdom
|
||||
- Better Uptime
|
||||
|
|
@ -575,6 +598,7 @@ Recommended tools:
|
|||
**Issue**: Deployment workflow fails
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check workflow logs in GitHub Actions
|
||||
2. Verify all required secrets are set
|
||||
3. Ensure SSH access to server works
|
||||
|
|
@ -593,6 +617,7 @@ echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin
|
|||
**Issue**: Service fails health checks after deployment
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check service logs
|
||||
2. Verify environment variables
|
||||
3. Check database connectivity
|
||||
|
|
@ -614,6 +639,7 @@ docker compose exec mana-core-auth env | grep -v PASSWORD
|
|||
**Issue**: Services can't connect to database
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Verify database is running
|
||||
2. Check connection strings
|
||||
3. Verify credentials
|
||||
|
|
@ -632,6 +658,7 @@ docker compose exec mana-core-auth nc -zv postgres 5432
|
|||
**Issue**: Docker build fails in CI
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check Dockerfile syntax
|
||||
2. Verify all COPY paths exist
|
||||
3. Check for build dependency issues
|
||||
|
|
@ -650,6 +677,7 @@ docker buildx build --progress=plain --file apps/chat/apps/backend/Dockerfile .
|
|||
**Issue**: Server runs out of disk space
|
||||
|
||||
**Solutions**:
|
||||
|
||||
```bash
|
||||
# Check disk usage
|
||||
df -h
|
||||
|
|
@ -670,6 +698,7 @@ ls -t | tail -n +10 | xargs rm -rf
|
|||
**Issue**: Docker Compose services fail to start
|
||||
|
||||
**Solutions**:
|
||||
|
||||
```bash
|
||||
# Check service dependencies
|
||||
docker compose config
|
||||
|
|
@ -692,6 +721,7 @@ Never deploy directly to production without testing in staging.
|
|||
### 2. Use Tagged Releases
|
||||
|
||||
Tag important releases:
|
||||
|
||||
```bash
|
||||
git tag -a v1.2.3 -m "Release version 1.2.3"
|
||||
git push origin v1.2.3
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ curl -X POST http://localhost:3001/api/auth/register \
|
|||
### Step 7: Configure SSL (Coolify Auto)
|
||||
|
||||
In Coolify UI:
|
||||
|
||||
1. Navigate to: Settings → Domains
|
||||
2. Add domain: `auth.manacore.app`
|
||||
3. Enable "Auto SSL" (Let's Encrypt)
|
||||
|
|
@ -676,12 +677,12 @@ curl -f https://api-chat.manacore.app/api/health
|
|||
|
||||
### Severity Levels
|
||||
|
||||
| Severity | Description | Response Time | Escalation |
|
||||
|----------|-------------|---------------|------------|
|
||||
| **P1 - Critical** | Total service outage, data loss | Immediate | CTO + All hands |
|
||||
| **P2 - High** | Major functionality broken | < 30 min | DevOps lead + Backend team |
|
||||
| **P3 - Medium** | Partial degradation, workaround exists | < 2 hours | On-call engineer |
|
||||
| **P4 - Low** | Minor issues, no user impact | < 24 hours | Backlog |
|
||||
| Severity | Description | Response Time | Escalation |
|
||||
| ----------------- | -------------------------------------- | ------------- | -------------------------- |
|
||||
| **P1 - Critical** | Total service outage, data loss | Immediate | CTO + All hands |
|
||||
| **P2 - High** | Major functionality broken | < 30 min | DevOps lead + Backend team |
|
||||
| **P3 - Medium** | Partial degradation, workaround exists | < 2 hours | On-call engineer |
|
||||
| **P4 - Low** | Minor issues, no user impact | < 24 hours | Backlog |
|
||||
|
||||
### Incident Response Workflow
|
||||
|
||||
|
|
|
|||
|
|
@ -8,26 +8,26 @@ Das Monorepo nutzt [Turborepo](https://turbo.build/) für parallele Builds und i
|
|||
|
||||
## Globale Befehle
|
||||
|
||||
| Befehl | Beschreibung |
|
||||
|--------|--------------|
|
||||
| `pnpm dev` | Startet alle Apps (Web, Mobile, Landing, Backend) |
|
||||
| `pnpm build` | Baut alle Packages und Apps |
|
||||
| `pnpm test` | Führt alle Tests aus |
|
||||
| `pnpm lint` | Führt Linting für alle Packages aus |
|
||||
| `pnpm type-check` | TypeScript-Typprüfung für alle Packages |
|
||||
| `pnpm clean` | Bereinigt Build-Artefakte |
|
||||
| `pnpm format` | Formatiert alle Dateien mit Prettier |
|
||||
| `pnpm format:check` | Prüft Formatierung ohne Änderungen |
|
||||
| Befehl | Beschreibung |
|
||||
| ------------------- | ------------------------------------------------- |
|
||||
| `pnpm dev` | Startet alle Apps (Web, Mobile, Landing, Backend) |
|
||||
| `pnpm build` | Baut alle Packages und Apps |
|
||||
| `pnpm test` | Führt alle Tests aus |
|
||||
| `pnpm lint` | Führt Linting für alle Packages aus |
|
||||
| `pnpm type-check` | TypeScript-Typprüfung für alle Packages |
|
||||
| `pnpm clean` | Bereinigt Build-Artefakte |
|
||||
| `pnpm format` | Formatiert alle Dateien mit Prettier |
|
||||
| `pnpm format:check` | Prüft Formatierung ohne Änderungen |
|
||||
|
||||
## App-Typ Befehle
|
||||
|
||||
Diese Befehle starten alle Apps eines bestimmten Typs gleichzeitig:
|
||||
|
||||
| Befehl | Beschreibung | Apps |
|
||||
|--------|--------------|------|
|
||||
| `pnpm dev:web` | Startet alle Web-Apps | maerchenzauber, manacore, manadeck, memoro |
|
||||
| Befehl | Beschreibung | Apps |
|
||||
| ------------------ | -------------------------- | ------------------------------------------ |
|
||||
| `pnpm dev:web` | Startet alle Web-Apps | maerchenzauber, manacore, manadeck, memoro |
|
||||
| `pnpm dev:landing` | Startet alle Landing Pages | maerchenzauber, manacore, manadeck, memoro |
|
||||
| `pnpm dev:mobile` | Startet alle Mobile-Apps | maerchenzauber, manacore, manadeck, memoro |
|
||||
| `pnpm dev:mobile` | Startet alle Mobile-Apps | maerchenzauber, manacore, manadeck, memoro |
|
||||
|
||||
### Beispiel
|
||||
|
||||
|
|
@ -46,12 +46,12 @@ pnpm dev:mobile
|
|||
|
||||
Diese Befehle starten ein komplettes Projekt mit allen zugehörigen Apps und Dependencies:
|
||||
|
||||
| Befehl | Beschreibung |
|
||||
|--------|--------------|
|
||||
| Befehl | Beschreibung |
|
||||
| ------------------------- | ------------------------------------------------------ |
|
||||
| `pnpm maerchenzauber:dev` | Startet Maerchenzauber (Backend, Web, Mobile, Landing) |
|
||||
| `pnpm manacore:dev` | Startet Manacore (Web, Mobile, Landing) |
|
||||
| `pnpm manadeck:dev` | Startet Manadeck (Web, Mobile, Landing) |
|
||||
| `pnpm memoro:dev` | Startet Memoro (Web, Mobile, Landing) |
|
||||
| `pnpm manacore:dev` | Startet Manacore (Web, Mobile, Landing) |
|
||||
| `pnpm manadeck:dev` | Startet Manadeck (Web, Mobile, Landing) |
|
||||
| `pnpm memoro:dev` | Startet Memoro (Web, Mobile, Landing) |
|
||||
|
||||
## Turbo Filter
|
||||
|
||||
|
|
@ -69,38 +69,38 @@ pnpm turbo run dev --filter=manacore-web --filter=memoro-web
|
|||
|
||||
Da die Package-Namen im Monorepo unterschiedlich sind, hier eine Übersicht:
|
||||
|
||||
| Projekt | Web | Landing | Mobile | Backend |
|
||||
|---------|-----|---------|--------|---------|
|
||||
| Projekt | Web | Landing | Mobile | Backend |
|
||||
| -------------- | ------------------ | ---------------------- | --------------------- | ---------------------- |
|
||||
| maerchenzauber | `@storyteller/web` | `@storyteller/landing` | `@storyteller/mobile` | `@storyteller/backend` |
|
||||
| manacore | `manacore-web` | `manacore-landing` | `manacore` | - |
|
||||
| manadeck | `web` | `landing` | `manadeck` | - |
|
||||
| memoro | `memoro-web` | `memoro-landing` | `memoro` | - |
|
||||
| manacore | `manacore-web` | `manacore-landing` | `manacore` | - |
|
||||
| manadeck | `web` | `landing` | `manadeck` | - |
|
||||
| memoro | `memoro-web` | `memoro-landing` | `memoro` | - |
|
||||
|
||||
### Filter-Syntax
|
||||
|
||||
| Pattern | Beschreibung |
|
||||
|---------|--------------|
|
||||
| `--filter=name` | Exakte Package-Übereinstimmung |
|
||||
| `--filter=name...` | Package und alle Dependencies |
|
||||
| `--filter='@scope/*'` | Alle Packages im Scope |
|
||||
| Pattern | Beschreibung |
|
||||
| --------------------- | ------------------------------ |
|
||||
| `--filter=name` | Exakte Package-Übereinstimmung |
|
||||
| `--filter=name...` | Package und alle Dependencies |
|
||||
| `--filter='@scope/*'` | Alle Packages im Scope |
|
||||
|
||||
## Port-Zuweisungen
|
||||
|
||||
Wenn mehrere Apps gleichzeitig laufen, verwenden sie unterschiedliche Ports:
|
||||
|
||||
| App-Typ | Projekt | Standard-Port |
|
||||
|---------|---------|---------------|
|
||||
| Web | maerchenzauber | 5173 |
|
||||
| Web | manacore | 5174 |
|
||||
| Web | manadeck | 5175 |
|
||||
| Web | memoro | 5176 |
|
||||
| Landing | maerchenzauber | 4321 |
|
||||
| Landing | manacore | 4322 |
|
||||
| Landing | manadeck | 4323 |
|
||||
| Landing | memoro | 4324 |
|
||||
| Backend | maerchenzauber | 3000 |
|
||||
| App-Typ | Projekt | Standard-Port |
|
||||
| ------- | -------------- | ------------- |
|
||||
| Web | maerchenzauber | 5173 |
|
||||
| Web | manacore | 5174 |
|
||||
| Web | manadeck | 5175 |
|
||||
| Web | memoro | 5176 |
|
||||
| Landing | maerchenzauber | 4321 |
|
||||
| Landing | manacore | 4322 |
|
||||
| Landing | manadeck | 4323 |
|
||||
| Landing | memoro | 4324 |
|
||||
| Backend | maerchenzauber | 3000 |
|
||||
|
||||
*Hinweis: Die tatsächlichen Ports können je nach Konfiguration variieren.*
|
||||
_Hinweis: Die tatsächlichen Ports können je nach Konfiguration variieren._
|
||||
|
||||
## Tipps
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ Comprehensive guide for working with Docker in the manacore-monorepo.
|
|||
## Overview
|
||||
|
||||
The monorepo uses Docker for:
|
||||
|
||||
- **Development**: Local service orchestration
|
||||
- **CI/CD**: Automated builds and tests
|
||||
- **Production**: Deployment and scaling
|
||||
|
|
@ -22,6 +23,7 @@ The monorepo uses Docker for:
|
|||
### Image Strategy
|
||||
|
||||
All images use:
|
||||
|
||||
- **Multi-stage builds**: Smaller production images
|
||||
- **Alpine Linux**: Minimal base images
|
||||
- **Non-root users**: Enhanced security
|
||||
|
|
@ -37,6 +39,7 @@ Templates are located in `docker/templates/`. Use these as starting points for n
|
|||
**File**: `docker/templates/Dockerfile.nestjs`
|
||||
|
||||
**Usage**:
|
||||
|
||||
```dockerfile
|
||||
# Copy template
|
||||
cp docker/templates/Dockerfile.nestjs apps/myproject/apps/backend/Dockerfile
|
||||
|
|
@ -45,11 +48,13 @@ cp docker/templates/Dockerfile.nestjs apps/myproject/apps/backend/Dockerfile
|
|||
```
|
||||
|
||||
**Build Arguments**:
|
||||
|
||||
- `SERVICE_PATH`: Path to service (e.g., `apps/chat/apps/backend`)
|
||||
- `PORT`: Service port (default: 3000)
|
||||
- `HEALTH_PATH`: Health check endpoint (default: `/health`)
|
||||
|
||||
**Example**:
|
||||
|
||||
```bash
|
||||
docker build \
|
||||
--build-arg SERVICE_PATH=apps/chat/apps/backend \
|
||||
|
|
@ -65,12 +70,14 @@ docker build \
|
|||
**File**: `docker/templates/Dockerfile.sveltekit`
|
||||
|
||||
**Features**:
|
||||
|
||||
- SSR support
|
||||
- Environment variable injection
|
||||
- Static asset optimization
|
||||
- Health endpoint
|
||||
|
||||
**Usage**:
|
||||
|
||||
```bash
|
||||
docker build \
|
||||
--build-arg SERVICE_PATH=apps/chat/apps/web \
|
||||
|
|
@ -85,6 +92,7 @@ docker build \
|
|||
**File**: `docker/templates/Dockerfile.astro`
|
||||
|
||||
**Features**:
|
||||
|
||||
- Static site serving with Nginx
|
||||
- Gzip compression
|
||||
- Security headers
|
||||
|
|
@ -93,6 +101,7 @@ docker build \
|
|||
**Nginx Configuration**: `docker/nginx/astro.conf`
|
||||
|
||||
**Usage**:
|
||||
|
||||
```bash
|
||||
docker build \
|
||||
--build-arg SERVICE_PATH=apps/chat/apps/landing \
|
||||
|
|
@ -377,10 +386,10 @@ Configure logging drivers:
|
|||
services:
|
||||
backend:
|
||||
logging:
|
||||
driver: "json-file"
|
||||
driver: 'json-file'
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
max-size: '10m'
|
||||
max-file: '3'
|
||||
```
|
||||
|
||||
### 8. Environment Variables
|
||||
|
|
@ -408,6 +417,7 @@ services:
|
|||
**Issue**: Container exits immediately
|
||||
|
||||
**Debug**:
|
||||
|
||||
```bash
|
||||
# View container logs
|
||||
docker logs container-name
|
||||
|
|
@ -424,6 +434,7 @@ docker run -it --rm image-name sh
|
|||
**Issue**: Docker runs out of disk space
|
||||
|
||||
**Solution**:
|
||||
|
||||
```bash
|
||||
# Check disk usage
|
||||
docker system df
|
||||
|
|
@ -447,6 +458,7 @@ docker rmi $(docker images -q)
|
|||
**Issue**: Docker build fails
|
||||
|
||||
**Debug**:
|
||||
|
||||
```bash
|
||||
# Build with verbose output
|
||||
docker build --progress=plain --no-cache -t image-name .
|
||||
|
|
@ -463,6 +475,7 @@ docker build --target builder -t image-name .
|
|||
**Issue**: Containers can't communicate
|
||||
|
||||
**Debug**:
|
||||
|
||||
```bash
|
||||
# List networks
|
||||
docker network ls
|
||||
|
|
@ -482,6 +495,7 @@ docker exec container1 nslookup container2
|
|||
**Issue**: Container runs slowly
|
||||
|
||||
**Debug**:
|
||||
|
||||
```bash
|
||||
# Check resource usage
|
||||
docker stats
|
||||
|
|
@ -498,6 +512,7 @@ docker history image-name
|
|||
**Issue**: Permission denied errors
|
||||
|
||||
**Solution**:
|
||||
|
||||
```bash
|
||||
# Check file ownership
|
||||
docker exec container-name ls -la /app
|
||||
|
|
@ -512,6 +527,7 @@ USER nodejs
|
|||
**Issue**: Env vars not available in container
|
||||
|
||||
**Debug**:
|
||||
|
||||
```bash
|
||||
# Check environment
|
||||
docker exec container-name env
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ Dieses Dokument beschreibt die Migration von ManaDeck von Supabase zu einer selb
|
|||
### Tabellen
|
||||
|
||||
#### 1. `decks`
|
||||
|
||||
```sql
|
||||
CREATE TABLE decks (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
|
@ -86,6 +87,7 @@ CREATE INDEX idx_decks_is_featured ON decks(is_featured);
|
|||
```
|
||||
|
||||
#### 2. `cards`
|
||||
|
||||
```sql
|
||||
CREATE TABLE cards (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
|
@ -107,6 +109,7 @@ CREATE INDEX idx_cards_position ON cards(deck_id, position);
|
|||
```
|
||||
|
||||
#### 3. `study_sessions`
|
||||
|
||||
```sql
|
||||
CREATE TABLE study_sessions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
|
@ -126,6 +129,7 @@ CREATE INDEX idx_study_sessions_deck_id ON study_sessions(deck_id);
|
|||
```
|
||||
|
||||
#### 4. `card_progress`
|
||||
|
||||
```sql
|
||||
CREATE TABLE card_progress (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
|
@ -147,6 +151,7 @@ CREATE INDEX idx_card_progress_next_review ON card_progress(next_review);
|
|||
```
|
||||
|
||||
#### 5. `deck_templates`
|
||||
|
||||
```sql
|
||||
CREATE TABLE deck_templates (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
|
@ -166,6 +171,7 @@ CREATE INDEX idx_deck_templates_is_active ON deck_templates(is_active);
|
|||
```
|
||||
|
||||
#### 6. `ai_generations`
|
||||
|
||||
```sql
|
||||
CREATE TABLE ai_generations (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
|
@ -185,6 +191,7 @@ CREATE INDEX idx_ai_generations_status ON ai_generations(status);
|
|||
```
|
||||
|
||||
#### 7. `user_stats` (für Leaderboard)
|
||||
|
||||
```sql
|
||||
CREATE TABLE user_stats (
|
||||
user_id UUID PRIMARY KEY,
|
||||
|
|
@ -233,23 +240,24 @@ manadeck/
|
|||
### Schema-Definitionen (Drizzle)
|
||||
|
||||
#### `schema/decks.ts`
|
||||
|
||||
```typescript
|
||||
import { pgTable, uuid, varchar, text, boolean, timestamp, jsonb } from 'drizzle-orm/pg-core';
|
||||
|
||||
export const decks = pgTable('decks', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').notNull(),
|
||||
title: varchar('title', { length: 255 }).notNull(),
|
||||
description: text('description'),
|
||||
coverImageUrl: text('cover_image_url'),
|
||||
isPublic: boolean('is_public').default(false),
|
||||
isFeatured: boolean('is_featured').default(false),
|
||||
featuredAt: timestamp('featured_at', { withTimezone: true }),
|
||||
settings: jsonb('settings').default({}),
|
||||
tags: text('tags').array().default([]),
|
||||
metadata: jsonb('metadata').default({}),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').notNull(),
|
||||
title: varchar('title', { length: 255 }).notNull(),
|
||||
description: text('description'),
|
||||
coverImageUrl: text('cover_image_url'),
|
||||
isPublic: boolean('is_public').default(false),
|
||||
isFeatured: boolean('is_featured').default(false),
|
||||
featuredAt: timestamp('featured_at', { withTimezone: true }),
|
||||
settings: jsonb('settings').default({}),
|
||||
tags: text('tags').array().default([]),
|
||||
metadata: jsonb('metadata').default({}),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),
|
||||
});
|
||||
|
||||
export type Deck = typeof decks.$inferSelect;
|
||||
|
|
@ -257,25 +265,37 @@ export type NewDeck = typeof decks.$inferInsert;
|
|||
```
|
||||
|
||||
#### `schema/cards.ts`
|
||||
|
||||
```typescript
|
||||
import { pgTable, uuid, varchar, text, integer, boolean, timestamp, jsonb } from 'drizzle-orm/pg-core';
|
||||
import {
|
||||
pgTable,
|
||||
uuid,
|
||||
varchar,
|
||||
text,
|
||||
integer,
|
||||
boolean,
|
||||
timestamp,
|
||||
jsonb,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
import { decks } from './decks';
|
||||
|
||||
export const cardTypeEnum = pgEnum('card_type', ['text', 'flashcard', 'quiz', 'mixed']);
|
||||
|
||||
export const cards = pgTable('cards', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
deckId: uuid('deck_id').notNull().references(() => decks.id, { onDelete: 'cascade' }),
|
||||
position: integer('position').notNull().default(0),
|
||||
title: varchar('title', { length: 255 }),
|
||||
content: jsonb('content').notNull(),
|
||||
cardType: cardTypeEnum('card_type').notNull(),
|
||||
aiModel: varchar('ai_model', { length: 100 }),
|
||||
aiPrompt: text('ai_prompt'),
|
||||
version: integer('version').default(1),
|
||||
isFavorite: boolean('is_favorite').default(false),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
deckId: uuid('deck_id')
|
||||
.notNull()
|
||||
.references(() => decks.id, { onDelete: 'cascade' }),
|
||||
position: integer('position').notNull().default(0),
|
||||
title: varchar('title', { length: 255 }),
|
||||
content: jsonb('content').notNull(),
|
||||
cardType: cardTypeEnum('card_type').notNull(),
|
||||
aiModel: varchar('ai_model', { length: 100 }),
|
||||
aiPrompt: text('ai_prompt'),
|
||||
version: integer('version').default(1),
|
||||
isFavorite: boolean('is_favorite').default(false),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),
|
||||
});
|
||||
|
||||
export type Card = typeof cards.$inferSelect;
|
||||
|
|
@ -283,6 +303,7 @@ export type NewCard = typeof cards.$inferInsert;
|
|||
```
|
||||
|
||||
#### `schema/index.ts`
|
||||
|
||||
```typescript
|
||||
export * from './decks';
|
||||
export * from './cards';
|
||||
|
|
@ -300,6 +321,7 @@ export { cardsRelations } from './cards';
|
|||
### Client Setup
|
||||
|
||||
#### `client.ts`
|
||||
|
||||
```typescript
|
||||
import { drizzle } from 'drizzle-orm/postgres-js';
|
||||
import postgres from 'postgres';
|
||||
|
|
@ -309,9 +331,9 @@ const connectionString = process.env.DATABASE_URL!;
|
|||
|
||||
// For connection pooling in serverless environments
|
||||
const client = postgres(connectionString, {
|
||||
max: 10,
|
||||
idle_timeout: 20,
|
||||
connect_timeout: 10,
|
||||
max: 10,
|
||||
idle_timeout: 20,
|
||||
connect_timeout: 10,
|
||||
});
|
||||
|
||||
export const db = drizzle(client, { schema });
|
||||
|
|
@ -325,6 +347,7 @@ export type Database = typeof db;
|
|||
### Phase 1: Setup (Tag 1-2)
|
||||
|
||||
#### 1.1 PostgreSQL Server aufsetzen
|
||||
|
||||
```bash
|
||||
# Option A: Railway.app (empfohlen für Staging)
|
||||
# Erstelle neues Projekt auf railway.app
|
||||
|
|
@ -344,6 +367,7 @@ docker run -d \
|
|||
```
|
||||
|
||||
#### 1.2 Database Package erstellen
|
||||
|
||||
```bash
|
||||
cd /Users/tillschneider/Documents/__00__Code/manacore-monorepo
|
||||
mkdir -p packages/manadeck-database
|
||||
|
|
@ -352,6 +376,7 @@ pnpm init
|
|||
```
|
||||
|
||||
#### 1.3 Dependencies installieren
|
||||
|
||||
```bash
|
||||
pnpm add drizzle-orm postgres
|
||||
pnpm add -D drizzle-kit typescript @types/node
|
||||
|
|
@ -360,17 +385,20 @@ pnpm add -D drizzle-kit typescript @types/node
|
|||
### Phase 2: Schema & Migration (Tag 2-3)
|
||||
|
||||
#### 2.1 Drizzle Schema erstellen
|
||||
|
||||
- Alle Tabellen wie oben definiert
|
||||
- Relations definieren
|
||||
- Indexes definieren
|
||||
|
||||
#### 2.2 Initial Migration generieren
|
||||
|
||||
```bash
|
||||
pnpm drizzle-kit generate
|
||||
pnpm drizzle-kit migrate
|
||||
```
|
||||
|
||||
#### 2.3 Daten von Supabase exportieren
|
||||
|
||||
```bash
|
||||
# In Supabase Dashboard: SQL Editor
|
||||
# Export alle Tabellen als CSV oder pg_dump
|
||||
|
|
@ -401,56 +429,54 @@ import { decks, cards } from '@manadeck/database/schema';
|
|||
import { eq, and, or, desc } from 'drizzle-orm';
|
||||
|
||||
export class DeckRepository {
|
||||
async findAllByUser(userId: string) {
|
||||
return db.query.decks.findMany({
|
||||
where: eq(decks.userId, userId),
|
||||
orderBy: desc(decks.updatedAt),
|
||||
with: {
|
||||
cards: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async findAllByUser(userId: string) {
|
||||
return db.query.decks.findMany({
|
||||
where: eq(decks.userId, userId),
|
||||
orderBy: desc(decks.updatedAt),
|
||||
with: {
|
||||
cards: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async findById(id: string) {
|
||||
return db.query.decks.findFirst({
|
||||
where: eq(decks.id, id),
|
||||
with: {
|
||||
cards: {
|
||||
orderBy: (cards, { asc }) => [asc(cards.position)],
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async findById(id: string) {
|
||||
return db.query.decks.findFirst({
|
||||
where: eq(decks.id, id),
|
||||
with: {
|
||||
cards: {
|
||||
orderBy: (cards, { asc }) => [asc(cards.position)],
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async findPublicAndUserDecks(userId: string) {
|
||||
return db.query.decks.findMany({
|
||||
where: or(
|
||||
eq(decks.userId, userId),
|
||||
and(eq(decks.isPublic, true), eq(decks.isFeatured, true))
|
||||
),
|
||||
orderBy: desc(decks.updatedAt),
|
||||
});
|
||||
}
|
||||
async findPublicAndUserDecks(userId: string) {
|
||||
return db.query.decks.findMany({
|
||||
where: or(
|
||||
eq(decks.userId, userId),
|
||||
and(eq(decks.isPublic, true), eq(decks.isFeatured, true))
|
||||
),
|
||||
orderBy: desc(decks.updatedAt),
|
||||
});
|
||||
}
|
||||
|
||||
async create(data: NewDeck) {
|
||||
const [deck] = await db.insert(decks).values(data).returning();
|
||||
return deck;
|
||||
}
|
||||
async create(data: NewDeck) {
|
||||
const [deck] = await db.insert(decks).values(data).returning();
|
||||
return deck;
|
||||
}
|
||||
|
||||
async update(id: string, userId: string, data: Partial<NewDeck>) {
|
||||
const [deck] = await db
|
||||
.update(decks)
|
||||
.set({ ...data, updatedAt: new Date() })
|
||||
.where(and(eq(decks.id, id), eq(decks.userId, userId)))
|
||||
.returning();
|
||||
return deck;
|
||||
}
|
||||
async update(id: string, userId: string, data: Partial<NewDeck>) {
|
||||
const [deck] = await db
|
||||
.update(decks)
|
||||
.set({ ...data, updatedAt: new Date() })
|
||||
.where(and(eq(decks.id, id), eq(decks.userId, userId)))
|
||||
.returning();
|
||||
return deck;
|
||||
}
|
||||
|
||||
async delete(id: string, userId: string) {
|
||||
await db
|
||||
.delete(decks)
|
||||
.where(and(eq(decks.id, id), eq(decks.userId, userId)));
|
||||
}
|
||||
async delete(id: string, userId: string) {
|
||||
await db.delete(decks).where(and(eq(decks.id, id), eq(decks.userId, userId)));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -461,30 +487,30 @@ export class DeckRepository {
|
|||
import { DeckRepository } from '../repositories/deck.repository';
|
||||
|
||||
export class DeckService {
|
||||
constructor(private deckRepo = new DeckRepository()) {}
|
||||
constructor(private deckRepo = new DeckRepository()) {}
|
||||
|
||||
async getUserDecks(userId: string) {
|
||||
return this.deckRepo.findPublicAndUserDecks(userId);
|
||||
}
|
||||
async getUserDecks(userId: string) {
|
||||
return this.deckRepo.findPublicAndUserDecks(userId);
|
||||
}
|
||||
|
||||
async getDeck(id: string) {
|
||||
return this.deckRepo.findById(id);
|
||||
}
|
||||
async getDeck(id: string) {
|
||||
return this.deckRepo.findById(id);
|
||||
}
|
||||
|
||||
async createDeck(userId: string, data: CreateDeckInput) {
|
||||
return this.deckRepo.create({
|
||||
...data,
|
||||
userId,
|
||||
});
|
||||
}
|
||||
async createDeck(userId: string, data: CreateDeckInput) {
|
||||
return this.deckRepo.create({
|
||||
...data,
|
||||
userId,
|
||||
});
|
||||
}
|
||||
|
||||
async updateDeck(id: string, userId: string, data: UpdateDeckInput) {
|
||||
return this.deckRepo.update(id, userId, data);
|
||||
}
|
||||
async updateDeck(id: string, userId: string, data: UpdateDeckInput) {
|
||||
return this.deckRepo.update(id, userId, data);
|
||||
}
|
||||
|
||||
async deleteDeck(id: string, userId: string) {
|
||||
return this.deckRepo.delete(id, userId);
|
||||
}
|
||||
async deleteDeck(id: string, userId: string) {
|
||||
return this.deckRepo.delete(id, userId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -498,37 +524,33 @@ import { getToken } from '$lib/auth';
|
|||
|
||||
const API_URL = import.meta.env.VITE_API_URL;
|
||||
|
||||
async function fetchApi<T>(
|
||||
endpoint: string,
|
||||
options: RequestInit = {}
|
||||
): Promise<T> {
|
||||
const token = getToken();
|
||||
async function fetchApi<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
|
||||
const token = getToken();
|
||||
|
||||
const response = await fetch(`${API_URL}${endpoint}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token && { Authorization: `Bearer ${token}` }),
|
||||
...options.headers,
|
||||
},
|
||||
});
|
||||
const response = await fetch(`${API_URL}${endpoint}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token && { Authorization: `Bearer ${token}` }),
|
||||
...options.headers,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.message || 'API Error');
|
||||
}
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.message || 'API Error');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export const api = {
|
||||
get: <T>(endpoint: string) => fetchApi<T>(endpoint),
|
||||
post: <T>(endpoint: string, data: unknown) =>
|
||||
fetchApi<T>(endpoint, { method: 'POST', body: JSON.stringify(data) }),
|
||||
put: <T>(endpoint: string, data: unknown) =>
|
||||
fetchApi<T>(endpoint, { method: 'PUT', body: JSON.stringify(data) }),
|
||||
delete: <T>(endpoint: string) =>
|
||||
fetchApi<T>(endpoint, { method: 'DELETE' }),
|
||||
get: <T>(endpoint: string) => fetchApi<T>(endpoint),
|
||||
post: <T>(endpoint: string, data: unknown) =>
|
||||
fetchApi<T>(endpoint, { method: 'POST', body: JSON.stringify(data) }),
|
||||
put: <T>(endpoint: string, data: unknown) =>
|
||||
fetchApi<T>(endpoint, { method: 'PUT', body: JSON.stringify(data) }),
|
||||
delete: <T>(endpoint: string) => fetchApi<T>(endpoint, { method: 'DELETE' }),
|
||||
};
|
||||
```
|
||||
|
||||
|
|
@ -540,87 +562,95 @@ import { api } from '$lib/api/client';
|
|||
import type { Deck, CreateDeckInput, UpdateDeckInput } from '$lib/types/deck';
|
||||
|
||||
function createDeckStore() {
|
||||
let decks = $state<Deck[]>([]);
|
||||
let currentDeck = $state<Deck | null>(null);
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let decks = $state<Deck[]>([]);
|
||||
let currentDeck = $state<Deck | null>(null);
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
return {
|
||||
get decks() { return decks; },
|
||||
get currentDeck() { return currentDeck; },
|
||||
get loading() { return loading; },
|
||||
get error() { return error; },
|
||||
return {
|
||||
get decks() {
|
||||
return decks;
|
||||
},
|
||||
get currentDeck() {
|
||||
return currentDeck;
|
||||
},
|
||||
get loading() {
|
||||
return loading;
|
||||
},
|
||||
get error() {
|
||||
return error;
|
||||
},
|
||||
|
||||
async fetchDecks() {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
decks = await api.get<Deck[]>('/api/decks');
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'Failed to fetch decks';
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
},
|
||||
async fetchDecks() {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
decks = await api.get<Deck[]>('/api/decks');
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'Failed to fetch decks';
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async fetchDeck(id: string) {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
currentDeck = await api.get<Deck>(`/api/decks/${id}`);
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'Failed to fetch deck';
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
},
|
||||
async fetchDeck(id: string) {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
currentDeck = await api.get<Deck>(`/api/decks/${id}`);
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'Failed to fetch deck';
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async createDeck(data: CreateDeckInput) {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
const deck = await api.post<Deck>('/api/decks', data);
|
||||
decks = [deck, ...decks];
|
||||
return deck;
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'Failed to create deck';
|
||||
throw e;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
},
|
||||
async createDeck(data: CreateDeckInput) {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
const deck = await api.post<Deck>('/api/decks', data);
|
||||
decks = [deck, ...decks];
|
||||
return deck;
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'Failed to create deck';
|
||||
throw e;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async updateDeck(id: string, data: UpdateDeckInput) {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
const deck = await api.put<Deck>(`/api/decks/${id}`, data);
|
||||
decks = decks.map(d => d.id === id ? deck : d);
|
||||
if (currentDeck?.id === id) currentDeck = deck;
|
||||
return deck;
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'Failed to update deck';
|
||||
throw e;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
},
|
||||
async updateDeck(id: string, data: UpdateDeckInput) {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
const deck = await api.put<Deck>(`/api/decks/${id}`, data);
|
||||
decks = decks.map((d) => (d.id === id ? deck : d));
|
||||
if (currentDeck?.id === id) currentDeck = deck;
|
||||
return deck;
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'Failed to update deck';
|
||||
throw e;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async deleteDeck(id: string) {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
await api.delete(`/api/decks/${id}`);
|
||||
decks = decks.filter(d => d.id !== id);
|
||||
if (currentDeck?.id === id) currentDeck = null;
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'Failed to delete deck';
|
||||
throw e;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
},
|
||||
};
|
||||
async deleteDeck(id: string) {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
await api.delete(`/api/decks/${id}`);
|
||||
decks = decks.filter((d) => d.id !== id);
|
||||
if (currentDeck?.id === id) currentDeck = null;
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'Failed to delete deck';
|
||||
throw e;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const deckStore = createDeckStore();
|
||||
|
|
@ -629,6 +659,7 @@ export const deckStore = createDeckStore();
|
|||
### Phase 5: Testing & Cutover (Tag 7-10)
|
||||
|
||||
#### 5.1 Integration Tests
|
||||
|
||||
```typescript
|
||||
// tests/deck.integration.test.ts
|
||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||
|
|
@ -637,111 +668,111 @@ import { decks } from '@manadeck/database/schema';
|
|||
import { DeckService } from '../services/deck.service';
|
||||
|
||||
describe('DeckService', () => {
|
||||
const service = new DeckService();
|
||||
const testUserId = 'test-user-id';
|
||||
const service = new DeckService();
|
||||
const testUserId = 'test-user-id';
|
||||
|
||||
afterAll(async () => {
|
||||
await db.delete(decks).where(eq(decks.userId, testUserId));
|
||||
});
|
||||
afterAll(async () => {
|
||||
await db.delete(decks).where(eq(decks.userId, testUserId));
|
||||
});
|
||||
|
||||
it('should create a deck', async () => {
|
||||
const deck = await service.createDeck(testUserId, {
|
||||
title: 'Test Deck',
|
||||
description: 'A test deck',
|
||||
});
|
||||
it('should create a deck', async () => {
|
||||
const deck = await service.createDeck(testUserId, {
|
||||
title: 'Test Deck',
|
||||
description: 'A test deck',
|
||||
});
|
||||
|
||||
expect(deck.id).toBeDefined();
|
||||
expect(deck.title).toBe('Test Deck');
|
||||
});
|
||||
expect(deck.id).toBeDefined();
|
||||
expect(deck.title).toBe('Test Deck');
|
||||
});
|
||||
|
||||
it('should fetch user decks', async () => {
|
||||
const userDecks = await service.getUserDecks(testUserId);
|
||||
expect(userDecks.length).toBeGreaterThan(0);
|
||||
});
|
||||
it('should fetch user decks', async () => {
|
||||
const userDecks = await service.getUserDecks(testUserId);
|
||||
expect(userDecks.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### 5.2 Datenmigrations-Script
|
||||
|
||||
```typescript
|
||||
// scripts/migrate-data.ts
|
||||
import { db as newDb } from '@manadeck/database';
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import { decks, cards } from '@manadeck/database/schema';
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_KEY!
|
||||
);
|
||||
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_KEY!);
|
||||
|
||||
async function migrateDecks() {
|
||||
console.log('Migrating decks...');
|
||||
console.log('Migrating decks...');
|
||||
|
||||
const { data: supabaseDecks, error } = await supabase
|
||||
.from('decks')
|
||||
.select('*');
|
||||
const { data: supabaseDecks, error } = await supabase.from('decks').select('*');
|
||||
|
||||
if (error) throw error;
|
||||
if (error) throw error;
|
||||
|
||||
for (const deck of supabaseDecks) {
|
||||
await newDb.insert(decks).values({
|
||||
id: deck.id,
|
||||
userId: deck.user_id,
|
||||
title: deck.title,
|
||||
description: deck.description,
|
||||
coverImageUrl: deck.cover_image_url,
|
||||
isPublic: deck.is_public,
|
||||
isFeatured: deck.is_featured,
|
||||
featuredAt: deck.featured_at,
|
||||
settings: deck.settings,
|
||||
tags: deck.tags,
|
||||
metadata: deck.metadata,
|
||||
createdAt: deck.created_at,
|
||||
updatedAt: deck.updated_at,
|
||||
}).onConflictDoNothing();
|
||||
}
|
||||
for (const deck of supabaseDecks) {
|
||||
await newDb
|
||||
.insert(decks)
|
||||
.values({
|
||||
id: deck.id,
|
||||
userId: deck.user_id,
|
||||
title: deck.title,
|
||||
description: deck.description,
|
||||
coverImageUrl: deck.cover_image_url,
|
||||
isPublic: deck.is_public,
|
||||
isFeatured: deck.is_featured,
|
||||
featuredAt: deck.featured_at,
|
||||
settings: deck.settings,
|
||||
tags: deck.tags,
|
||||
metadata: deck.metadata,
|
||||
createdAt: deck.created_at,
|
||||
updatedAt: deck.updated_at,
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
}
|
||||
|
||||
console.log(`Migrated ${supabaseDecks.length} decks`);
|
||||
console.log(`Migrated ${supabaseDecks.length} decks`);
|
||||
}
|
||||
|
||||
async function migrateCards() {
|
||||
console.log('Migrating cards...');
|
||||
console.log('Migrating cards...');
|
||||
|
||||
const { data: supabaseCards, error } = await supabase
|
||||
.from('cards')
|
||||
.select('*');
|
||||
const { data: supabaseCards, error } = await supabase.from('cards').select('*');
|
||||
|
||||
if (error) throw error;
|
||||
if (error) throw error;
|
||||
|
||||
for (const card of supabaseCards) {
|
||||
await newDb.insert(cards).values({
|
||||
id: card.id,
|
||||
deckId: card.deck_id,
|
||||
position: card.position,
|
||||
title: card.title,
|
||||
content: card.content,
|
||||
cardType: card.card_type,
|
||||
aiModel: card.ai_model,
|
||||
aiPrompt: card.ai_prompt,
|
||||
version: card.version,
|
||||
isFavorite: card.is_favorite,
|
||||
createdAt: card.created_at,
|
||||
updatedAt: card.updated_at,
|
||||
}).onConflictDoNothing();
|
||||
}
|
||||
for (const card of supabaseCards) {
|
||||
await newDb
|
||||
.insert(cards)
|
||||
.values({
|
||||
id: card.id,
|
||||
deckId: card.deck_id,
|
||||
position: card.position,
|
||||
title: card.title,
|
||||
content: card.content,
|
||||
cardType: card.card_type,
|
||||
aiModel: card.ai_model,
|
||||
aiPrompt: card.ai_prompt,
|
||||
version: card.version,
|
||||
isFavorite: card.is_favorite,
|
||||
createdAt: card.created_at,
|
||||
updatedAt: card.updated_at,
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
}
|
||||
|
||||
console.log(`Migrated ${supabaseCards.length} cards`);
|
||||
console.log(`Migrated ${supabaseCards.length} cards`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await migrateDecks();
|
||||
await migrateCards();
|
||||
// ... andere Tabellen
|
||||
console.log('Migration completed successfully!');
|
||||
} catch (error) {
|
||||
console.error('Migration failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
try {
|
||||
await migrateDecks();
|
||||
await migrateCards();
|
||||
// ... andere Tabellen
|
||||
console.log('Migration completed successfully!');
|
||||
} catch (error) {
|
||||
console.error('Migration failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
@ -751,13 +782,13 @@ main();
|
|||
|
||||
## Zeitplan
|
||||
|
||||
| Phase | Beschreibung | Dauer | Status |
|
||||
|-------|--------------|-------|--------|
|
||||
| 1 | Setup (PostgreSQL, Package) | 1-2 Tage | ⬜ Pending |
|
||||
| 2 | Schema & Migration | 1-2 Tage | ⬜ Pending |
|
||||
| 3 | Backend Migration | 2-3 Tage | ⬜ Pending |
|
||||
| 4 | Frontend Migration | 2-3 Tage | ⬜ Pending |
|
||||
| 5 | Testing & Cutover | 2-3 Tage | ⬜ Pending |
|
||||
| Phase | Beschreibung | Dauer | Status |
|
||||
| ----- | --------------------------- | -------- | ---------- |
|
||||
| 1 | Setup (PostgreSQL, Package) | 1-2 Tage | ⬜ Pending |
|
||||
| 2 | Schema & Migration | 1-2 Tage | ⬜ Pending |
|
||||
| 3 | Backend Migration | 2-3 Tage | ⬜ Pending |
|
||||
| 4 | Frontend Migration | 2-3 Tage | ⬜ Pending |
|
||||
| 5 | Testing & Cutover | 2-3 Tage | ⬜ Pending |
|
||||
|
||||
**Gesamtdauer: ~10-13 Tage**
|
||||
|
||||
|
|
@ -766,6 +797,7 @@ main();
|
|||
## Checkliste
|
||||
|
||||
### Pre-Migration
|
||||
|
||||
- [ ] PostgreSQL Server aufgesetzt
|
||||
- [ ] Database Package erstellt
|
||||
- [ ] Drizzle Schema definiert
|
||||
|
|
@ -773,6 +805,7 @@ main();
|
|||
- [ ] Supabase Daten exportiert
|
||||
|
||||
### Backend
|
||||
|
||||
- [ ] Repository Pattern implementiert
|
||||
- [ ] DeckRepository
|
||||
- [ ] CardRepository
|
||||
|
|
@ -786,18 +819,21 @@ main();
|
|||
- [ ] Authorization Middleware (ersetzt RLS)
|
||||
|
||||
### Frontend
|
||||
|
||||
- [ ] API Client erstellt
|
||||
- [ ] deckStore migriert
|
||||
- [ ] Supabase imports entfernt
|
||||
- [ ] Environment Variables aktualisiert
|
||||
|
||||
### Testing
|
||||
|
||||
- [ ] Unit Tests für Repositories
|
||||
- [ ] Integration Tests für Services
|
||||
- [ ] E2E Tests für API
|
||||
- [ ] Manual Testing aller Features
|
||||
|
||||
### Cutover
|
||||
|
||||
- [ ] Daten migriert (Script ausgeführt)
|
||||
- [ ] DNS/Environment umgestellt
|
||||
- [ ] Rollback Plan dokumentiert
|
||||
|
|
@ -819,12 +855,12 @@ Supabase-Daten bleiben während der Migration unberührt.
|
|||
|
||||
## Kosten nach Migration
|
||||
|
||||
| Service | Geschätzte Kosten |
|
||||
|---------|-------------------|
|
||||
| PostgreSQL (Railway) | ~$5-20/Monat |
|
||||
| PostgreSQL (Neon Free) | $0/Monat |
|
||||
| Backup (optional) | ~$5/Monat |
|
||||
| **Gesamt** | **$5-25/Monat** |
|
||||
| Service | Geschätzte Kosten |
|
||||
| ---------------------- | ----------------- |
|
||||
| PostgreSQL (Railway) | ~$5-20/Monat |
|
||||
| PostgreSQL (Neon Free) | $0/Monat |
|
||||
| Backup (optional) | ~$5/Monat |
|
||||
| **Gesamt** | **$5-25/Monat** |
|
||||
|
||||
vs. Supabase Pro: $25-300/Monat
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ pnpm run nutriphi:dev
|
|||
Maerchenzauber ist eine magische Geschichten-App für Kinder, die mithilfe von KI personalisierte Geschichten mit benutzerdefinierten Charakteren erstellt.
|
||||
|
||||
#### Features
|
||||
|
||||
- KI-gestützte Geschichtenerstellung mit konsistenten Charakteren
|
||||
- Benutzerdefinierte Charaktergenerierung aus Beschreibungen oder Fotos
|
||||
- Mehrseitige illustrierte Geschichten (10 Seiten)
|
||||
|
|
@ -72,17 +73,19 @@ Maerchenzauber ist eine magische Geschichten-App für Kinder, die mithilfe von K
|
|||
- System-Charaktere (z.B. "Finia" der weise Fuchs)
|
||||
|
||||
#### Tech-Stack
|
||||
| Komponente | Technologie |
|
||||
|------------|-------------|
|
||||
| Backend | NestJS (Port 3002) |
|
||||
| Mobile | React Native + Expo |
|
||||
| Web | SvelteKit |
|
||||
| Landing | Astro |
|
||||
| KI | Azure OpenAI (GPT-4), Google Gemini, Replicate (Flux) |
|
||||
| Datenbank | Supabase (PostgreSQL) |
|
||||
| Storage | Supabase Storage |
|
||||
|
||||
| Komponente | Technologie |
|
||||
| ---------- | ----------------------------------------------------- |
|
||||
| Backend | NestJS (Port 3002) |
|
||||
| Mobile | React Native + Expo |
|
||||
| Web | SvelteKit |
|
||||
| Landing | Astro |
|
||||
| KI | Azure OpenAI (GPT-4), Google Gemini, Replicate (Flux) |
|
||||
| Datenbank | Supabase (PostgreSQL) |
|
||||
| Storage | Supabase Storage |
|
||||
|
||||
#### Projektstruktur
|
||||
|
||||
```
|
||||
maerchenzauber/
|
||||
├── apps/
|
||||
|
|
@ -93,6 +96,7 @@ maerchenzauber/
|
|||
```
|
||||
|
||||
#### Entwicklung
|
||||
|
||||
```bash
|
||||
# Backend starten
|
||||
cd maerchenzauber/apps/backend && npm run dev
|
||||
|
|
@ -113,6 +117,7 @@ cd maerchenzauber/apps/web && npm run dev
|
|||
Manacore ist die zentrale Plattform für Organisations-Management, Team-Kollaboration und Credit-Transfers. Es dient als Authentifizierungs-Hub für alle anderen Anwendungen.
|
||||
|
||||
#### Features
|
||||
|
||||
- Einheitliche Authentifizierung mit Supabase
|
||||
- Organisations-Management mit rollenbasiertem Zugriff
|
||||
- Team-Kollaboration und Mitgliederverwaltung
|
||||
|
|
@ -122,21 +127,24 @@ Manacore ist die zentrale Plattform für Organisations-Management, Team-Kollabor
|
|||
- Echtzeit-Updates
|
||||
|
||||
#### Unterstützte Apps
|
||||
|
||||
- **Memoro** - Sprachaufnahmen und Memory-Management
|
||||
- **ManaDeck** - KI-gestützte Lernkarten
|
||||
- **Storyteller** - Kreatives Schreiben mit KI
|
||||
- **ManaCore** - Zentrale Account- und Organisationsverwaltung
|
||||
|
||||
#### Tech-Stack
|
||||
| Komponente | Technologie |
|
||||
|------------|-------------|
|
||||
| Web | SvelteKit 2 + Svelte 5 (Runes) |
|
||||
| Mobile | Expo 52 + React Native 0.76 |
|
||||
| Styling | TailwindCSS / NativeWind |
|
||||
| Auth | Supabase Auth mit SSR |
|
||||
| Testing | Vitest + Playwright |
|
||||
|
||||
| Komponente | Technologie |
|
||||
| ---------- | ------------------------------ |
|
||||
| Web | SvelteKit 2 + Svelte 5 (Runes) |
|
||||
| Mobile | Expo 52 + React Native 0.76 |
|
||||
| Styling | TailwindCSS / NativeWind |
|
||||
| Auth | Supabase Auth mit SSR |
|
||||
| Testing | Vitest + Playwright |
|
||||
|
||||
#### Projektstruktur
|
||||
|
||||
```
|
||||
manacore/
|
||||
├── apps/
|
||||
|
|
@ -154,6 +162,7 @@ manacore/
|
|||
Manadeck ist ein Deck-Management-System mit KI-gestützter Kartenerstellung und dem integrierten Mana Credit-System.
|
||||
|
||||
#### Features
|
||||
|
||||
- Deck-Erstellung und -Verwaltung
|
||||
- KI-gestützte Kartengenerierung
|
||||
- Credit-System Integration (10 Mana pro Deck, 2 Mana pro Karte)
|
||||
|
|
@ -161,23 +170,26 @@ Manadeck ist ein Deck-Management-System mit KI-gestützter Kartenerstellung und
|
|||
- NestJS Backend mit AuthGuard
|
||||
|
||||
#### Credit-Kosten
|
||||
| Operation | Kosten |
|
||||
|-----------|--------|
|
||||
| Deck erstellen | 10 Mana |
|
||||
| Karte erstellen | 2 Mana |
|
||||
| KI-Kartengenerierung | 5 Mana |
|
||||
| Deck exportieren | 3 Mana |
|
||||
|
||||
| Operation | Kosten |
|
||||
| -------------------- | ------- |
|
||||
| Deck erstellen | 10 Mana |
|
||||
| Karte erstellen | 2 Mana |
|
||||
| KI-Kartengenerierung | 5 Mana |
|
||||
| Deck exportieren | 3 Mana |
|
||||
|
||||
#### Tech-Stack
|
||||
| Komponente | Technologie |
|
||||
|------------|-------------|
|
||||
| Backend | NestJS (Port 8080) |
|
||||
| Mobile | React Native + Expo |
|
||||
| Web | SvelteKit |
|
||||
| Landing | Astro |
|
||||
| Datenbank | Supabase |
|
||||
|
||||
| Komponente | Technologie |
|
||||
| ---------- | ------------------- |
|
||||
| Backend | NestJS (Port 8080) |
|
||||
| Mobile | React Native + Expo |
|
||||
| Web | SvelteKit |
|
||||
| Landing | Astro |
|
||||
| Datenbank | Supabase |
|
||||
|
||||
#### Projektstruktur
|
||||
|
||||
```
|
||||
manadeck/
|
||||
├── backend/ # NestJS API Server
|
||||
|
|
@ -196,6 +208,7 @@ manadeck/
|
|||
Memoro transformiert Audio-Aufnahmen in strukturierte, durchsuchbare Inhalte mithilfe von KI. Ideal für Meetings, Interviews, Vorlesungen oder persönliche Notizen.
|
||||
|
||||
#### Features
|
||||
|
||||
- Hochwertige Audio-Aufnahme (Hintergrundaufnahme mit Pause/Resume)
|
||||
- KI-gestützte Analyse (Blueprints und Prompts)
|
||||
- Kollaborative Spaces für Teams
|
||||
|
|
@ -205,17 +218,19 @@ Memoro transformiert Audio-Aufnahmen in strukturierte, durchsuchbare Inhalte mit
|
|||
- Enterprise-Security mit Row-Level Security
|
||||
|
||||
#### Tech-Stack
|
||||
| Komponente | Technologie |
|
||||
|------------|-------------|
|
||||
| Mobile | React Native 0.81.4 + Expo SDK 54 |
|
||||
| Web | SvelteKit 2.x |
|
||||
| Audio | expo-audio, Azure Speech Services |
|
||||
| State | Zustand |
|
||||
| Payments | RevenueCat |
|
||||
| Analytics | PostHog, Sentry |
|
||||
| i18n | react-i18next (32 Sprachen) |
|
||||
|
||||
| Komponente | Technologie |
|
||||
| ---------- | --------------------------------- |
|
||||
| Mobile | React Native 0.81.4 + Expo SDK 54 |
|
||||
| Web | SvelteKit 2.x |
|
||||
| Audio | expo-audio, Azure Speech Services |
|
||||
| State | Zustand |
|
||||
| Payments | RevenueCat |
|
||||
| Analytics | PostHog, Sentry |
|
||||
| i18n | react-i18next (32 Sprachen) |
|
||||
|
||||
#### Projektstruktur
|
||||
|
||||
```
|
||||
memoro/
|
||||
├── apps/
|
||||
|
|
@ -227,6 +242,7 @@ memoro/
|
|||
```
|
||||
|
||||
#### Feature-Module
|
||||
|
||||
- auth, audioRecordingV2, memos, spaces, credits
|
||||
- subscription, i18n, theme, blueprints, prompts
|
||||
- und 23 weitere...
|
||||
|
|
@ -240,20 +256,23 @@ memoro/
|
|||
Picture ist eine Cross-Platform Bildbearbeitungs-Anwendung mit Canvas-basierter Bearbeitung.
|
||||
|
||||
#### Features
|
||||
|
||||
- Canvas-basierte Bildbearbeitung (Konva)
|
||||
- Cross-Platform (iOS, Android, Web)
|
||||
- Theme-System Integration
|
||||
- Subscription-Management
|
||||
|
||||
#### Tech-Stack
|
||||
| Komponente | Technologie |
|
||||
|------------|-------------|
|
||||
| Mobile | React Native + Expo SDK 54 |
|
||||
| Web | SvelteKit + Svelte 5 |
|
||||
| Canvas | Konva |
|
||||
| Styling | TailwindCSS 4.0 |
|
||||
|
||||
| Komponente | Technologie |
|
||||
| ---------- | -------------------------- |
|
||||
| Mobile | React Native + Expo SDK 54 |
|
||||
| Web | SvelteKit + Svelte 5 |
|
||||
| Canvas | Konva |
|
||||
| Styling | TailwindCSS 4.0 |
|
||||
|
||||
#### Projektstruktur
|
||||
|
||||
```
|
||||
picture/
|
||||
├── apps/
|
||||
|
|
@ -273,6 +292,7 @@ uLoad ist eine URL-Shortening und Link-Management Plattform mit umfangreichen An
|
|||
**Live:** https://ulo.ad
|
||||
|
||||
#### Features
|
||||
|
||||
- URL-Verkürzung
|
||||
- Link-Analytics und Tracking
|
||||
- Stripe-Integration für Zahlungen
|
||||
|
|
@ -280,19 +300,21 @@ uLoad ist eine URL-Shortening und Link-Management Plattform mit umfangreichen An
|
|||
- Cloudflare R2 Storage
|
||||
|
||||
#### Tech-Stack
|
||||
| Komponente | Technologie |
|
||||
|------------|-------------|
|
||||
| Framework | SvelteKit v2.22 + Svelte 5.0 |
|
||||
| Backend | PocketBase (embedded SQLite) |
|
||||
| Datenbank | PostgreSQL via Drizzle ORM |
|
||||
| Cache | Redis |
|
||||
| Styling | Tailwind CSS v4.0 |
|
||||
| Testing | Vitest + Playwright |
|
||||
| Payments | Stripe |
|
||||
| Email | Resend |
|
||||
| Storage | Cloudflare R2 |
|
||||
|
||||
| Komponente | Technologie |
|
||||
| ---------- | ---------------------------- |
|
||||
| Framework | SvelteKit v2.22 + Svelte 5.0 |
|
||||
| Backend | PocketBase (embedded SQLite) |
|
||||
| Datenbank | PostgreSQL via Drizzle ORM |
|
||||
| Cache | Redis |
|
||||
| Styling | Tailwind CSS v4.0 |
|
||||
| Testing | Vitest + Playwright |
|
||||
| Payments | Stripe |
|
||||
| Email | Resend |
|
||||
| Storage | Cloudflare R2 |
|
||||
|
||||
#### Projektstruktur
|
||||
|
||||
```
|
||||
uload/
|
||||
├── apps/
|
||||
|
|
@ -305,6 +327,7 @@ uload/
|
|||
```
|
||||
|
||||
#### Entwicklung
|
||||
|
||||
```bash
|
||||
cd uload/apps/web
|
||||
|
||||
|
|
@ -328,20 +351,23 @@ pnpm run test # Unit + E2E Tests
|
|||
Chat ist eine mobile Chat-Anwendung mit Supabase-Backend und Markdown-Unterstützung.
|
||||
|
||||
#### Features
|
||||
|
||||
- Echtzeit-Chat mit Supabase
|
||||
- Markdown-Rendering
|
||||
- Expo Router Navigation
|
||||
- NativeWind Styling
|
||||
|
||||
#### Tech-Stack
|
||||
| Komponente | Technologie |
|
||||
|------------|-------------|
|
||||
| Mobile | Expo SDK 52 + React Native 0.76.7 |
|
||||
| Navigation | Expo Router |
|
||||
| Styling | NativeWind (Tailwind CSS) |
|
||||
| Backend | Supabase |
|
||||
|
||||
| Komponente | Technologie |
|
||||
| ---------- | --------------------------------- |
|
||||
| Mobile | Expo SDK 52 + React Native 0.76.7 |
|
||||
| Navigation | Expo Router |
|
||||
| Styling | NativeWind (Tailwind CSS) |
|
||||
| Backend | Supabase |
|
||||
|
||||
#### Projektstruktur
|
||||
|
||||
```
|
||||
chat/
|
||||
├── apps/
|
||||
|
|
@ -357,6 +383,7 @@ chat/
|
|||
Nutriphi ist ein intelligenter Ernährungs-Tracker, der mithilfe von Google Gemini Vision API Fotos von Mahlzeiten analysiert und automatisch Nährwertinformationen extrahiert.
|
||||
|
||||
#### Features
|
||||
|
||||
- KI-gestützte Mahlzeitenanalyse aus Fotos
|
||||
- Automatische Erkennung von Kalorien, Protein, Kohlenhydraten, Fett
|
||||
- Tägliche Ernährungsbilanz und Statistiken
|
||||
|
|
@ -366,17 +393,19 @@ Nutriphi ist ein intelligenter Ernährungs-Tracker, der mithilfe von Google Gemi
|
|||
- Cloud-Sync mit Supabase
|
||||
|
||||
#### Tech-Stack
|
||||
| Komponente | Technologie |
|
||||
|------------|-------------|
|
||||
| Backend | NestJS (Port 3002) |
|
||||
| Mobile | Expo SDK 53 + React Native 0.79 |
|
||||
| Web | SvelteKit |
|
||||
| Landing | Astro |
|
||||
| KI | Google Gemini Vision API |
|
||||
| Datenbank | Supabase (PostgreSQL), SQLite (lokal) |
|
||||
| State | Zustand |
|
||||
|
||||
| Komponente | Technologie |
|
||||
| ---------- | ------------------------------------- |
|
||||
| Backend | NestJS (Port 3002) |
|
||||
| Mobile | Expo SDK 53 + React Native 0.79 |
|
||||
| Web | SvelteKit |
|
||||
| Landing | Astro |
|
||||
| KI | Google Gemini Vision API |
|
||||
| Datenbank | Supabase (PostgreSQL), SQLite (lokal) |
|
||||
| State | Zustand |
|
||||
|
||||
#### Projektstruktur
|
||||
|
||||
```
|
||||
nutriphi/
|
||||
├── apps/
|
||||
|
|
@ -387,16 +416,18 @@ nutriphi/
|
|||
```
|
||||
|
||||
#### API Endpoints
|
||||
| Endpoint | Methode | Beschreibung |
|
||||
|----------|---------|--------------|
|
||||
| `/api/health` | GET | Health Check |
|
||||
| `/api/meals/analyze/image` | POST | Mahlzeit-Foto analysieren |
|
||||
| `/api/meals/analyze/text` | POST | Mahlzeit-Text analysieren |
|
||||
| `/api/meals` | POST | Mahlzeit speichern |
|
||||
| `/api/meals/user/:userId` | GET | Mahlzeiten eines Users |
|
||||
| `/api/meals/user/:userId/summary` | GET | Tagesbilanz |
|
||||
|
||||
| Endpoint | Methode | Beschreibung |
|
||||
| --------------------------------- | ------- | ------------------------- |
|
||||
| `/api/health` | GET | Health Check |
|
||||
| `/api/meals/analyze/image` | POST | Mahlzeit-Foto analysieren |
|
||||
| `/api/meals/analyze/text` | POST | Mahlzeit-Text analysieren |
|
||||
| `/api/meals` | POST | Mahlzeit speichern |
|
||||
| `/api/meals/user/:userId` | GET | Mahlzeiten eines Users |
|
||||
| `/api/meals/user/:userId/summary` | GET | Tagesbilanz |
|
||||
|
||||
#### Entwicklung
|
||||
|
||||
```bash
|
||||
# Backend starten
|
||||
pnpm dev:nutriphi:backend
|
||||
|
|
@ -419,48 +450,48 @@ Alle Projekte teilen gemeinsame Packages unter `packages/`:
|
|||
|
||||
### Core Packages
|
||||
|
||||
| Package | Beschreibung |
|
||||
|---------|--------------|
|
||||
| `@manacore/shared-types` | Gemeinsame TypeScript Types |
|
||||
| `@manacore/shared-utils` | Utility-Funktionen (Date, String, Async) |
|
||||
| `@manacore/shared-supabase` | Einheitlicher Supabase Client |
|
||||
| `@manacore/shared-config` | Gemeinsame Konfiguration |
|
||||
| Package | Beschreibung |
|
||||
| --------------------------- | ---------------------------------------- |
|
||||
| `@manacore/shared-types` | Gemeinsame TypeScript Types |
|
||||
| `@manacore/shared-utils` | Utility-Funktionen (Date, String, Async) |
|
||||
| `@manacore/shared-supabase` | Einheitlicher Supabase Client |
|
||||
| `@manacore/shared-config` | Gemeinsame Konfiguration |
|
||||
|
||||
### Auth & Security
|
||||
|
||||
| Package | Beschreibung |
|
||||
|---------|--------------|
|
||||
| `@manacore/shared-auth` | Authentifizierungs-Logik |
|
||||
| `@manacore/shared-auth-ui` | Auth UI-Komponenten |
|
||||
| `@manacore/shared-auth-stores` | Auth State Stores |
|
||||
| Package | Beschreibung |
|
||||
| ------------------------------ | ------------------------ |
|
||||
| `@manacore/shared-auth` | Authentifizierungs-Logik |
|
||||
| `@manacore/shared-auth-ui` | Auth UI-Komponenten |
|
||||
| `@manacore/shared-auth-stores` | Auth State Stores |
|
||||
|
||||
### UI & Styling
|
||||
|
||||
| Package | Beschreibung |
|
||||
|---------|--------------|
|
||||
| `@manacore/shared-ui` | React Native UI-Komponenten |
|
||||
| `@manacore/shared-icons` | Icon-Library |
|
||||
| `@manacore/shared-tailwind` | Tailwind Konfiguration |
|
||||
| `@manacore/shared-theme` | Theme-Logik |
|
||||
| `@manacore/shared-theme-ui` | Theme UI-Komponenten |
|
||||
| `@manacore/shared-branding` | Branding Assets |
|
||||
| `@manacore/shared-landing-ui` | Landing Page Komponenten |
|
||||
| Package | Beschreibung |
|
||||
| ----------------------------- | --------------------------- |
|
||||
| `@manacore/shared-ui` | React Native UI-Komponenten |
|
||||
| `@manacore/shared-icons` | Icon-Library |
|
||||
| `@manacore/shared-tailwind` | Tailwind Konfiguration |
|
||||
| `@manacore/shared-theme` | Theme-Logik |
|
||||
| `@manacore/shared-theme-ui` | Theme UI-Komponenten |
|
||||
| `@manacore/shared-branding` | Branding Assets |
|
||||
| `@manacore/shared-landing-ui` | Landing Page Komponenten |
|
||||
|
||||
### Business Logic
|
||||
|
||||
| Package | Beschreibung |
|
||||
|---------|--------------|
|
||||
| Package | Beschreibung |
|
||||
| ------------------------------------- | ----------------------------- |
|
||||
| `@manacore/shared-subscription-types` | Subscription TypeScript Types |
|
||||
| `@manacore/shared-subscription-ui` | Subscription UI-Komponenten |
|
||||
| `@manacore/shared-credit-service` | Credit/Mana Service |
|
||||
| `@manacore/shared-i18n` | Internationalisierung |
|
||||
| `@manacore/shared-subscription-ui` | Subscription UI-Komponenten |
|
||||
| `@manacore/shared-credit-service` | Credit/Mana Service |
|
||||
| `@manacore/shared-i18n` | Internationalisierung |
|
||||
|
||||
### Datenbank
|
||||
|
||||
| Package | Beschreibung |
|
||||
|---------|--------------|
|
||||
| Package | Beschreibung |
|
||||
| ------------------- | ------------------------- |
|
||||
| `manadeck-database` | Manadeck Datenbank-Schema |
|
||||
| `uload-database` | uLoad Datenbank-Schema |
|
||||
| `uload-database` | uLoad Datenbank-Schema |
|
||||
|
||||
### Verwendung
|
||||
|
||||
|
|
@ -477,41 +508,41 @@ import { formatDate, truncate, retry } from '@manacore/shared-utils';
|
|||
|
||||
### Frontend
|
||||
|
||||
| Kategorie | Web | Mobile |
|
||||
|-----------|-----|--------|
|
||||
| Framework | SvelteKit 2 / Astro | React Native + Expo |
|
||||
| UI Library | Svelte 5 (Runes) | React 18/19 |
|
||||
| Styling | TailwindCSS | NativeWind |
|
||||
| State | Svelte Stores | Zustand / Context |
|
||||
| Routing | File-based | Expo Router |
|
||||
| Kategorie | Web | Mobile |
|
||||
| ---------- | ------------------- | ------------------- |
|
||||
| Framework | SvelteKit 2 / Astro | React Native + Expo |
|
||||
| UI Library | Svelte 5 (Runes) | React 18/19 |
|
||||
| Styling | TailwindCSS | NativeWind |
|
||||
| State | Svelte Stores | Zustand / Context |
|
||||
| Routing | File-based | Expo Router |
|
||||
|
||||
### Backend
|
||||
|
||||
| Kategorie | Technologie |
|
||||
|-----------|-------------|
|
||||
| API | NestJS |
|
||||
| Auth | Mana Core Middleware / Supabase Auth |
|
||||
| Database | PostgreSQL (Supabase) / PocketBase |
|
||||
| Storage | Supabase Storage / Cloudflare R2 |
|
||||
| Cache | Redis |
|
||||
| Kategorie | Technologie |
|
||||
| --------- | ------------------------------------ |
|
||||
| API | NestJS |
|
||||
| Auth | Mana Core Middleware / Supabase Auth |
|
||||
| Database | PostgreSQL (Supabase) / PocketBase |
|
||||
| Storage | Supabase Storage / Cloudflare R2 |
|
||||
| Cache | Redis |
|
||||
|
||||
### AI/ML
|
||||
|
||||
| Service | Verwendung |
|
||||
|---------|------------|
|
||||
| Azure OpenAI (GPT-4) | Text-Generierung |
|
||||
| Google Gemini | Text-Analyse |
|
||||
| Replicate (Flux) | Bild-Generierung |
|
||||
| Azure Speech Services | Sprache-zu-Text |
|
||||
| Service | Verwendung |
|
||||
| --------------------- | ---------------- |
|
||||
| Azure OpenAI (GPT-4) | Text-Generierung |
|
||||
| Google Gemini | Text-Analyse |
|
||||
| Replicate (Flux) | Bild-Generierung |
|
||||
| Azure Speech Services | Sprache-zu-Text |
|
||||
|
||||
### DevOps
|
||||
|
||||
| Kategorie | Technologie |
|
||||
|-----------|-------------|
|
||||
| Package Manager | pnpm 9.15.0 |
|
||||
| Build System | Turborepo |
|
||||
| CI/CD | EAS Build (Mobile), Vercel/Netlify (Web) |
|
||||
| Deployment | Google Cloud Run, Docker |
|
||||
| Kategorie | Technologie |
|
||||
| --------------- | ---------------------------------------- |
|
||||
| Package Manager | pnpm 9.15.0 |
|
||||
| Build System | Turborepo |
|
||||
| CI/CD | EAS Build (Mobile), Vercel/Netlify (Web) |
|
||||
| Deployment | Google Cloud Run, Docker |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -597,6 +628,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
### Analyse des bestehenden Ökosystems
|
||||
|
||||
**Stärken der Plattform:**
|
||||
|
||||
- Etabliertes Credit-System (Mana) für Monetarisierung
|
||||
- Zentrale Authentifizierung über Manacore
|
||||
- Multi-Platform-Expertise (Web + Mobile)
|
||||
|
|
@ -606,6 +638,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Bewährte Shared Packages
|
||||
|
||||
**Bestehende Domänen:**
|
||||
|
||||
- Kreatives Schreiben (Maerchenzauber)
|
||||
- Sprachaufnahmen & Transkription (Memoro)
|
||||
- Lernen & Wissensmanagement (Manadeck)
|
||||
|
|
@ -622,6 +655,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Eine Notion-ähnliche Notiz-Anwendung mit tiefer KI-Integration und nahtloser Verbindung zu anderen Mana-Apps.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Block-basierter Editor (ähnlich Notion)
|
||||
- KI-gestützte Zusammenfassungen und Umstrukturierung
|
||||
- Automatische Verlinkung verwandter Notizen (Knowledge Graph)
|
||||
|
|
@ -630,6 +664,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Markdown-Export/Import
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Memoro-Integration:** Audio-Memos werden automatisch als Notizen importiert
|
||||
- **Manadeck-Integration:** Aus Notizen Lernkarten generieren
|
||||
- **Chat-Integration:** Chat-Verläufe als Notizen speichern
|
||||
|
|
@ -645,6 +680,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Zielgruppe:** Studenten, Wissensarbeiter, Forscher, Journalisten
|
||||
|
||||
**Technische Besonderheiten:**
|
||||
|
||||
- Offline-first mit Sync
|
||||
- Echtzeit-Kollaboration
|
||||
- Versionierung & History
|
||||
|
|
@ -657,6 +693,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ein schlankes, KI-gestütztes Projektmanagement-Tool, das sich auf Einzelpersonen und kleine Teams konzentriert.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Kanban-Boards, Listen und Kalender-Ansichten
|
||||
- KI-gestützte Task-Zerlegung (großes Ziel → Subtasks)
|
||||
- Intelligente Priorisierung basierend auf Deadlines und Abhängigkeiten
|
||||
|
|
@ -665,6 +702,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Focus Mode mit Pomodoro-Timer
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Memoro-Integration:** Meeting-Aufnahmen → automatisch extrahierte Action Items
|
||||
- **ManaNote-Integration:** Projekt-Dokumentation verknüpfen
|
||||
- **Manacore-Integration:** Team-Spaces mit Rollen
|
||||
|
|
@ -688,6 +726,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ein Kalender, der nicht nur Termine verwaltet, sondern aktiv bei der Zeitplanung hilft.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Smart Scheduling: Findet automatisch optimale Zeitslots
|
||||
- Meeting-Vorbereitung: Zeigt relevante Dokumente/Notizen vor Terminen
|
||||
- Time Blocking: KI schlägt Fokuszeiten vor
|
||||
|
|
@ -696,6 +735,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Reisezeit-Berechnung zwischen Terminen
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Memoro-Integration:** Nach Meetings automatisch Transkript verlinken
|
||||
- **ManaTask-Integration:** Deadline-Visualisierung im Kalender
|
||||
- **ManaNote-Integration:** Meeting-Notizen direkt zum Termin
|
||||
|
|
@ -719,6 +759,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Während Maerchenzauber auf Kindergeschichten spezialisiert ist, richtet sich ManaWrite an professionelle Content-Erstellung.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Blog-Posts, Artikel, Essays
|
||||
- Marketing-Texte (Ads, Landing Pages, E-Mails)
|
||||
- Social Media Content mit Plattform-Anpassung
|
||||
|
|
@ -728,6 +769,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- A/B-Varianten-Generierung
|
||||
|
||||
**Content-Typen:**
|
||||
|
||||
- Blog-Artikel
|
||||
- Newsletter
|
||||
- Produktbeschreibungen
|
||||
|
|
@ -736,6 +778,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Reden und Präsentationen
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Memoro-Integration:** Gesprochene Gedanken → ausformulierte Texte
|
||||
- **ManaNote-Integration:** Notizen → fertige Artikel
|
||||
- **uLoad-Integration:** Tracking-Links für veröffentlichte Inhalte
|
||||
|
|
@ -758,6 +801,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ein mobiler Video-Editor für kurze Social-Media-Videos mit KI-Unterstützung.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Automatische Untertitel-Generierung (32 Sprachen)
|
||||
- KI-Schnitt: Erkennt beste Momente, entfernt "Ähms" und Pausen
|
||||
- Thumbnail-Generierung mit KI
|
||||
|
|
@ -767,6 +811,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Talking Head → Animated Avatar
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Memoro-Integration:** Audio-Transkripte für Untertitel
|
||||
- **Picture-Integration:** Thumbnail-Bearbeitung
|
||||
- **ManaWrite-Integration:** Video-Skripte erstellen
|
||||
|
|
@ -788,6 +833,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Eine All-in-One Lösung für Podcast-Produktion - von der Aufnahme bis zur Veröffentlichung.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Multi-Track-Aufnahme (Remote-Interviews)
|
||||
- Automatische Audio-Verbesserung (Noise Reduction, Normalisierung)
|
||||
- KI-Kapitel-Generierung mit Timestamps
|
||||
|
|
@ -797,6 +843,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Analytics Dashboard
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Memoro-Integration:** Gleiche Audio-Engine, Transkription
|
||||
- **ManaWrite-Integration:** Show Notes und Beschreibungen
|
||||
- **uLoad-Integration:** Tracking-Links für Episoden
|
||||
|
|
@ -819,6 +866,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ergänzung zu Picture mit Fokus auf Brand-Design und Marketing-Materialien.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Logo-Generator mit Varianten
|
||||
- Brand Kit Management (Farben, Fonts, Assets)
|
||||
- Social Media Template-Generator
|
||||
|
|
@ -828,6 +876,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Infografik-Generator
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Picture-Integration:** Detaillierte Bildbearbeitung
|
||||
- **ManaWrite-Integration:** Text für Marketing-Materialien
|
||||
- **uLoad-Integration:** QR-Codes mit Tracking
|
||||
|
|
@ -852,6 +901,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Eine Plattform zum Erstellen und Konsumieren von Mikro-Kursen mit KI-Unterstützung.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Kurs-Builder mit Drag & Drop
|
||||
- KI-generierte Quizze und Tests
|
||||
- Lernpfade mit Abhängigkeiten
|
||||
|
|
@ -861,6 +911,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Spaced Repetition Integration
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Manadeck-Integration:** Kursinhalte → Lernkarten
|
||||
- **Memoro-Integration:** Vorlesungen aufnehmen und transkribieren
|
||||
- **ManaNote-Integration:** Kurs-Notizen
|
||||
|
|
@ -883,6 +934,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ein Tool zum schnellen Erfassen und Verarbeiten von Dokumenten, Artikeln und Büchern.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- PDF/EPUB-Import und -Annotation
|
||||
- Web-Artikel-Clipper
|
||||
- KI-Zusammenfassungen (verschiedene Längen)
|
||||
|
|
@ -892,6 +944,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Text-to-Speech für Dokumente
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Manadeck-Integration:** Highlights → Lernkarten
|
||||
- **ManaNote-Integration:** Exzerpte in Notizen überführen
|
||||
- **ManaLearn-Integration:** Leselisten für Kurse
|
||||
|
|
@ -913,6 +966,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Mehr als ein einfacher Übersetzer - ein Tool für professionelle Lokalisierung.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Dokumenten-Übersetzung (PDF, DOCX, etc.)
|
||||
- Kontext-bewusste Übersetzung
|
||||
- Terminologie-Management (Glossare)
|
||||
|
|
@ -922,6 +976,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Batch-Übersetzung für Websites
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **ManaWrite-Integration:** Mehrsprachige Content-Erstellung
|
||||
- **Shared i18n:** Gleiche 32-Sprachen-Basis
|
||||
- **ManaRead-Integration:** Fremdsprachige Dokumente verstehen
|
||||
|
|
@ -945,6 +1000,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ein personalisierter Fitness-Begleiter mit adaptiven Trainingsplänen.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- KI-generierte Trainingspläne basierend auf Zielen
|
||||
- Video-Übungsanleitungen
|
||||
- Progressive Overload Tracking
|
||||
|
|
@ -970,6 +1026,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Eine App für mentales Wohlbefinden mit geführten Meditationen und Journaling.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Geführte Meditationen (verschiedene Längen und Themen)
|
||||
- Atemübungen mit Visualisierung
|
||||
- Stimmungs-Tracking
|
||||
|
|
@ -979,6 +1036,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Therapie-Vorbereitung (Gedanken strukturieren)
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Maerchenzauber-Integration:** Beruhigende Geschichten
|
||||
- **Memoro-Integration:** Gedanken aufnehmen statt schreiben
|
||||
|
||||
|
|
@ -999,6 +1057,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ein Rezept-Manager mit KI-Funktionen für Planung und Anpassung.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Rezept-Import aus URLs
|
||||
- KI-Rezeptgenerierung basierend auf Zutaten ("Was kann ich kochen?")
|
||||
- Automatische Skalierung von Portionen
|
||||
|
|
@ -1027,6 +1086,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ein intelligentes Tool zur Verwaltung persönlicher Finanzen mit KI-Insights.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Bank-Synchronisation (via Plaid/ähnlich)
|
||||
- Automatische Kategorisierung von Transaktionen
|
||||
- Budget-Erstellung und -Tracking
|
||||
|
|
@ -1053,6 +1113,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Einfache Rechnungsstellung für Freelancer und kleine Unternehmen.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Professionelle Rechnungs-Templates
|
||||
- Automatische Nummerierung
|
||||
- Wiederkehrende Rechnungen
|
||||
|
|
@ -1064,6 +1125,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Kunden-Verwaltung (CRM-light)
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **ManaDesign-Integration:** Gebrandete Rechnungen
|
||||
- **uLoad-Integration:** Zahlungslinks
|
||||
|
||||
|
|
@ -1083,6 +1145,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ein Tool zur Erstellung überzeugender Pitch-Decks und Präsentationen.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- KI-generierte Präsentations-Struktur
|
||||
- Design-Vorlagen für verschiedene Anlässe
|
||||
- Storytelling-Unterstützung
|
||||
|
|
@ -1093,6 +1156,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Pitch-Timer mit Übung
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **ManaDesign-Integration:** Visuelle Assets
|
||||
- **ManaWrite-Integration:** Texte und Skripte
|
||||
- **Memoro-Integration:** Präsentation aufnehmen und analysieren
|
||||
|
|
@ -1116,6 +1180,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Eine Video-Konferenz-Lösung mit eingebauter KI-Unterstützung.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- HD Video-Calls
|
||||
- Echtzeit-Transkription
|
||||
- Live-Untertitel in verschiedenen Sprachen
|
||||
|
|
@ -1127,6 +1192,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Aufnahme mit automatischer Verarbeitung
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Memoro-Integration:** Gleiche Transkriptions-Engine
|
||||
- **ManaNote-Integration:** Meeting Notes direkt speichern
|
||||
- **ManaTask-Integration:** Action Items → Tasks
|
||||
|
|
@ -1149,6 +1215,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Eine moderne Forum/Community-Plattform für Marken und Communities.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Threads und Diskussionen
|
||||
- Q&A-Bereich mit Voting
|
||||
- KI-Moderation
|
||||
|
|
@ -1159,6 +1226,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Integration mit Chat
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Chat-Integration:** Private Nachrichten
|
||||
- **ManaLearn-Integration:** Community-Kurse
|
||||
- **Manacore-Integration:** Organisation/Team als Community
|
||||
|
|
@ -1181,6 +1249,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Eine intelligente Bibliothek für Code-Snippets mit KI-Unterstützung.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Snippet-Organisation mit Tags und Ordnern
|
||||
- Syntax-Highlighting für alle gängigen Sprachen
|
||||
- KI-Code-Erklärung
|
||||
|
|
@ -1207,6 +1276,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Automatische API-Dokumentation und Testing.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- OpenAPI/Swagger-Import
|
||||
- Automatische Docs-Generierung
|
||||
- Interaktiver API-Explorer
|
||||
|
|
@ -1233,6 +1303,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ein KI-gestützter Reiseplaner für die perfekte Reise.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- KI-Reiserouten basierend auf Interessen und Budget
|
||||
- Tag-für-Tag-Itineraries
|
||||
- Restaurant- und Aktivitäts-Empfehlungen
|
||||
|
|
@ -1243,6 +1314,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Erinnerungsbuch nach der Reise
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Picture-Integration:** Reisefotos bearbeiten
|
||||
- **ManaNote-Integration:** Reisenotizen
|
||||
- **ManaFinance-Integration:** Reise-Budget
|
||||
|
|
@ -1264,6 +1336,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Eine Erweiterung von Maerchenzauber für interaktive "Choose Your Own Adventure"-Geschichten.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Interaktive Entscheidungs-Geschichten
|
||||
- KI-generierte Verzweigungen
|
||||
- Verschiedene Genres (Fantasy, Krimi, Romance, Horror)
|
||||
|
|
@ -1273,6 +1346,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Multiplayer-Abenteuer (Gruppen-Entscheidungen)
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **Maerchenzauber-Integration:** Charaktere und Illustrationen
|
||||
- **Chat-Integration:** Multiplayer-Koordination
|
||||
|
||||
|
|
@ -1293,6 +1367,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
**Konzept:** Ein Tool zur KI-gestützten Musikerstellung für Content Creator.
|
||||
|
||||
**Kernfeatures:**
|
||||
|
||||
- Hintergrundmusik-Generierung
|
||||
- Stil- und Stimmungs-basierte Musik
|
||||
- Podcast-Intro/Outro-Generator
|
||||
|
|
@ -1303,6 +1378,7 @@ Dieser Abschnitt enthält durchdachte Ideen für neue Anwendungen, die das Manac
|
|||
- Loops und Samples
|
||||
|
||||
**Synergien:**
|
||||
|
||||
- **ManaPodcast-Integration:** Musik für Podcasts
|
||||
- **ManaVideo-Integration:** Hintergrundmusik
|
||||
- **ManaMind-Integration:** Entspannungsmusik
|
||||
|
|
@ -1325,32 +1401,32 @@ Basierend auf Synergien mit bestehenden Apps, Marktpotenzial und technischer Mac
|
|||
|
||||
#### Hohe Priorität (Sofortiges Potenzial)
|
||||
|
||||
| App | Begründung |
|
||||
|-----|------------|
|
||||
| **ManaNote** | Natürliche Erweiterung von Memoro, hohe Synergien |
|
||||
| **ManaWrite** | Nutzt bestehende KI-Infrastruktur, klarer Markt |
|
||||
| **ManaRead** | Ergänzt Manadeck perfekt, Bildungsmarkt |
|
||||
| **ManaMeet** | Memoro-Technologie wiederverwendbar |
|
||||
| App | Begründung |
|
||||
| ------------- | ------------------------------------------------- |
|
||||
| **ManaNote** | Natürliche Erweiterung von Memoro, hohe Synergien |
|
||||
| **ManaWrite** | Nutzt bestehende KI-Infrastruktur, klarer Markt |
|
||||
| **ManaRead** | Ergänzt Manadeck perfekt, Bildungsmarkt |
|
||||
| **ManaMeet** | Memoro-Technologie wiederverwendbar |
|
||||
|
||||
#### Mittlere Priorität (Strategisch wichtig)
|
||||
|
||||
| App | Begründung |
|
||||
|-----|------------|
|
||||
| **ManaTask** | Produktivitäts-Suite vervollständigen |
|
||||
| **ManaCalendar** | Verbindet alle Produktivitäts-Apps |
|
||||
| **ManaPodcast** | Wachsender Markt, Memoro-Basis |
|
||||
| **ManaDesign** | Picture erweitern, Marketing-Use-Cases |
|
||||
| **ManaLearn** | Manadeck + Memoro + Video kombinieren |
|
||||
| App | Begründung |
|
||||
| ---------------- | -------------------------------------- |
|
||||
| **ManaTask** | Produktivitäts-Suite vervollständigen |
|
||||
| **ManaCalendar** | Verbindet alle Produktivitäts-Apps |
|
||||
| **ManaPodcast** | Wachsender Markt, Memoro-Basis |
|
||||
| **ManaDesign** | Picture erweitern, Marketing-Use-Cases |
|
||||
| **ManaLearn** | Manadeck + Memoro + Video kombinieren |
|
||||
|
||||
#### Langfristig (Exploration)
|
||||
|
||||
| App | Begründung |
|
||||
|-----|------------|
|
||||
| **ManaVideo** | Komplex, aber hoher Bedarf |
|
||||
| App | Begründung |
|
||||
| --------------- | ---------------------------------- |
|
||||
| **ManaVideo** | Komplex, aber hoher Bedarf |
|
||||
| **ManaFinance** | Andere Domäne, aber hohe Nachfrage |
|
||||
| **ManaFit** | Großer Markt, wenig Synergien |
|
||||
| **ManaMusic** | KI-Musik im Aufwind |
|
||||
| **ManaTrip** | Saisonal, aber emotional |
|
||||
| **ManaFit** | Großer Markt, wenig Synergien |
|
||||
| **ManaMusic** | KI-Musik im Aufwind |
|
||||
| **ManaTrip** | Saisonal, aber emotional |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1388,4 +1464,4 @@ Die Vision: **Ein zusammenhängendes Ökosystem, in dem Daten nahtlos zwischen A
|
|||
|
||||
---
|
||||
|
||||
*Zuletzt aktualisiert: November 2025*
|
||||
_Zuletzt aktualisiert: November 2025_
|
||||
|
|
|
|||
|
|
@ -35,35 +35,39 @@ Komplette Anleitung zum Hosten aller Projekte auf eigener Infrastruktur (VPS).
|
|||
|
||||
## Technologie-Stack pro Projekt
|
||||
|
||||
| Projekt | Web App | Landing | Backend | Mobile | Datenbank |
|
||||
|---------|---------|---------|---------|--------|-----------|
|
||||
| **Maerchenzauber** | SvelteKit | Astro | NestJS | Expo | Supabase |
|
||||
| **Manacore** | SvelteKit | Astro | - | Expo | Supabase |
|
||||
| **Manadeck** | SvelteKit | Astro | NestJS | Expo | PostgreSQL |
|
||||
| **Memoro** | SvelteKit | Astro | - | Expo | Supabase |
|
||||
| **Picture** | SvelteKit | Astro | - | Expo | Supabase |
|
||||
| **uLoad** | SvelteKit | - | - | - | PostgreSQL + Redis |
|
||||
| Projekt | Web App | Landing | Backend | Mobile | Datenbank |
|
||||
| ------------------ | --------- | ------- | ------- | ------ | ------------------ |
|
||||
| **Maerchenzauber** | SvelteKit | Astro | NestJS | Expo | Supabase |
|
||||
| **Manacore** | SvelteKit | Astro | - | Expo | Supabase |
|
||||
| **Manadeck** | SvelteKit | Astro | NestJS | Expo | PostgreSQL |
|
||||
| **Memoro** | SvelteKit | Astro | - | Expo | Supabase |
|
||||
| **Picture** | SvelteKit | Astro | - | Expo | Supabase |
|
||||
| **uLoad** | SvelteKit | - | - | - | PostgreSQL + Redis |
|
||||
|
||||
---
|
||||
|
||||
## Deployment-Optionen im Überblick
|
||||
|
||||
### Option A: Single VPS mit Coolify (Empfohlen für Start)
|
||||
|
||||
- **Kosten:** ~€15-30/Monat
|
||||
- **Komplexität:** Niedrig
|
||||
- **Skalierung:** Begrenzt
|
||||
|
||||
### Option B: Multi-VPS mit Coolify
|
||||
|
||||
- **Kosten:** ~€50-100/Monat
|
||||
- **Komplexität:** Mittel
|
||||
- **Skalierung:** Gut
|
||||
|
||||
### Option C: Kubernetes (K3s)
|
||||
|
||||
- **Kosten:** ~€30-80/Monat
|
||||
- **Komplexität:** Hoch
|
||||
- **Skalierung:** Sehr gut
|
||||
|
||||
### Option D: Hybrid (Self-Hosted + Managed)
|
||||
|
||||
- **Kosten:** ~€20-50/Monat + Supabase
|
||||
- **Komplexität:** Niedrig-Mittel
|
||||
- **Skalierung:** Flexibel
|
||||
|
|
@ -97,15 +101,15 @@ Die einfachste Lösung für den Start. Alle Services auf einem Server.
|
|||
|
||||
## Ressourcen-Anforderungen
|
||||
|
||||
| Komponente | RAM | CPU | Disk |
|
||||
|------------|-----|-----|------|
|
||||
| PostgreSQL | 1GB | 0.5 | 10GB |
|
||||
| Redis | 256MB | 0.2 | 1GB |
|
||||
| Coolify | 512MB | 0.3 | 5GB |
|
||||
| Traefik | 128MB | 0.1 | - |
|
||||
| Pro Web App | 256MB | 0.3 | - |
|
||||
| Pro Backend | 512MB | 0.5 | - |
|
||||
| Pro Landing | 64MB | 0.1 | - |
|
||||
| Komponente | RAM | CPU | Disk |
|
||||
| ----------------- | -------- | ------ | --------- |
|
||||
| PostgreSQL | 1GB | 0.5 | 10GB |
|
||||
| Redis | 256MB | 0.2 | 1GB |
|
||||
| Coolify | 512MB | 0.3 | 5GB |
|
||||
| Traefik | 128MB | 0.1 | - |
|
||||
| Pro Web App | 256MB | 0.3 | - |
|
||||
| Pro Backend | 512MB | 0.5 | - |
|
||||
| Pro Landing | 64MB | 0.1 | - |
|
||||
| **Gesamt (alle)** | **~6GB** | **~4** | **~30GB** |
|
||||
|
||||
**Empfohlener Server:** Hetzner CX31 (4 vCPU, 8GB RAM, 80GB) - €8.98/Monat
|
||||
|
|
@ -128,6 +132,7 @@ curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
|
|||
### 2. Datenbank-Services erstellen
|
||||
|
||||
**PostgreSQL:**
|
||||
|
||||
```
|
||||
Name: shared-postgres
|
||||
Version: 16-alpine
|
||||
|
|
@ -135,6 +140,7 @@ Databases: manacore, manadeck, uload
|
|||
```
|
||||
|
||||
**Redis:**
|
||||
|
||||
```
|
||||
Name: shared-redis
|
||||
Version: 7-alpine
|
||||
|
|
@ -152,6 +158,7 @@ Version: 7-alpine
|
|||
#### Konfiguration pro Projekt
|
||||
|
||||
**Alle SvelteKit Web Apps:**
|
||||
|
||||
```
|
||||
Base Directory: /
|
||||
Dockerfile: {projekt}/apps/web/Dockerfile # Falls vorhanden
|
||||
|
|
@ -163,6 +170,7 @@ Port: 3000
|
|||
```
|
||||
|
||||
**Alle Astro Landing Pages:**
|
||||
|
||||
```
|
||||
Build Pack: Static
|
||||
Base Directory: {projekt}/apps/landing
|
||||
|
|
@ -171,6 +179,7 @@ Publish Directory: dist
|
|||
```
|
||||
|
||||
**NestJS Backends:**
|
||||
|
||||
```
|
||||
Base Directory: /
|
||||
Dockerfile: {projekt}/apps/backend/Dockerfile
|
||||
|
|
@ -181,21 +190,21 @@ Port: 4000
|
|||
|
||||
### 4. Domain-Mapping
|
||||
|
||||
| Service | Domain | Port |
|
||||
|---------|--------|------|
|
||||
| uload-web | ulo.ad | 3000 |
|
||||
| maerchenzauber-web | app.maerchenzauber.de | 3001 |
|
||||
| maerchenzauber-landing | maerchenzauber.de | 8080 |
|
||||
| Service | Domain | Port |
|
||||
| ---------------------- | --------------------- | ---- |
|
||||
| uload-web | ulo.ad | 3000 |
|
||||
| maerchenzauber-web | app.maerchenzauber.de | 3001 |
|
||||
| maerchenzauber-landing | maerchenzauber.de | 8080 |
|
||||
| maerchenzauber-backend | api.maerchenzauber.de | 4000 |
|
||||
| manacore-web | app.manacore.io | 3002 |
|
||||
| manacore-landing | manacore.io | 8081 |
|
||||
| manadeck-web | app.manadeck.de | 3003 |
|
||||
| manadeck-landing | manadeck.de | 8082 |
|
||||
| manadeck-backend | api.manadeck.de | 4001 |
|
||||
| memoro-web | app.memoro.ai | 3004 |
|
||||
| memoro-landing | memoro.ai | 8083 |
|
||||
| picture-web | app.picture.io | 3005 |
|
||||
| picture-landing | picture.io | 8084 |
|
||||
| manacore-web | app.manacore.io | 3002 |
|
||||
| manacore-landing | manacore.io | 8081 |
|
||||
| manadeck-web | app.manadeck.de | 3003 |
|
||||
| manadeck-landing | manadeck.de | 8082 |
|
||||
| manadeck-backend | api.manadeck.de | 4001 |
|
||||
| memoro-web | app.memoro.ai | 3004 |
|
||||
| memoro-landing | memoro.ai | 8083 |
|
||||
| picture-web | app.picture.io | 3005 |
|
||||
| picture-landing | picture.io | 8084 |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -228,16 +237,19 @@ Bessere Isolation und Skalierung durch mehrere Server.
|
|||
## Server-Aufteilung
|
||||
|
||||
### VPS 1: Frontend (CX21 - €4.49/Monat)
|
||||
|
||||
- Alle SvelteKit Web Apps
|
||||
- Alle Astro Landing Pages
|
||||
- Traefik Reverse Proxy
|
||||
|
||||
### VPS 2: Backends (CX21 - €4.49/Monat)
|
||||
|
||||
- Maerchenzauber NestJS Backend
|
||||
- Manadeck NestJS Backend
|
||||
- Background Workers
|
||||
|
||||
### VPS 3: Datenbanken (CX31 - €8.98/Monat)
|
||||
|
||||
- PostgreSQL (shared)
|
||||
- Redis (shared)
|
||||
- Automated Backups
|
||||
|
|
@ -424,22 +436,22 @@ Kombination aus Self-Hosting und Managed Services für beste Balance.
|
|||
|
||||
### Managed Services (empfohlen)
|
||||
|
||||
| Service | Anbieter | Kosten | Grund |
|
||||
|---------|----------|--------|-------|
|
||||
| Datenbank | Supabase | Free-$25/M | Auth + Realtime inklusive |
|
||||
| Landing Pages | Vercel/Netlify | Free | CDN + Edge |
|
||||
| CDN | Cloudflare | Free | DDoS + Caching |
|
||||
| Email | Resend | Free-$20/M | Deliverability |
|
||||
| Payments | Stripe | % per Tx | Compliance |
|
||||
| Service | Anbieter | Kosten | Grund |
|
||||
| ------------- | -------------- | ---------- | ------------------------- |
|
||||
| Datenbank | Supabase | Free-$25/M | Auth + Realtime inklusive |
|
||||
| Landing Pages | Vercel/Netlify | Free | CDN + Edge |
|
||||
| CDN | Cloudflare | Free | DDoS + Caching |
|
||||
| Email | Resend | Free-$20/M | Deliverability |
|
||||
| Payments | Stripe | % per Tx | Compliance |
|
||||
|
||||
### Self-Hosted (VPS)
|
||||
|
||||
| Service | Grund |
|
||||
|---------|-------|
|
||||
| Service | Grund |
|
||||
| -------- | -------------------------------------- |
|
||||
| Web Apps | Volle Kontrolle, günstiger bei Traffic |
|
||||
| Backends | Custom Code, API Keys |
|
||||
| uLoad | Komplett eigene Infra gewünscht |
|
||||
| Redis | Falls benötigt |
|
||||
| Backends | Custom Code, API Keys |
|
||||
| uLoad | Komplett eigene Infra gewünscht |
|
||||
| Redis | Falls benötigt |
|
||||
|
||||
## Setup
|
||||
|
||||
|
|
@ -472,13 +484,13 @@ curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
|
|||
|
||||
## Kosten-Vergleich
|
||||
|
||||
| Komponente | Full Self-Hosted | Hybrid |
|
||||
|------------|------------------|--------|
|
||||
| VPS | €9-18/Monat | €4.50/Monat |
|
||||
| Supabase | - | Free-€25/Monat |
|
||||
| Vercel | - | Free |
|
||||
| Cloudflare | - | Free |
|
||||
| **Gesamt** | **€9-18/Monat** | **€4.50-30/Monat** |
|
||||
| Komponente | Full Self-Hosted | Hybrid |
|
||||
| ---------- | ---------------- | ------------------ |
|
||||
| VPS | €9-18/Monat | €4.50/Monat |
|
||||
| Supabase | - | Free-€25/Monat |
|
||||
| Vercel | - | Free |
|
||||
| Cloudflare | - | Free |
|
||||
| **Gesamt** | **€9-18/Monat** | **€4.50-30/Monat** |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -546,6 +558,7 @@ CMD ["nginx", "-g", "daemon off;"]
|
|||
## NestJS Backends
|
||||
|
||||
Bereits vorhanden in:
|
||||
|
||||
- `maerchenzauber/apps/backend/Dockerfile`
|
||||
- `manadeck/backend/Dockerfile`
|
||||
|
||||
|
|
@ -578,6 +591,7 @@ DATABASE_URL=postgresql://user:pass@host:5432/db
|
|||
## Projekt-spezifische Variablen
|
||||
|
||||
### Maerchenzauber Backend
|
||||
|
||||
```env
|
||||
AZURE_OPENAI_ENDPOINT=https://xxx.openai.azure.com
|
||||
AZURE_OPENAI_API_KEY=xxx
|
||||
|
|
@ -587,11 +601,13 @@ GOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.json
|
|||
```
|
||||
|
||||
### Manadeck Backend
|
||||
|
||||
```env
|
||||
GOOGLE_GEMINI_API_KEY=xxx
|
||||
```
|
||||
|
||||
### uLoad
|
||||
|
||||
```env
|
||||
REDIS_URL=redis://localhost:6379
|
||||
STRIPE_SECRET_KEY=sk_live_xxx
|
||||
|
|
@ -609,18 +625,21 @@ AUTH_SECRET=xxx
|
|||
# Checkliste: Komplettes Self-Hosting
|
||||
|
||||
## Infrastruktur
|
||||
|
||||
- [ ] VPS bestellt (Hetzner CX21/CX31)
|
||||
- [ ] SSH-Zugang eingerichtet
|
||||
- [ ] Coolify installiert
|
||||
- [ ] Firewall konfiguriert
|
||||
|
||||
## Datenbanken
|
||||
|
||||
- [ ] PostgreSQL läuft
|
||||
- [ ] Redis läuft (falls benötigt)
|
||||
- [ ] Backups eingerichtet
|
||||
- [ ] Connection Strings notiert
|
||||
|
||||
## Projekte (für jedes)
|
||||
|
||||
- [ ] Dockerfile erstellt/geprüft
|
||||
- [ ] Environment Variables gesetzt
|
||||
- [ ] Domain konfiguriert
|
||||
|
|
@ -628,16 +647,19 @@ AUTH_SECRET=xxx
|
|||
- [ ] Health-Check funktioniert
|
||||
|
||||
## DNS (für jede Domain)
|
||||
|
||||
- [ ] A-Record auf Server-IP
|
||||
- [ ] www CNAME (optional)
|
||||
- [ ] Propagation geprüft
|
||||
|
||||
## Monitoring
|
||||
|
||||
- [ ] Logs erreichbar
|
||||
- [ ] Alerting eingerichtet (optional)
|
||||
- [ ] Uptime-Monitoring (optional)
|
||||
|
||||
## Backups
|
||||
|
||||
- [ ] Datenbank-Backup automatisiert
|
||||
- [ ] Backup-Test durchgeführt
|
||||
- [ ] Offsite-Backup (optional)
|
||||
|
|
@ -654,6 +676,7 @@ AUTH_SECRET=xxx
|
|||
4. **Cloudflare** für DNS + CDN (Free)
|
||||
|
||||
**Vorteile:**
|
||||
|
||||
- Schneller Start
|
||||
- Geringe Kosten
|
||||
- Managed Auth & Realtime
|
||||
|
|
@ -662,6 +685,7 @@ AUTH_SECRET=xxx
|
|||
## Für Wachstum: Option B (Multi-VPS)
|
||||
|
||||
Wenn Traffic steigt:
|
||||
|
||||
1. Datenbanken auf eigenen VPS migrieren
|
||||
2. Frontend/Backend trennen
|
||||
3. Load Balancing hinzufügen
|
||||
|
|
@ -669,6 +693,7 @@ Wenn Traffic steigt:
|
|||
## Für Enterprise: Option C (Kubernetes)
|
||||
|
||||
Wenn benötigt:
|
||||
|
||||
- Auto-Scaling
|
||||
- Zero-Downtime Deployments
|
||||
- Multi-Region
|
||||
|
|
|
|||
|
|
@ -29,12 +29,14 @@ This document outlines the plan to unify common code across all web apps in the
|
|||
All web apps now use the shared packages consistently:
|
||||
|
||||
**Logo Components** - Migrated to `@manacore/shared-branding`:
|
||||
|
||||
- `memoro/apps/web/src/lib/components/MemoroLogo.svelte` → uses `AppLogo`
|
||||
- `manadeck/apps/web/src/lib/components/ManaDeckLogo.svelte` → uses `AppLogo`
|
||||
- `manacore/apps/web/src/lib/components/ManaCoreLogo.svelte` → uses `AppLogo`
|
||||
- `maerchenzauber/apps/web/src/lib/components/StorytellerLogo.svelte` → uses `AppLogo`
|
||||
|
||||
**Formatter Functions** - Migrated to `@manacore/shared-utils`:
|
||||
|
||||
- `memoro/apps/web/src/lib/components/memo/AdditionalRecordings.svelte` → uses `formatDurationFromMs`, `formatFileSize`
|
||||
- `memoro/apps/web/src/lib/components/RecordingButton.svelte` → uses `formatDuration`
|
||||
- `memoro/apps/web/src/lib/components/statistics/OverviewCard.svelte` → uses `formatDurationWithUnits`
|
||||
|
|
@ -52,6 +54,7 @@ All web apps now use the shared packages consistently:
|
|||
**Estimated LOC Savings**: 500-800 per app
|
||||
|
||||
**Components to unify**:
|
||||
|
||||
- `Button.svelte` - Primary, secondary, ghost, danger variants
|
||||
- `Input.svelte` - Text input with label, error states
|
||||
- `Text.svelte` - Typography component with variants
|
||||
|
|
@ -63,6 +66,7 @@ All web apps now use the shared packages consistently:
|
|||
- `Dropdown.svelte` - Select/dropdown menus
|
||||
|
||||
**Apps using these**:
|
||||
|
||||
- ManaCore Web
|
||||
- Memoro Web
|
||||
- Maerchenzauber Web
|
||||
|
|
@ -77,6 +81,7 @@ All web apps now use the shared packages consistently:
|
|||
**Estimated LOC Savings**: 800-1200 per app
|
||||
|
||||
**Modules to unify**:
|
||||
|
||||
- `tokenManager.ts` - JWT token storage, refresh, validation
|
||||
- `authService.ts` - Login, logout, register, password reset
|
||||
- `supabaseClient.ts` - Authenticated Supabase client factory
|
||||
|
|
@ -84,6 +89,7 @@ All web apps now use the shared packages consistently:
|
|||
- `authGuard.ts` - Route protection utilities
|
||||
|
||||
**Considerations**:
|
||||
|
||||
- Each app may have different Supabase projects
|
||||
- Token storage strategy (localStorage vs cookies)
|
||||
- OAuth providers per app
|
||||
|
|
@ -97,6 +103,7 @@ All web apps now use the shared packages consistently:
|
|||
**Estimated Benefit**: Consistent branding, easier theme updates
|
||||
|
||||
**Config unified**:
|
||||
|
||||
- Color palette (primary, secondary, accent colors)
|
||||
- Theme variants (Lume, Nature, Stone, Ocean) with light/dark modes
|
||||
- Typography scale (font sizes, line heights)
|
||||
|
|
@ -105,6 +112,7 @@ All web apps now use the shared packages consistently:
|
|||
- CSS variable-based theming system
|
||||
|
||||
**Structure**:
|
||||
|
||||
```
|
||||
packages/shared-tailwind/
|
||||
├── package.json
|
||||
|
|
@ -117,6 +125,7 @@ packages/shared-tailwind/
|
|||
```
|
||||
|
||||
**Apps using this**:
|
||||
|
||||
- Memoro Web (full migration with theme.css + components.css)
|
||||
- ManaCore Web (preset only, keeps local colors)
|
||||
- ManaDeck Web (colors import, HSL-based system)
|
||||
|
|
@ -131,6 +140,7 @@ packages/shared-tailwind/
|
|||
**Estimated LOC Savings**: 200-400 per app
|
||||
|
||||
**Utilities included**:
|
||||
|
||||
- `date.ts` - formatDate, formatRelativeTime, toISOString
|
||||
- `format.ts` - formatDuration, formatFileSize, formatNumber, formatCurrency, formatPercent
|
||||
- `validation.ts` - isValidEmail, isValidUrl, isValidPhone, validatePassword, isValidUuid
|
||||
|
|
@ -146,6 +156,7 @@ packages/shared-tailwind/
|
|||
**Estimated Benefit**: Type safety across packages
|
||||
|
||||
**Types to unify**:
|
||||
|
||||
- `User` - Common user type
|
||||
- `ApiResponse<T>` - Standard API response wrapper
|
||||
- `PaginatedResponse<T>` - Pagination types
|
||||
|
|
@ -163,6 +174,7 @@ packages/shared-tailwind/
|
|||
**Estimated LOC Savings**: 100-300 per app
|
||||
|
||||
**Modules to unify**:
|
||||
|
||||
- `i18n.ts` - svelte-i18n setup and initialization
|
||||
- `detectLocale.ts` - Browser language detection
|
||||
- Common translations:
|
||||
|
|
@ -172,6 +184,7 @@ packages/shared-tailwind/
|
|||
- Validation messages
|
||||
|
||||
**Structure**:
|
||||
|
||||
```
|
||||
packages/shared-i18n/
|
||||
├── package.json
|
||||
|
|
@ -197,6 +210,7 @@ packages/shared-i18n/
|
|||
**Estimated Benefit**: Consistent env handling
|
||||
|
||||
**Config to unify**:
|
||||
|
||||
- Environment variable validation (Zod schemas)
|
||||
- API endpoint construction
|
||||
- Feature flag utilities
|
||||
|
|
@ -229,6 +243,7 @@ packages/shared-i18n/
|
|||
## Guidelines for Shared Packages
|
||||
|
||||
### Package Structure
|
||||
|
||||
```
|
||||
packages/shared-{name}/
|
||||
├── package.json
|
||||
|
|
@ -240,24 +255,26 @@ packages/shared-{name}/
|
|||
```
|
||||
|
||||
### Package.json Template
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@manacore/shared-{name}",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^5.0.0"
|
||||
}
|
||||
"name": "@manacore/shared-{name}",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^5.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Keep it minimal** - Only share truly common code
|
||||
2. **Document props** - Use TypeScript interfaces with JSDoc
|
||||
3. **Version carefully** - Coordinate updates across apps
|
||||
|
|
@ -273,6 +290,7 @@ packages/shared-{name}/
|
|||
Centralized branding configuration for all Mana ecosystem apps.
|
||||
|
||||
**Exports**:
|
||||
|
||||
- `AppLogo` - SVG logo component that renders app-specific logo
|
||||
- `AppLogoWithName` - Logo with app name and tagline
|
||||
- `ManaIcon` - Generic Mana icon component
|
||||
|
|
@ -280,9 +298,10 @@ Centralized branding configuration for all Mana ecosystem apps.
|
|||
- `AppId` type - Union type of all app IDs
|
||||
|
||||
**Usage**:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { AppLogo } from '@manacore/shared-branding';
|
||||
import { AppLogo } from '@manacore/shared-branding';
|
||||
</script>
|
||||
|
||||
<AppLogo app="memoro" size={32} />
|
||||
|
|
@ -294,6 +313,7 @@ Centralized branding configuration for all Mana ecosystem apps.
|
|||
Duration and formatting utilities.
|
||||
|
||||
**Exports**:
|
||||
|
||||
- `formatDuration(seconds)` - Returns `MM:SS` or `HH:MM:SS`
|
||||
- `formatDurationFromMs(ms)` - Converts milliseconds first
|
||||
- `formatDurationWithUnits(seconds, locale)` - Returns `2h 30m` style
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ This document provides a comprehensive automated testing strategy for the Manaco
|
|||
|
||||
### Existing Tests by Project
|
||||
|
||||
| Project | Backend | Mobile | Web | Total |
|
||||
|---------|---------|--------|-----|-------|
|
||||
| Maerchenzauber | 8 | 5 | 0 | 13 |
|
||||
| Memoro | 0 | 3 | 0 | 3 |
|
||||
| Uload | 0 | 0 | 9 | 9 |
|
||||
| **Total** | **8** | **8** | **9** | **25** |
|
||||
| Project | Backend | Mobile | Web | Total |
|
||||
| -------------- | ------- | ------ | ----- | ------ |
|
||||
| Maerchenzauber | 8 | 5 | 0 | 13 |
|
||||
| Memoro | 0 | 3 | 0 | 3 |
|
||||
| Uload | 0 | 0 | 9 | 9 |
|
||||
| **Total** | **8** | **8** | **9** | **25** |
|
||||
|
||||
### Strengths
|
||||
|
||||
|
|
@ -44,7 +44,9 @@ This document provides a comprehensive automated testing strategy for the Manaco
|
|||
### 1. Documentation (docs/)
|
||||
|
||||
#### [TESTING.md](./TESTING.md) - 35,000+ words
|
||||
|
||||
Comprehensive testing strategy covering:
|
||||
|
||||
- Testing infrastructure by app type
|
||||
- Test organization patterns
|
||||
- Coverage strategy (80% minimum, 100% for critical paths)
|
||||
|
|
@ -54,7 +56,9 @@ Comprehensive testing strategy covering:
|
|||
- Best practices and FAQs
|
||||
|
||||
#### [TESTING_IMPLEMENTATION_GUIDE.md](./TESTING_IMPLEMENTATION_GUIDE.md) - 8,000+ words
|
||||
|
||||
Quick start guide for developers:
|
||||
|
||||
- Step-by-step setup for each app type
|
||||
- Running tests locally
|
||||
- Coverage reports
|
||||
|
|
@ -62,6 +66,7 @@ Quick start guide for developers:
|
|||
- Quick reference commands
|
||||
|
||||
#### [TESTING_SUMMARY.md](./TESTING_SUMMARY.md) - This file
|
||||
|
||||
High-level overview and index of all testing resources.
|
||||
|
||||
### 2. Shared Test Configuration (packages/test-config/)
|
||||
|
|
@ -81,6 +86,7 @@ packages/test-config/
|
|||
```
|
||||
|
||||
**Features**:
|
||||
|
||||
- 80% coverage thresholds enforced
|
||||
- Auto-clear mocks between tests
|
||||
- Platform-specific ignore patterns
|
||||
|
|
@ -112,7 +118,9 @@ test-examples/
|
|||
### 4. CI/CD Integration (.github/workflows/)
|
||||
|
||||
#### [test.yml](./.github/workflows/test.yml)
|
||||
|
||||
Automated testing workflow with:
|
||||
|
||||
- Parallel test execution across all projects
|
||||
- Coverage reporting to Codecov
|
||||
- Automated PR comments with results
|
||||
|
|
@ -127,6 +135,7 @@ Automated testing workflow with:
|
|||
8. Status reporting
|
||||
|
||||
**Features**:
|
||||
|
||||
- Matrix strategy for parallel execution
|
||||
- Automatic coverage uploads
|
||||
- PR status checks
|
||||
|
|
@ -135,15 +144,15 @@ Automated testing workflow with:
|
|||
|
||||
## Testing Framework Matrix
|
||||
|
||||
| App Type | Framework | Config Location | Coverage Tool |
|
||||
|----------|-----------|----------------|---------------|
|
||||
| **NestJS Backend** | Jest | `@manacore/test-config/jest-backend` | Jest |
|
||||
| **React Native Mobile** | Jest + jest-expo | `@manacore/test-config/jest-mobile` | Jest |
|
||||
| **SvelteKit Web** | Vitest | `@manacore/test-config/vitest-svelte` | v8 |
|
||||
| **Astro Landing** | Vitest | `@manacore/test-config/vitest-base` | v8 |
|
||||
| **Shared Packages** | Vitest | `@manacore/test-config/vitest-base` | v8 |
|
||||
| **E2E (Web)** | Playwright | `@manacore/test-config/playwright` | N/A |
|
||||
| **E2E (Mobile)** | Detox/Maestro | TBD | N/A |
|
||||
| App Type | Framework | Config Location | Coverage Tool |
|
||||
| ----------------------- | ---------------- | ------------------------------------- | ------------- |
|
||||
| **NestJS Backend** | Jest | `@manacore/test-config/jest-backend` | Jest |
|
||||
| **React Native Mobile** | Jest + jest-expo | `@manacore/test-config/jest-mobile` | Jest |
|
||||
| **SvelteKit Web** | Vitest | `@manacore/test-config/vitest-svelte` | v8 |
|
||||
| **Astro Landing** | Vitest | `@manacore/test-config/vitest-base` | v8 |
|
||||
| **Shared Packages** | Vitest | `@manacore/test-config/vitest-base` | v8 |
|
||||
| **E2E (Web)** | Playwright | `@manacore/test-config/playwright` | N/A |
|
||||
| **E2E (Mobile)** | Detox/Maestro | TBD | N/A |
|
||||
|
||||
## Coverage Strategy
|
||||
|
||||
|
|
@ -336,10 +345,10 @@ it('should create item successfully', async () => {
|
|||
|
||||
```typescript
|
||||
// ✅ Good
|
||||
it('should reject sign in with invalid email format')
|
||||
it('should reject sign in with invalid email format');
|
||||
|
||||
// ❌ Bad
|
||||
it('test sign in')
|
||||
it('test sign in');
|
||||
```
|
||||
|
||||
### 3. Test Behavior, Not Implementation
|
||||
|
|
@ -457,6 +466,7 @@ afterEach(() => {
|
|||
This testing strategy provides a complete foundation for achieving 80% test coverage across the Manacore monorepo. All documentation, configurations, examples, and CI/CD integration are ready for implementation. The next step is to begin writing tests following the patterns and guidelines provided.
|
||||
|
||||
**Estimated Impact**:
|
||||
|
||||
- **Quality**: 80%+ reduction in bugs
|
||||
- **Confidence**: 100% confidence in deployments
|
||||
- **Velocity**: Faster feature development with safety net
|
||||
|
|
|
|||
|
|
@ -169,15 +169,16 @@ redis://uload-redis:6379
|
|||
|
||||
Da uload Teil eines Monorepos ist, muss die Build-Konfiguration genau so sein:
|
||||
|
||||
| Einstellung | Wert |
|
||||
|-------------|------|
|
||||
| **Base Directory** | `/` (leer lassen oder `/`) |
|
||||
| **Build Pack** | Dockerfile |
|
||||
| **Dockerfile Location** | `uload/Dockerfile` |
|
||||
| **Port Exposes** | `3000` |
|
||||
| Einstellung | Wert |
|
||||
| ----------------------- | -------------------------- |
|
||||
| **Base Directory** | `/` (leer lassen oder `/`) |
|
||||
| **Build Pack** | Dockerfile |
|
||||
| **Dockerfile Location** | `uload/Dockerfile` |
|
||||
| **Port Exposes** | `3000` |
|
||||
|
||||
**Warum `/` als Base Directory?**
|
||||
Das Dockerfile benötigt Zugriff auf:
|
||||
|
||||
- `uload/apps/web/` (die App)
|
||||
- `packages/shared-*` (gemeinsame Packages)
|
||||
- `pnpm-workspace.yaml` und `pnpm-lock.yaml` (Workspace-Config)
|
||||
|
|
@ -243,10 +244,10 @@ Kopiere das Ergebnis als `AUTH_SECRET`.
|
|||
|
||||
Bei deinem DNS-Provider (z.B. Cloudflare, Namecheap):
|
||||
|
||||
| Type | Name | Value | TTL |
|
||||
|------|------|-------|-----|
|
||||
| A | @ | DEINE-SERVER-IP | 3600 |
|
||||
| A | www | DEINE-SERVER-IP | 3600 |
|
||||
| Type | Name | Value | TTL |
|
||||
| ---- | ---- | --------------- | ---- |
|
||||
| A | @ | DEINE-SERVER-IP | 3600 |
|
||||
| A | www | DEINE-SERVER-IP | 3600 |
|
||||
|
||||
### 8.2 Domain in Coolify hinzufügen
|
||||
|
||||
|
|
@ -275,6 +276,7 @@ DNS-Änderungen können 5-30 Minuten dauern. SSL-Zertifikate werden automatisch
|
|||
Klicke auf das laufende Deployment um die Logs zu sehen.
|
||||
|
||||
**Erfolgreicher Build zeigt:**
|
||||
|
||||
```
|
||||
✔ done
|
||||
Listening on http://0.0.0.0:3000
|
||||
|
|
@ -321,8 +323,9 @@ curl https://ulo.ad/api/health
|
|||
```
|
||||
|
||||
Erwartete Antwort:
|
||||
|
||||
```json
|
||||
{"status":"ok","timestamp":"2025-11-25T12:00:00.000Z","uptime":123.45}
|
||||
{ "status": "ok", "timestamp": "2025-11-25T12:00:00.000Z", "uptime": 123.45 }
|
||||
```
|
||||
|
||||
### 11.2 Website öffnen
|
||||
|
|
@ -351,6 +354,7 @@ In Coolify: Application → **Redeploy**
|
|||
Application → **Logs**
|
||||
|
||||
**Via SSH:**
|
||||
|
||||
```bash
|
||||
docker logs -f $(docker ps -qf "name=uload")
|
||||
```
|
||||
|
|
@ -375,19 +379,19 @@ cat backup_20251125.sql | docker exec -i uload-postgres psql -U uload uload
|
|||
|
||||
### Build schlägt fehl
|
||||
|
||||
| Problem | Lösung |
|
||||
|---------|--------|
|
||||
| "Cannot find package" | Prüfe Base Directory (muss `/` sein) |
|
||||
| "pnpm-lock.yaml not found" | Prüfe dass pnpm-lock.yaml im Repo ist |
|
||||
| Timeout beim Build | Erhöhe Build-Timeout in Coolify Settings |
|
||||
| Problem | Lösung |
|
||||
| -------------------------- | ---------------------------------------- |
|
||||
| "Cannot find package" | Prüfe Base Directory (muss `/` sein) |
|
||||
| "pnpm-lock.yaml not found" | Prüfe dass pnpm-lock.yaml im Repo ist |
|
||||
| Timeout beim Build | Erhöhe Build-Timeout in Coolify Settings |
|
||||
|
||||
### Container startet nicht
|
||||
|
||||
| Problem | Lösung |
|
||||
|---------|--------|
|
||||
| "Missing API key" | Prüfe RESEND_API_KEY Environment Variable |
|
||||
| "Cannot connect to database" | Prüfe DATABASE_URL (Internal URL!) |
|
||||
| Port already in use | Prüfe ob alter Container noch läuft |
|
||||
| Problem | Lösung |
|
||||
| ---------------------------- | ----------------------------------------- |
|
||||
| "Missing API key" | Prüfe RESEND_API_KEY Environment Variable |
|
||||
| "Cannot connect to database" | Prüfe DATABASE_URL (Internal URL!) |
|
||||
| Port already in use | Prüfe ob alter Container noch läuft |
|
||||
|
||||
### SSL-Zertifikat Fehler
|
||||
|
||||
|
|
@ -429,18 +433,19 @@ cat backup_20251125.sql | docker exec -i uload-postgres psql -U uload uload
|
|||
|
||||
## Dateien im Repository
|
||||
|
||||
| Datei | Beschreibung |
|
||||
|-------|--------------|
|
||||
| `uload/Dockerfile` | Multi-Stage Docker Build |
|
||||
| `uload/docker-compose.yml` | Lokale Entwicklung |
|
||||
| `uload/docker-compose.coolify.yml` | Coolify Deployment |
|
||||
| `uload/docker-compose.prod.yml` | Standalone Production |
|
||||
| Datei | Beschreibung |
|
||||
| ---------------------------------- | ------------------------ |
|
||||
| `uload/Dockerfile` | Multi-Stage Docker Build |
|
||||
| `uload/docker-compose.yml` | Lokale Entwicklung |
|
||||
| `uload/docker-compose.coolify.yml` | Coolify Deployment |
|
||||
| `uload/docker-compose.prod.yml` | Standalone Production |
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
Bei Problemen:
|
||||
|
||||
1. Coolify Logs prüfen
|
||||
2. Container Logs prüfen (`docker logs`)
|
||||
3. GitHub Issues: https://github.com/anthropics/claude-code/issues
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ test-examples/
|
|||
### Backend Tests (NestJS)
|
||||
|
||||
#### `example.controller.spec.ts`
|
||||
|
||||
Demonstrates:
|
||||
|
||||
- Controller unit testing with mocked services
|
||||
- Request/response handling
|
||||
- Authentication/authorization testing
|
||||
|
|
@ -34,13 +36,16 @@ Demonstrates:
|
|||
- CRUD operations
|
||||
|
||||
**Key Patterns**:
|
||||
|
||||
- Use `@nestjs/testing` TestingModule
|
||||
- Mock all service dependencies
|
||||
- Test both success and error paths
|
||||
- Verify service method calls
|
||||
|
||||
#### `example.service.spec.ts`
|
||||
|
||||
Demonstrates:
|
||||
|
||||
- Service business logic testing
|
||||
- Database operation mocking
|
||||
- External API mocking
|
||||
|
|
@ -49,6 +54,7 @@ Demonstrates:
|
|||
- Authorization checks
|
||||
|
||||
**Key Patterns**:
|
||||
|
||||
- Mock database and external services
|
||||
- Test error handling thoroughly
|
||||
- Verify data transformations
|
||||
|
|
@ -57,7 +63,9 @@ Demonstrates:
|
|||
### Mobile Tests (React Native)
|
||||
|
||||
#### `ExampleComponent.test.tsx`
|
||||
|
||||
Demonstrates:
|
||||
|
||||
- Component rendering
|
||||
- User interactions (press, long press)
|
||||
- State management
|
||||
|
|
@ -67,13 +75,16 @@ Demonstrates:
|
|||
- Snapshot testing
|
||||
|
||||
**Key Patterns**:
|
||||
|
||||
- Use `@testing-library/react-native`
|
||||
- Test user behavior, not implementation
|
||||
- Verify accessibility props
|
||||
- Test loading and error states
|
||||
|
||||
#### `authService.test.ts`
|
||||
|
||||
Demonstrates:
|
||||
|
||||
- Async service testing
|
||||
- API call mocking with fetch
|
||||
- Storage operations (SecureStore)
|
||||
|
|
@ -82,6 +93,7 @@ Demonstrates:
|
|||
- Integration with other services
|
||||
|
||||
**Key Patterns**:
|
||||
|
||||
- Mock global fetch
|
||||
- Mock Expo modules (SecureStore)
|
||||
- Test timeout scenarios
|
||||
|
|
@ -90,7 +102,9 @@ Demonstrates:
|
|||
### Web Tests (SvelteKit)
|
||||
|
||||
#### `Button.test.ts`
|
||||
|
||||
Demonstrates:
|
||||
|
||||
- Svelte 5 component testing
|
||||
- Reactive state with runes ($state, $derived)
|
||||
- User events
|
||||
|
|
@ -100,13 +114,16 @@ Demonstrates:
|
|||
- Debouncing
|
||||
|
||||
**Key Patterns**:
|
||||
|
||||
- Use `@testing-library/svelte`
|
||||
- Test Svelte 5 reactivity
|
||||
- Verify accessibility attributes
|
||||
- Test custom event dispatch
|
||||
|
||||
#### `page.server.test.ts`
|
||||
|
||||
Demonstrates:
|
||||
|
||||
- Server load function testing
|
||||
- Form action testing
|
||||
- Database mocking (PocketBase)
|
||||
|
|
@ -116,6 +133,7 @@ Demonstrates:
|
|||
- File upload handling
|
||||
|
||||
**Key Patterns**:
|
||||
|
||||
- Mock `locals` object
|
||||
- Mock database client
|
||||
- Test redirect behavior
|
||||
|
|
@ -125,7 +143,9 @@ Demonstrates:
|
|||
### Shared Package Tests
|
||||
|
||||
#### `format.test.ts`
|
||||
|
||||
Demonstrates:
|
||||
|
||||
- Pure function testing
|
||||
- Parameterized tests (it.each)
|
||||
- Edge case testing
|
||||
|
|
@ -135,6 +155,7 @@ Demonstrates:
|
|||
- Unicode and emoji handling
|
||||
|
||||
**Key Patterns**:
|
||||
|
||||
- Test with multiple inputs using `it.each`
|
||||
- Cover edge cases thoroughly
|
||||
- Test security vulnerabilities
|
||||
|
|
@ -180,6 +201,7 @@ jest.mock('@your-project/custom-service', () => ({
|
|||
### 4. Reference Best Practices
|
||||
|
||||
Each file includes comments explaining:
|
||||
|
||||
- Why specific patterns are used
|
||||
- What to test and what not to test
|
||||
- Common pitfalls to avoid
|
||||
|
|
|
|||
|
|
@ -85,11 +85,15 @@ describe('ExampleController', () => {
|
|||
error: new Error('Validation failed'),
|
||||
});
|
||||
|
||||
await expect(controller.create(invalidDto, { user: mockUser })).rejects.toThrow(BadRequestException);
|
||||
await expect(controller.create(invalidDto, { user: mockUser })).rejects.toThrow(
|
||||
BadRequestException
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw UnauthorizedException when user is not authenticated', async () => {
|
||||
await expect(controller.create(createDto, { user: null })).rejects.toThrow(UnauthorizedException);
|
||||
await expect(controller.create(createDto, { user: null })).rejects.toThrow(
|
||||
UnauthorizedException
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle service errors gracefully', async () => {
|
||||
|
|
@ -155,7 +159,9 @@ describe('ExampleController', () => {
|
|||
error: new Error('Not found'),
|
||||
});
|
||||
|
||||
await expect(controller.findOne('invalid-id', { user: mockUser })).rejects.toThrow(NotFoundException);
|
||||
await expect(controller.findOne('invalid-id', { user: mockUser })).rejects.toThrow(
|
||||
NotFoundException
|
||||
);
|
||||
});
|
||||
|
||||
it('should not allow access to other users examples', async () => {
|
||||
|
|
@ -166,7 +172,9 @@ describe('ExampleController', () => {
|
|||
error: null,
|
||||
});
|
||||
|
||||
await expect(controller.findOne(exampleId, { user: mockUser })).rejects.toThrow(UnauthorizedException);
|
||||
await expect(controller.findOne(exampleId, { user: mockUser })).rejects.toThrow(
|
||||
UnauthorizedException
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -236,7 +244,9 @@ describe('ExampleController', () => {
|
|||
error: new Error('Not found'),
|
||||
});
|
||||
|
||||
await expect(controller.remove('invalid-id', { user: mockUser })).rejects.toThrow(NotFoundException);
|
||||
await expect(controller.remove('invalid-id', { user: mockUser })).rejects.toThrow(
|
||||
NotFoundException
|
||||
);
|
||||
});
|
||||
|
||||
it('should not allow deletion of other users examples', async () => {
|
||||
|
|
@ -245,7 +255,9 @@ describe('ExampleController', () => {
|
|||
error: new Error('Unauthorized'),
|
||||
});
|
||||
|
||||
await expect(controller.remove(exampleId, { user: mockUser })).rejects.toThrow(UnauthorizedException);
|
||||
await expect(controller.remove(exampleId, { user: mockUser })).rejects.toThrow(
|
||||
UnauthorizedException
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@ describe('ExampleComponent', () => {
|
|||
});
|
||||
|
||||
it('should render with testID for automation', () => {
|
||||
const { getByTestId } = render(<ExampleComponent {...defaultProps} testID="example-component" />);
|
||||
const { getByTestId } = render(
|
||||
<ExampleComponent {...defaultProps} testID="example-component" />
|
||||
);
|
||||
|
||||
expect(getByTestId('example-component')).toBeTruthy();
|
||||
});
|
||||
|
|
@ -78,7 +80,9 @@ describe('ExampleComponent', () => {
|
|||
});
|
||||
|
||||
it('should call onLongPress when long pressed', () => {
|
||||
const { getByText } = render(<ExampleComponent {...defaultProps} onLongPress={mockOnLongPress} />);
|
||||
const { getByText } = render(
|
||||
<ExampleComponent {...defaultProps} onLongPress={mockOnLongPress} />
|
||||
);
|
||||
|
||||
fireEvent(getByText('Test Title'), 'onLongPress');
|
||||
|
||||
|
|
@ -242,7 +246,9 @@ describe('ExampleComponent', () => {
|
|||
});
|
||||
|
||||
it('should handle undefined props gracefully', () => {
|
||||
const { getByText } = render(<ExampleComponent title="Test" onPress={mockOnPress} description={undefined} />);
|
||||
const { getByText } = render(
|
||||
<ExampleComponent title="Test" onPress={mockOnPress} description={undefined} />
|
||||
);
|
||||
|
||||
expect(getByText('Test')).toBeTruthy();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -72,7 +72,10 @@ describe('authService', () => {
|
|||
|
||||
// Verify tokens were stored
|
||||
expect(SecureStore.setItemAsync).toHaveBeenCalledWith('@auth/appToken', mockTokens.appToken);
|
||||
expect(SecureStore.setItemAsync).toHaveBeenCalledWith('@auth/refreshToken', mockTokens.refreshToken);
|
||||
expect(SecureStore.setItemAsync).toHaveBeenCalledWith(
|
||||
'@auth/refreshToken',
|
||||
mockTokens.refreshToken
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle invalid credentials error', async () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue