Compare commits
2
Commits
aa8de00969
...
94d02736f7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94d02736f7 | ||
|
|
2f7bd923df |
No files matched your search
@@ -27,15 +27,15 @@ LOG_LEVEL=debug
|
|||||||
# DB_USERNAME=root
|
# DB_USERNAME=root
|
||||||
# DB_PASSWORD=
|
# DB_PASSWORD=
|
||||||
|
|
||||||
# Secondary PostgreSQL Connection (for backend schema)
|
# Secondary PostgreSQL Connection (for backend schema) - Local Docker
|
||||||
DB_CONNECTION2=pgsql
|
DB_CONNECTION2=pgsql
|
||||||
DB_HOST2=127.0.0.1
|
DB_HOST2=127.0.0.1
|
||||||
DB_PORT2=5433
|
DB_PORT2=5432
|
||||||
DB_DATABASE2=risk_ingest_db
|
DB_DATABASE2=ingest_db
|
||||||
DB_USERNAME2=risk_ingest_user
|
DB_USERNAME2=ingest_user
|
||||||
DB_PASSWORD2=S0prast3r1a
|
DB_PASSWORD2=ingest_pwd
|
||||||
|
|
||||||
SESSION_DRIVER=database
|
SESSION_DRIVER=file
|
||||||
SESSION_LIFETIME=120
|
SESSION_LIFETIME=120
|
||||||
SESSION_ENCRYPT=false
|
SESSION_ENCRYPT=false
|
||||||
SESSION_PATH=/
|
SESSION_PATH=/
|
||||||
@@ -43,9 +43,9 @@ SESSION_DOMAIN=null
|
|||||||
|
|
||||||
BROADCAST_CONNECTION=log
|
BROADCAST_CONNECTION=log
|
||||||
FILESYSTEM_DISK=local
|
FILESYSTEM_DISK=local
|
||||||
QUEUE_CONNECTION=database
|
QUEUE_CONNECTION=sync
|
||||||
|
|
||||||
CACHE_STORE=database
|
CACHE_STORE=file
|
||||||
# CACHE_PREFIX=
|
# CACHE_PREFIX=
|
||||||
|
|
||||||
MEMCACHED_HOST=127.0.0.1
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Gitea Runner Configuration
|
||||||
|
# Kopiere diese Datei zu .env.gitea-runner und passe die Werte an
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Gitea Instance
|
||||||
|
# ============================================
|
||||||
|
# URL deiner Gitea-Installation
|
||||||
|
# Wenn Gitea auf der gleichen NAS läuft:
|
||||||
|
GITEA_URL=http://your-synology-ip:3000
|
||||||
|
|
||||||
|
# Wenn Gitea in Docker läuft und im gleichen Netzwerk:
|
||||||
|
# GITEA_URL=http://gitea:3000
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Runner Configuration
|
||||||
|
# ============================================
|
||||||
|
# Runner Registration Token
|
||||||
|
# Generiere diesen Token in Gitea:
|
||||||
|
# Repository → Settings → Actions → Runners → Create new Runner
|
||||||
|
RUNNER_TOKEN=your_gitea_runner_registration_token_here
|
||||||
|
|
||||||
|
# Runner Name (wird in Gitea angezeigt)
|
||||||
|
RUNNER_NAME=synology-runner
|
||||||
|
|
||||||
|
# Maximale Anzahl gleichzeitiger Jobs
|
||||||
|
RUNNER_CAPACITY=1
|
||||||
|
|
||||||
|
# Log Level: trace, debug, info, warn, error, fatal
|
||||||
|
LOG_LEVEL=info
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# Laravel Application Configuration für Synology NAS Deployment
|
||||||
|
# Kopiere diese Datei zu .env.synology und passe die Werte an
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Application Settings
|
||||||
|
# ============================================
|
||||||
|
APP_NAME=Laravel
|
||||||
|
APP_ENV=production
|
||||||
|
APP_KEY=base64:L9RVZ3pNFyAvTbMqicT1rL5GbgE+7lJerkU9wyc95H8=
|
||||||
|
APP_DEBUG=false
|
||||||
|
APP_URL=http://your-synology-ip:8080
|
||||||
|
|
||||||
|
APP_LOCALE=en
|
||||||
|
APP_FALLBACK_LOCALE=en
|
||||||
|
APP_FAKER_LOCALE=en_US
|
||||||
|
|
||||||
|
APP_MAINTENANCE_DRIVER=file
|
||||||
|
|
||||||
|
BCRYPT_ROUNDS=12
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Logging
|
||||||
|
# ============================================
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_STACK=single
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=info
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Database - PostgreSQL (Haupt-Datenbank)
|
||||||
|
# ============================================
|
||||||
|
DB_CONNECTION2=pgsql
|
||||||
|
DB_HOST2=postgres
|
||||||
|
DB_PORT2=5432
|
||||||
|
DB_DATABASE2=ingest_db
|
||||||
|
DB_USERNAME2=ingest_user
|
||||||
|
DB_PASSWORD2=ingest_pwd
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Session & Cache
|
||||||
|
# ============================================
|
||||||
|
SESSION_DRIVER=file
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
SESSION_ENCRYPT=false
|
||||||
|
SESSION_PATH=/
|
||||||
|
SESSION_DOMAIN=null
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Broadcasting & Queues
|
||||||
|
# ============================================
|
||||||
|
BROADCAST_CONNECTION=log
|
||||||
|
QUEUE_CONNECTION=sync
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Cache
|
||||||
|
# ============================================
|
||||||
|
CACHE_STORE=file
|
||||||
|
FILESYSTEM_DISK=local
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Mail Configuration
|
||||||
|
# ============================================
|
||||||
|
MAIL_MAILER=log
|
||||||
|
MAIL_SCHEME=null
|
||||||
|
MAIL_HOST=127.0.0.1
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_FROM_ADDRESS="hello@example.com"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Vite
|
||||||
|
# ============================================
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
name: Build and Deploy to Synology NAS
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
env:
|
||||||
|
DOCKER_IMAGE: laravel-app
|
||||||
|
DOCKER_REGISTRY: ${{ secrets.SYNOLOGY_HOST }}:5000 # Synology Docker Registry Port
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Job 1: Run Tests
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
|
- name: Validate Conventional Commit (subject line only)
|
||||||
|
id: validate
|
||||||
|
run: |
|
||||||
|
SUBJECT="$(git log -1 --pretty=%s)"
|
||||||
|
echo "Commit subject: $SUBJECT"
|
||||||
|
if echo "$SUBJECT" | grep -Eq '^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .+'; then
|
||||||
|
echo "valid=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "valid=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.4'
|
||||||
|
extensions: mbstring, xml, ctype, json, bcmath, pdo, pdo_sqlite
|
||||||
|
coverage: none
|
||||||
|
|
||||||
|
- name: Install Composer Dependencies
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
run: composer install --prefer-dist --no-progress --no-suggest
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install NPM Dependencies
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Build Frontend Assets
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Run Tests
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
run: php artisan test
|
||||||
|
|
||||||
|
# Job 2: Build and Push Docker Image
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Validate Conventional Commit
|
||||||
|
id: validate
|
||||||
|
run: |
|
||||||
|
SUBJECT="$(git log -1 --pretty=%s)"
|
||||||
|
echo "Commit subject: $SUBJECT"
|
||||||
|
if echo "$SUBJECT" | grep -Eq '^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .+'; then
|
||||||
|
echo "valid=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "valid=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Stop if not a Conventional Commit
|
||||||
|
if: ${{ steps.validate.outputs.valid != 'true' }}
|
||||||
|
run: |
|
||||||
|
echo "Latest commit is not a valid Conventional Commit. Skipping build."
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Determine Docker Tag
|
||||||
|
id: docker_tag
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.ref_name }}" == "main" ]; then
|
||||||
|
echo "tag=latest" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "env=production" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "tag=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "env=staging" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build Docker Image
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
push: false
|
||||||
|
load: true
|
||||||
|
tags: ${{ env.DOCKER_IMAGE }}:${{ steps.docker_tag.outputs.tag }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Save Docker Image
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
run: |
|
||||||
|
docker save ${{ env.DOCKER_IMAGE }}:${{ steps.docker_tag.outputs.tag }} | gzip > laravel-app.tar.gz
|
||||||
|
|
||||||
|
- name: Upload Docker Image Artifact
|
||||||
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: docker-image
|
||||||
|
path: laravel-app.tar.gz
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
# Job 3: Deploy to Synology NAS
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
if: github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'develop')
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Download Docker Image Artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: docker-image
|
||||||
|
|
||||||
|
- name: Determine Environment
|
||||||
|
id: env
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.ref_name }}" == "main" ]; then
|
||||||
|
echo "env=production" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "env=staging" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Setup SSH
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "${{ secrets.SYNOLOGY_SSH_KEY }}" > ~/.ssh/synology_key
|
||||||
|
chmod 600 ~/.ssh/synology_key
|
||||||
|
ssh-keyscan -H ${{ secrets.SYNOLOGY_HOST }} >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Copy Files to Synology
|
||||||
|
run: |
|
||||||
|
# Transfer Docker Image
|
||||||
|
scp -i ~/.ssh/synology_key laravel-app.tar.gz \
|
||||||
|
${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }}:/volume1/docker/laravel-app/
|
||||||
|
|
||||||
|
# Transfer Docker Compose file
|
||||||
|
scp -i ~/.ssh/synology_key docker-compose.synology.yml \
|
||||||
|
${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }}:/volume1/docker/laravel-app/
|
||||||
|
|
||||||
|
# Transfer deployment script
|
||||||
|
scp -i ~/.ssh/synology_key scripts/deploy-synology.sh \
|
||||||
|
${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }}:/volume1/docker/laravel-app/
|
||||||
|
|
||||||
|
- name: Deploy on Synology
|
||||||
|
run: |
|
||||||
|
ssh -i ~/.ssh/synology_key \
|
||||||
|
${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \
|
||||||
|
"cd /volume1/docker/laravel-app && chmod +x deploy-synology.sh && ./deploy-synology.sh"
|
||||||
|
|
||||||
|
- name: Health Check
|
||||||
|
run: |
|
||||||
|
sleep 10 # Wait for container to start
|
||||||
|
|
||||||
|
# Check if the app is responding
|
||||||
|
SYNOLOGY_IP="${{ secrets.SYNOLOGY_HOST }}"
|
||||||
|
MAX_RETRIES=30
|
||||||
|
RETRY_COUNT=0
|
||||||
|
|
||||||
|
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
|
||||||
|
if curl -f -s http://$SYNOLOGY_IP:8080/health > /dev/null 2>&1; then
|
||||||
|
echo "✅ Application is healthy!"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "⏳ Waiting for application to be ready... ($RETRY_COUNT/$MAX_RETRIES)"
|
||||||
|
sleep 5
|
||||||
|
RETRY_COUNT=$((RETRY_COUNT + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "❌ Health check failed after $MAX_RETRIES attempts"
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
rm -f ~/.ssh/synology_key
|
||||||
|
ssh -i ~/.ssh/synology_key \
|
||||||
|
${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \
|
||||||
|
"rm -f /volume1/docker/laravel-app/laravel-app.tar.gz" || true
|
||||||
|
|
||||||
|
# Job 4: Notify on Success/Failure (optional)
|
||||||
|
notify:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [test, build, deploy]
|
||||||
|
if: always()
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Deployment Status
|
||||||
|
run: |
|
||||||
|
if [ "${{ needs.deploy.result }}" == "success" ]; then
|
||||||
|
echo "✅ Deployment to Synology NAS successful!"
|
||||||
|
echo "🌐 Application available at: http://${{ secrets.SYNOLOGY_HOST }}:8080"
|
||||||
|
else
|
||||||
|
echo "❌ Deployment failed. Check the logs for details."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -39,6 +39,14 @@ yarn-error.log
|
|||||||
/database/*.sqlite
|
/database/*.sqlite
|
||||||
/database/*.sqlite-journal
|
/database/*.sqlite-journal
|
||||||
*.sql.gz
|
*.sql.gz
|
||||||
|
/backups
|
||||||
|
|
||||||
|
# CI/CD & Deployment
|
||||||
|
.env.synology
|
||||||
|
.env.gitea-runner
|
||||||
|
kubeconfig
|
||||||
|
*.tar.gz
|
||||||
|
laravel-app.tar.gz
|
||||||
|
|
||||||
# Backup & Temporary Files
|
# Backup & Temporary Files
|
||||||
*.bak
|
*.bak
|
||||||
|
|||||||
+281
@@ -0,0 +1,281 @@
|
|||||||
|
# CI/CD Automatisierung für Synology NAS
|
||||||
|
|
||||||
|
Dieses Projekt ist vollständig für automatisches Deployment auf deiner Synology NAS mit Gitea Actions vorbereitet.
|
||||||
|
|
||||||
|
## 🚀 Schnellstart
|
||||||
|
|
||||||
|
### 1. Gitea Runner einrichten (einmalig)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Auf der Synology NAS
|
||||||
|
cd /volume1/docker
|
||||||
|
mkdir gitea-runner
|
||||||
|
cd gitea-runner
|
||||||
|
|
||||||
|
# Environment Datei erstellen
|
||||||
|
cat > .env << 'EOF'
|
||||||
|
GITEA_URL=http://your-synology-ip:3000
|
||||||
|
RUNNER_TOKEN=your_token_from_gitea
|
||||||
|
RUNNER_NAME=synology-runner
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Runner starten
|
||||||
|
docker-compose -f /path/to/docker-compose.gitea-runner.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
**Runner Token generieren:**
|
||||||
|
1. Gitea öffnen
|
||||||
|
2. Repository → Settings → Actions → Runners
|
||||||
|
3. "Create new Runner" klicken
|
||||||
|
4. Token kopieren und in `.env` einfügen
|
||||||
|
|
||||||
|
📖 Detaillierte Anleitung: [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md)
|
||||||
|
|
||||||
|
### 2. Repository Secrets konfigurieren (einmalig)
|
||||||
|
|
||||||
|
In Gitea: **Repository → Settings → Secrets**
|
||||||
|
|
||||||
|
| Secret Name | Wert | Beschreibung |
|
||||||
|
|------------|------|--------------|
|
||||||
|
| `SYNOLOGY_HOST` | `192.168.1.100` | IP deiner Synology |
|
||||||
|
| `SYNOLOGY_USER` | `admin` | SSH-Benutzername |
|
||||||
|
| `SYNOLOGY_SSH_KEY` | `-----BEGIN...` | Private SSH-Key |
|
||||||
|
| `APP_KEY` | `base64:...` | Laravel APP_KEY |
|
||||||
|
|
||||||
|
**SSH-Key erstellen:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Auf der Synology NAS
|
||||||
|
ssh-keygen -t ed25519 -C "gitea-deploy" -f ~/.ssh/gitea_deploy
|
||||||
|
cat ~/.ssh/gitea_deploy.pub >> ~/.ssh/authorized_keys
|
||||||
|
cat ~/.ssh/gitea_deploy # Diesen Key als Secret verwenden
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Code pushen und automatisch deployen! 🎉
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "feat: meine neue Funktion"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
Das wars! Der Rest läuft automatisch:
|
||||||
|
- ✅ Tests werden ausgeführt
|
||||||
|
- ✅ Docker Image wird gebaut
|
||||||
|
- ✅ Deployment auf NAS
|
||||||
|
- ✅ Health Check
|
||||||
|
- ✅ Benachrichtigung bei Erfolg/Fehler
|
||||||
|
|
||||||
|
## 📁 Wichtige Dateien
|
||||||
|
|
||||||
|
| Datei | Beschreibung |
|
||||||
|
|-------|--------------|
|
||||||
|
| [`.gitea/workflows/deploy-synology.yml`](.gitea/workflows/deploy-synology.yml) | Gitea Actions Workflow |
|
||||||
|
| [`docker-compose.synology.yml`](docker-compose.synology.yml) | Docker Compose für Deployment |
|
||||||
|
| [`scripts/deploy-synology.sh`](scripts/deploy-synology.sh) | Deployment-Script |
|
||||||
|
| [`.env.synology.example`](.env.synology.example) | Environment-Beispiel |
|
||||||
|
| [`SYNOLOGY_DEPLOYMENT.md`](SYNOLOGY_DEPLOYMENT.md) | Vollständige Deployment-Doku |
|
||||||
|
| [`GITEA_RUNNER_SETUP.md`](GITEA_RUNNER_SETUP.md) | Gitea Runner Setup-Anleitung |
|
||||||
|
|
||||||
|
## 🔄 Workflow-Prozess
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Developer pushed Code zu Gitea
|
||||||
|
↓
|
||||||
|
2. Gitea Actions Workflow startet
|
||||||
|
↓
|
||||||
|
3. Tests laufen (Pest)
|
||||||
|
↓
|
||||||
|
4. Docker Image wird gebaut
|
||||||
|
↓
|
||||||
|
5. Image wird zur Synology NAS übertragen
|
||||||
|
↓
|
||||||
|
6. Deployment-Script läuft auf NAS
|
||||||
|
↓
|
||||||
|
7. Container werden aktualisiert
|
||||||
|
↓
|
||||||
|
8. Migrationen & Cache-Optimierung
|
||||||
|
↓
|
||||||
|
9. Health Check
|
||||||
|
↓
|
||||||
|
10. ✅ Deployment erfolgreich!
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Features
|
||||||
|
|
||||||
|
### Automatisierte Tests
|
||||||
|
- PHP-Tests mit Pest
|
||||||
|
- Frontend-Build-Validierung
|
||||||
|
- Nur erfolgreiche Builds werden deployed
|
||||||
|
|
||||||
|
### Intelligentes Deployment
|
||||||
|
- Automatisches Backup vor Deployment
|
||||||
|
- Rollback bei Fehlern
|
||||||
|
- Health Checks nach Deployment
|
||||||
|
- Zero-Downtime durch Docker
|
||||||
|
|
||||||
|
### Branch-spezifisches Deployment
|
||||||
|
- `main` → Production (Port 8080)
|
||||||
|
- `develop` → Staging (Port 8081)
|
||||||
|
- Feature-Branches → Nur Tests
|
||||||
|
|
||||||
|
### Conventional Commits
|
||||||
|
Der Workflow akzeptiert nur Conventional Commits:
|
||||||
|
- `feat:` - Neue Features
|
||||||
|
- `fix:` - Bugfixes
|
||||||
|
- `docs:` - Dokumentation
|
||||||
|
- `chore:` - Wartung
|
||||||
|
- `refactor:` - Code-Refactoring
|
||||||
|
- `test:` - Tests
|
||||||
|
- `ci:` - CI/CD Änderungen
|
||||||
|
|
||||||
|
**Beispiel:**
|
||||||
|
```bash
|
||||||
|
git commit -m "feat: add user authentication"
|
||||||
|
git commit -m "fix: resolve database connection issue"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔍 Monitoring
|
||||||
|
|
||||||
|
### Workflow Status prüfen
|
||||||
|
|
||||||
|
**In Gitea:**
|
||||||
|
1. Repository öffnen
|
||||||
|
2. Tab "Actions" anklicken
|
||||||
|
3. Alle Runs mit Status sehen
|
||||||
|
|
||||||
|
**Logs ansehen:**
|
||||||
|
- Klicke auf einen Run
|
||||||
|
- Klicke auf einen Job (test/build/deploy)
|
||||||
|
- Sieh detaillierte Logs
|
||||||
|
|
||||||
|
### Container Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Auf der Synology NAS via SSH
|
||||||
|
docker logs -f laravel_app
|
||||||
|
docker logs -f laravel_postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Endpoint
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://your-synology-ip:8080/health
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "healthy",
|
||||||
|
"timestamp": "2025-12-17T10:30:00Z",
|
||||||
|
"app": "Laravel",
|
||||||
|
"env": "production"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠 Manuelle Befehle
|
||||||
|
|
||||||
|
### Manuelles Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Auf der Synology NAS
|
||||||
|
cd /volume1/docker/laravel-app
|
||||||
|
./scripts/deploy-synology.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Container verwalten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Status prüfen
|
||||||
|
docker-compose -f docker-compose.synology.yml ps
|
||||||
|
|
||||||
|
# Logs ansehen
|
||||||
|
docker-compose -f docker-compose.synology.yml logs -f
|
||||||
|
|
||||||
|
# Neustart
|
||||||
|
docker-compose -f docker-compose.synology.yml restart
|
||||||
|
|
||||||
|
# Stoppen
|
||||||
|
docker-compose -f docker-compose.synology.yml down
|
||||||
|
```
|
||||||
|
|
||||||
|
### Laravel Artisan
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Migrationen
|
||||||
|
docker exec laravel_app php artisan migrate
|
||||||
|
|
||||||
|
# Cache leeren
|
||||||
|
docker exec laravel_app php artisan cache:clear
|
||||||
|
|
||||||
|
# Shell öffnen
|
||||||
|
docker exec -it laravel_app sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
|
### Workflow startet nicht
|
||||||
|
|
||||||
|
**Prüfen:**
|
||||||
|
1. Runner Status in Gitea → Settings → Actions → Runners
|
||||||
|
2. Commit-Message ist Conventional Commit Format
|
||||||
|
3. Branch ist `main` oder `develop`
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# Runner neu starten
|
||||||
|
docker restart gitea-runner
|
||||||
|
|
||||||
|
# Runner Logs prüfen
|
||||||
|
docker logs gitea-runner
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deployment schlägt fehl
|
||||||
|
|
||||||
|
**Prüfen:**
|
||||||
|
1. SSH-Verbindung zur NAS funktioniert
|
||||||
|
2. Alle Secrets sind korrekt gesetzt
|
||||||
|
3. Deployment-Script ist executable
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# SSH-Key testen
|
||||||
|
ssh -i ~/.ssh/gitea_deploy admin@your-synology-ip
|
||||||
|
|
||||||
|
# Permissions prüfen
|
||||||
|
chmod +x scripts/deploy-synology.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Check fehlschlägt
|
||||||
|
|
||||||
|
**Prüfen:**
|
||||||
|
1. Container läuft: `docker ps | grep laravel_app`
|
||||||
|
2. Logs: `docker logs laravel_app`
|
||||||
|
3. Netzwerk: `curl http://localhost:8080/health`
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# Container neu starten
|
||||||
|
docker-compose -f docker-compose.synology.yml restart
|
||||||
|
|
||||||
|
# .env prüfen
|
||||||
|
docker exec laravel_app cat .env.synology
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📚 Weitere Dokumentation
|
||||||
|
|
||||||
|
- **Deployment Details:** [SYNOLOGY_DEPLOYMENT.md](SYNOLOGY_DEPLOYMENT.md)
|
||||||
|
- **Gitea Runner Setup:** [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md)
|
||||||
|
- **Workflow Konfiguration:** [.gitea/workflows/deploy-synology.yml](.gitea/workflows/deploy-synology.yml)
|
||||||
|
- **Deployment Script:** [scripts/deploy-synology.sh](scripts/deploy-synology.sh)
|
||||||
|
|
||||||
|
## 🎉 Das wars!
|
||||||
|
|
||||||
|
Nach der einmaligen Einrichtung läuft alles automatisch:
|
||||||
|
|
||||||
|
1. Code schreiben
|
||||||
|
2. Commit & Push
|
||||||
|
3. Warten bis Deployment fertig ist
|
||||||
|
4. Anwendung ist live! 🚀
|
||||||
|
|
||||||
|
**Happy Deploying!** 🎊
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
# Deployment Files Übersicht
|
||||||
|
|
||||||
|
Diese Datei gibt einen Überblick über alle Dateien, die für das automatisierte Deployment auf deiner Synology NAS erstellt wurden.
|
||||||
|
|
||||||
|
## 📋 Erstelle Dateien
|
||||||
|
|
||||||
|
### 1. CI/CD Workflow
|
||||||
|
- **`.gitea/workflows/deploy-synology.yml`**
|
||||||
|
- Gitea Actions Workflow für automatisches Build & Deployment
|
||||||
|
- Führt Tests aus, baut Docker Image, deployt auf NAS
|
||||||
|
- Triggert bei Push auf `main` oder `develop`
|
||||||
|
|
||||||
|
### 2. Docker Konfiguration
|
||||||
|
- **`docker-compose.synology.yml`**
|
||||||
|
- Docker Compose für Synology NAS Deployment
|
||||||
|
- Definiert Laravel App + PostgreSQL Datenbank
|
||||||
|
- Mit persistenten Volumes und Health Checks
|
||||||
|
|
||||||
|
- **`docker-compose.gitea-runner.yml`**
|
||||||
|
- Docker Compose für Gitea Runner
|
||||||
|
- Ermöglicht automatische Workflows
|
||||||
|
|
||||||
|
- **`Dockerfile`**
|
||||||
|
- Bereits vorhanden, wird verwendet für Image-Build
|
||||||
|
- Multi-stage Build für optimale Image-Größe
|
||||||
|
|
||||||
|
### 3. Environment Konfiguration
|
||||||
|
- **`.env.synology.example`**
|
||||||
|
- Beispiel-Environment für Synology Deployment
|
||||||
|
- Muss kopiert werden zu `.env.synology`
|
||||||
|
- Enthält alle notwendigen Variablen
|
||||||
|
|
||||||
|
- **`.env.gitea-runner.example`**
|
||||||
|
- Beispiel-Environment für Gitea Runner
|
||||||
|
- Muss kopiert werden zu `.env.gitea-runner`
|
||||||
|
|
||||||
|
### 4. Deployment Scripts
|
||||||
|
- **`scripts/deploy-synology.sh`**
|
||||||
|
- Automatisches Deployment-Script
|
||||||
|
- Läuft auf der Synology NAS
|
||||||
|
- Handhabt Backup, Deployment, Rollback, Health Checks
|
||||||
|
|
||||||
|
### 5. Dokumentation
|
||||||
|
- **`SYNOLOGY_DEPLOYMENT.md`**
|
||||||
|
- Vollständige Anleitung für manuelles Deployment
|
||||||
|
- Inklusive CI/CD Setup Abschnitt
|
||||||
|
- Troubleshooting Tipps
|
||||||
|
|
||||||
|
- **`GITEA_RUNNER_SETUP.md`**
|
||||||
|
- Detaillierte Anleitung für Gitea Runner Setup
|
||||||
|
- Secrets-Konfiguration
|
||||||
|
- Monitoring & Troubleshooting
|
||||||
|
|
||||||
|
- **`CI_CD_README.md`**
|
||||||
|
- Schnellstart-Anleitung für CI/CD
|
||||||
|
- Übersicht über alle Features
|
||||||
|
- Wichtige Befehle
|
||||||
|
|
||||||
|
- **`DEPLOYMENT_FILES_OVERVIEW.md`** (diese Datei)
|
||||||
|
- Übersicht über alle erstellten Dateien
|
||||||
|
|
||||||
|
### 6. Application Code
|
||||||
|
- **`routes/web.php`**
|
||||||
|
- Health Check Endpoint hinzugefügt (`/health`)
|
||||||
|
- Wird für automatische Health Checks verwendet
|
||||||
|
|
||||||
|
### 7. Git Konfiguration
|
||||||
|
- **`.gitignore`**
|
||||||
|
- Erweitert um CI/CD spezifische Dateien
|
||||||
|
- `.env.synology` und `.env.gitea-runner` ignoriert
|
||||||
|
- Build-Artefakte ignoriert
|
||||||
|
|
||||||
|
## 🔧 Verwendung der Dateien
|
||||||
|
|
||||||
|
### Einmalige Einrichtung
|
||||||
|
|
||||||
|
1. **Gitea Runner deployen:**
|
||||||
|
```bash
|
||||||
|
# Auf Synology NAS
|
||||||
|
cp .env.gitea-runner.example .env.gitea-runner
|
||||||
|
# Bearbeite .env.gitea-runner mit deinen Werten
|
||||||
|
docker-compose -f docker-compose.gitea-runner.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Repository Secrets in Gitea setzen:**
|
||||||
|
- `SYNOLOGY_HOST`
|
||||||
|
- `SYNOLOGY_USER`
|
||||||
|
- `SYNOLOGY_SSH_KEY`
|
||||||
|
- `APP_KEY`
|
||||||
|
|
||||||
|
3. **Workflow-Dateien committen:**
|
||||||
|
```bash
|
||||||
|
git add .gitea/
|
||||||
|
git commit -m "ci: add automated deployment"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manuelles Deployment
|
||||||
|
|
||||||
|
Falls du manuell deployen möchtest (ohne CI/CD):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Auf Synology NAS
|
||||||
|
cd /volume1/docker/laravel-app
|
||||||
|
cp .env.synology.example .env.synology
|
||||||
|
# Bearbeite .env.synology
|
||||||
|
docker-compose -f docker-compose.synology.yml up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 Datei-Abhängigkeiten
|
||||||
|
|
||||||
|
```
|
||||||
|
.gitea/workflows/deploy-synology.yml
|
||||||
|
├── docker-compose.synology.yml
|
||||||
|
├── scripts/deploy-synology.sh
|
||||||
|
├── .env.synology (zu erstellen)
|
||||||
|
└── Dockerfile
|
||||||
|
|
||||||
|
docker-compose.gitea-runner.yml
|
||||||
|
└── .env.gitea-runner (zu erstellen)
|
||||||
|
```
|
||||||
|
|
||||||
|
## ✅ Checkliste für Deployment
|
||||||
|
|
||||||
|
### Vor dem ersten Deployment:
|
||||||
|
|
||||||
|
- [ ] Gitea Runner deployed (`docker-compose.gitea-runner.yml`)
|
||||||
|
- [ ] Runner in Gitea registriert
|
||||||
|
- [ ] Repository Secrets gesetzt
|
||||||
|
- [ ] `.env.synology` auf NAS erstellt und konfiguriert
|
||||||
|
- [ ] SSH-Keys für Deployment eingerichtet
|
||||||
|
- [ ] Projekt-Verzeichnis auf NAS: `/volume1/docker/laravel-app`
|
||||||
|
|
||||||
|
### Vor jedem Push:
|
||||||
|
|
||||||
|
- [ ] Tests lokal ausgeführt (`php artisan test`)
|
||||||
|
- [ ] Conventional Commit Message verwendet
|
||||||
|
- [ ] Code reviewed
|
||||||
|
|
||||||
|
### Nach dem Deployment:
|
||||||
|
|
||||||
|
- [ ] Workflow Status in Gitea Actions überprüft
|
||||||
|
- [ ] Health Check erfolgreich: `curl http://nas-ip:8080/health`
|
||||||
|
- [ ] Anwendung erreichbar: `http://nas-ip:8080`
|
||||||
|
- [ ] Logs prüfen: `docker logs laravel_app`
|
||||||
|
|
||||||
|
## 🔐 Sicherheit
|
||||||
|
|
||||||
|
### Dateien die NICHT committet werden sollten:
|
||||||
|
|
||||||
|
- `.env.synology` - Enthält Produktions-Secrets
|
||||||
|
- `.env.gitea-runner` - Enthält Runner-Token
|
||||||
|
- `kubeconfig` - Falls verwendet
|
||||||
|
- `*.tar.gz` - Build-Artefakte
|
||||||
|
- SSH Private Keys
|
||||||
|
|
||||||
|
Diese Dateien sind bereits in `.gitignore` eingetragen!
|
||||||
|
|
||||||
|
### Dateien die committet werden sollten:
|
||||||
|
|
||||||
|
- `.env.synology.example` - Template für andere Entwickler
|
||||||
|
- `.env.gitea-runner.example` - Template für Runner
|
||||||
|
- Alle `docker-compose*.yml` Dateien
|
||||||
|
- Alle Dokumentations-Dateien
|
||||||
|
- Workflow-Dateien in `.gitea/workflows/`
|
||||||
|
- Deployment-Scripts in `scripts/`
|
||||||
|
|
||||||
|
## 🚀 Nächste Schritte
|
||||||
|
|
||||||
|
1. **Lies die Dokumentation:**
|
||||||
|
- Start mit [CI_CD_README.md](CI_CD_README.md) für Schnellstart
|
||||||
|
- Dann [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md) für Runner-Setup
|
||||||
|
- Bei Problemen: [SYNOLOGY_DEPLOYMENT.md](SYNOLOGY_DEPLOYMENT.md)
|
||||||
|
|
||||||
|
2. **Setup durchführen:**
|
||||||
|
- Folge der Anleitung in [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md)
|
||||||
|
- Konfiguriere Secrets in Gitea
|
||||||
|
- Teste mit einem Push
|
||||||
|
|
||||||
|
3. **Deployment testen:**
|
||||||
|
- Mache eine kleine Änderung
|
||||||
|
- Committe mit Conventional Commit
|
||||||
|
- Push und beobachte Workflow in Gitea Actions
|
||||||
|
|
||||||
|
4. **Optional: Erweitere Workflow:**
|
||||||
|
- Füge Notifications hinzu (Email, Telegram, Discord)
|
||||||
|
- Konfiguriere mehrere Environments (Staging, Production)
|
||||||
|
- Füge weitere Tests hinzu
|
||||||
|
|
||||||
|
## 📝 Hinweise
|
||||||
|
|
||||||
|
- Alle Scripts sind für **Synology DSM 7.x** optimiert
|
||||||
|
- Docker und Docker Compose müssen auf der NAS installiert sein
|
||||||
|
- Gitea Actions muss in Gitea aktiviert sein
|
||||||
|
- PHP 8.4 und Laravel 12 werden verwendet
|
||||||
|
|
||||||
|
## 🆘 Support
|
||||||
|
|
||||||
|
Bei Fragen oder Problemen:
|
||||||
|
|
||||||
|
1. Prüfe die Troubleshooting-Sektionen in den Dokumentations-Dateien
|
||||||
|
2. Prüfe Logs: `docker logs gitea-runner` und `docker logs laravel_app`
|
||||||
|
3. Verifiziere alle Secrets und Environment-Variablen
|
||||||
|
4. Stelle sicher, dass alle Ports verfügbar sind
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Erstellt am:** 2025-12-17
|
||||||
|
**Version:** 1.0
|
||||||
|
**Für:** Synology NAS Deployment mit Gitea Actions
|
||||||
@@ -0,0 +1,411 @@
|
|||||||
|
# Gitea Runner Setup auf Synology NAS
|
||||||
|
|
||||||
|
Diese Anleitung erklärt, wie du einen Gitea Actions Runner auf deiner Synology NAS einrichtest, um automatische Deployments durchzuführen.
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
- Gitea läuft auf deiner Synology NAS
|
||||||
|
- Docker ist auf der Synology NAS installiert
|
||||||
|
- SSH-Zugriff auf die Synology NAS
|
||||||
|
- Portainer läuft (optional, aber empfohlen für Container-Management)
|
||||||
|
|
||||||
|
## Option 1: Gitea Runner mit Docker Compose (empfohlen)
|
||||||
|
|
||||||
|
### 1. Runner Docker Compose Datei erstellen
|
||||||
|
|
||||||
|
Erstelle eine Datei `/volume1/docker/gitea-runner/docker-compose.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
runner:
|
||||||
|
image: gitea/act_runner:latest
|
||||||
|
container_name: gitea-runner
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
environment:
|
||||||
|
- GITEA_INSTANCE_URL=http://your-gitea-url:3000
|
||||||
|
- GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN}
|
||||||
|
- GITEA_RUNNER_NAME=synology-runner
|
||||||
|
- GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bullseye
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- gitea-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
gitea-network:
|
||||||
|
external: true
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Runner Token generieren
|
||||||
|
|
||||||
|
1. Öffne deine Gitea-Instanz im Browser
|
||||||
|
2. Navigiere zu deinem Repository
|
||||||
|
3. Gehe zu **Settings** → **Actions** → **Runners**
|
||||||
|
4. Klicke auf **Create new Runner**
|
||||||
|
5. Kopiere den generierten Token
|
||||||
|
|
||||||
|
### 3. Environment Variables setzen
|
||||||
|
|
||||||
|
Erstelle eine `.env` Datei im selben Verzeichnis:
|
||||||
|
|
||||||
|
```env
|
||||||
|
RUNNER_TOKEN=dein_gitea_runner_token_hier
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Runner starten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /volume1/docker/gitea-runner
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Runner verifizieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Logs anschauen
|
||||||
|
docker logs -f gitea-runner
|
||||||
|
|
||||||
|
# Status prüfen
|
||||||
|
docker ps | grep gitea-runner
|
||||||
|
```
|
||||||
|
|
||||||
|
In Gitea solltest du nun unter **Settings** → **Actions** → **Runners** deinen registrierten Runner sehen.
|
||||||
|
|
||||||
|
## Option 2: Runner direkt in Portainer deployen
|
||||||
|
|
||||||
|
### 1. In Portainer einloggen
|
||||||
|
|
||||||
|
Öffne Portainer: `http://your-synology-ip:9000`
|
||||||
|
|
||||||
|
### 2. Stack erstellen
|
||||||
|
|
||||||
|
1. Gehe zu **Stacks** → **+ Add stack**
|
||||||
|
2. Name: `gitea-runner`
|
||||||
|
3. Wähle **Web editor**
|
||||||
|
4. Füge die obige docker-compose.yml ein
|
||||||
|
|
||||||
|
### 3. Environment Variables
|
||||||
|
|
||||||
|
Füge folgende Environment Variable hinzu:
|
||||||
|
- **RUNNER_TOKEN**: Dein Gitea Runner Token
|
||||||
|
|
||||||
|
### 4. Deploy
|
||||||
|
|
||||||
|
Klicke auf **Deploy the stack**
|
||||||
|
|
||||||
|
## Runner Konfiguration
|
||||||
|
|
||||||
|
### Custom Runner Labels
|
||||||
|
|
||||||
|
Um spezifische Workflows auszuführen, kannst du Custom Labels hinzufügen:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
- GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bullseye,ubuntu-22.04:docker://ubuntu:22.04,php-8.4:docker://php:8.4-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mehrere Runner
|
||||||
|
|
||||||
|
Für parallele Builds kannst du mehrere Runner starten:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
runner-1:
|
||||||
|
image: gitea/act_runner:latest
|
||||||
|
container_name: gitea-runner-1
|
||||||
|
# ... config ...
|
||||||
|
|
||||||
|
runner-2:
|
||||||
|
image: gitea/act_runner:latest
|
||||||
|
container_name: gitea-runner-2
|
||||||
|
# ... config ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Repository Secrets konfigurieren
|
||||||
|
|
||||||
|
Um das automatische Deployment zu ermöglichen, musst du Secrets in deinem Gitea-Repository hinterlegen:
|
||||||
|
|
||||||
|
### 1. In Gitea Repository Settings
|
||||||
|
|
||||||
|
1. Gehe zu deinem Repository
|
||||||
|
2. Klicke auf **Settings** → **Secrets**
|
||||||
|
3. Füge folgende Secrets hinzu:
|
||||||
|
|
||||||
|
| Secret Name | Beschreibung | Beispiel |
|
||||||
|
|------------|--------------|----------|
|
||||||
|
| `SYNOLOGY_HOST` | IP oder Hostname deiner Synology | `192.168.1.100` |
|
||||||
|
| `SYNOLOGY_USER` | SSH-Benutzername | `admin` |
|
||||||
|
| `SYNOLOGY_SSH_KEY` | Privater SSH-Key für Zugriff | `-----BEGIN OPENSSH PRIVATE KEY-----...` |
|
||||||
|
| `APP_KEY` | Laravel Application Key | `base64:xyz...` |
|
||||||
|
|
||||||
|
### 2. SSH-Key generieren (falls nicht vorhanden)
|
||||||
|
|
||||||
|
Auf deiner Synology NAS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH-Key-Pair generieren
|
||||||
|
ssh-keygen -t ed25519 -C "gitea-runner@synology" -f ~/.ssh/gitea_deploy
|
||||||
|
|
||||||
|
# Public Key zum authorized_keys hinzufügen
|
||||||
|
cat ~/.ssh/gitea_deploy.pub >> ~/.ssh/authorized_keys
|
||||||
|
chmod 600 ~/.ssh/authorized_keys
|
||||||
|
|
||||||
|
# Private Key anzeigen (für Secret)
|
||||||
|
cat ~/.ssh/gitea_deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
Kopiere den **gesamten** Private Key (inklusive `-----BEGIN` und `-----END` Zeilen) und füge ihn als `SYNOLOGY_SSH_KEY` Secret hinzu.
|
||||||
|
|
||||||
|
### 3. Secrets verifizieren
|
||||||
|
|
||||||
|
Stelle sicher, dass alle benötigten Secrets gesetzt sind:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In Gitea Repository Settings → Secrets
|
||||||
|
✅ SYNOLOGY_HOST
|
||||||
|
✅ SYNOLOGY_USER
|
||||||
|
✅ SYNOLOGY_SSH_KEY
|
||||||
|
✅ APP_KEY
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workflow aktivieren
|
||||||
|
|
||||||
|
### 1. Workflow-Datei pushen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Lokal im Projekt
|
||||||
|
git add .gitea/workflows/deploy-synology.yml
|
||||||
|
git commit -m "ci: add automated deployment workflow"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Workflow ausführen
|
||||||
|
|
||||||
|
Gitea Actions wird automatisch bei jedem Push auf `main` oder `develop` ausgelöst.
|
||||||
|
|
||||||
|
### 3. Workflow Status prüfen
|
||||||
|
|
||||||
|
1. Gehe zu deinem Repository in Gitea
|
||||||
|
2. Klicke auf **Actions**
|
||||||
|
3. Du siehst alle Workflow-Runs mit Status (Success/Failure)
|
||||||
|
4. Klicke auf einen Run, um Details und Logs zu sehen
|
||||||
|
|
||||||
|
## Workflow manuell auslösen
|
||||||
|
|
||||||
|
Falls du den Workflow manuell starten möchtest:
|
||||||
|
|
||||||
|
### 1. Workflow-Datei erweitern
|
||||||
|
|
||||||
|
Füge in `.gitea/workflows/deploy-synology.yml` hinzu:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
workflow_dispatch: # Ermöglicht manuelles Auslösen
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Manuell auslösen
|
||||||
|
|
||||||
|
1. Gehe zu **Actions** in deinem Repository
|
||||||
|
2. Wähle den Workflow aus
|
||||||
|
3. Klicke auf **Run workflow**
|
||||||
|
|
||||||
|
## Monitoring & Logs
|
||||||
|
|
||||||
|
### Runner Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Live Logs
|
||||||
|
docker logs -f gitea-runner
|
||||||
|
|
||||||
|
# Letzte 100 Zeilen
|
||||||
|
docker logs --tail 100 gitea-runner
|
||||||
|
```
|
||||||
|
|
||||||
|
### Workflow Logs
|
||||||
|
|
||||||
|
In Gitea UI:
|
||||||
|
1. **Actions** Tab
|
||||||
|
2. Wähle einen Workflow Run
|
||||||
|
3. Klicke auf die einzelnen Jobs, um Logs zu sehen
|
||||||
|
|
||||||
|
### Deployment Logs auf Synology
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Laravel App Logs
|
||||||
|
docker logs -f laravel_app
|
||||||
|
|
||||||
|
# Deployment Script Logs
|
||||||
|
# Diese werden in der Workflow-Ausgabe angezeigt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Problem: Runner verbindet sich nicht
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Logs prüfen
|
||||||
|
docker logs gitea-runner
|
||||||
|
|
||||||
|
# Runner neu registrieren
|
||||||
|
docker-compose down
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: Workflow startet nicht
|
||||||
|
|
||||||
|
1. **Runner Status prüfen**: Gehe zu Repository → Settings → Actions → Runners
|
||||||
|
2. **Runner Labels prüfen**: Stelle sicher, dass `runs-on: ubuntu-latest` mit den Runner Labels übereinstimmt
|
||||||
|
3. **Secrets prüfen**: Alle benötigten Secrets müssen gesetzt sein
|
||||||
|
|
||||||
|
### Problem: SSH-Verbindung fehlschlägt
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH-Key Permissions prüfen
|
||||||
|
chmod 600 ~/.ssh/gitea_deploy
|
||||||
|
chmod 644 ~/.ssh/gitea_deploy.pub
|
||||||
|
chmod 700 ~/.ssh
|
||||||
|
chmod 600 ~/.ssh/authorized_keys
|
||||||
|
|
||||||
|
# SSH-Verbindung testen (lokal auf der NAS)
|
||||||
|
ssh -i ~/.ssh/gitea_deploy admin@localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: Deployment schlägt fehl
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Prüfe deployment script permissions
|
||||||
|
cd /volume1/docker/laravel-app
|
||||||
|
ls -la deploy-synology.sh
|
||||||
|
|
||||||
|
# Mache es executable
|
||||||
|
chmod +x deploy-synology.sh
|
||||||
|
|
||||||
|
# Teste deployment script manuell
|
||||||
|
./deploy-synology.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: Health Check fehlschlägt
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Prüfe ob Container läuft
|
||||||
|
docker ps | grep laravel_app
|
||||||
|
|
||||||
|
# Prüfe Logs
|
||||||
|
docker logs laravel_app
|
||||||
|
|
||||||
|
# Teste Health Endpoint manuell
|
||||||
|
curl http://localhost:8080/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### 1. Separate Runner für Production und Staging
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
runner-production:
|
||||||
|
environment:
|
||||||
|
- GITEA_RUNNER_LABELS=production:docker://ubuntu:22.04
|
||||||
|
|
||||||
|
runner-staging:
|
||||||
|
environment:
|
||||||
|
- GITEA_RUNNER_LABELS=staging:docker://ubuntu:22.04
|
||||||
|
```
|
||||||
|
|
||||||
|
Im Workflow:
|
||||||
|
```yaml
|
||||||
|
jobs:
|
||||||
|
deploy-production:
|
||||||
|
runs-on: production
|
||||||
|
if: github.ref == 'refs/heads/main'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Workflow nur für Conventional Commits
|
||||||
|
|
||||||
|
Der aktuelle Workflow filtert bereits nach Conventional Commits:
|
||||||
|
- `feat:` - Neue Features
|
||||||
|
- `fix:` - Bugfixes
|
||||||
|
- `docs:` - Dokumentation
|
||||||
|
- `chore:` - Wartungsarbeiten
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
### 3. Notifications
|
||||||
|
|
||||||
|
Erweitere den Workflow um Benachrichtigungen:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Send Notification
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
# Telegram, Discord, Email, etc.
|
||||||
|
curl -X POST https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage \
|
||||||
|
-d chat_id=${{ secrets.TELEGRAM_CHAT_ID }} \
|
||||||
|
-d text="Deployment status: ${{ job.status }}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Rollback-Strategie
|
||||||
|
|
||||||
|
Im deployment script ist bereits ein Backup-Mechanismus implementiert:
|
||||||
|
- Datenbank-Backups vor jedem Deployment
|
||||||
|
- Letzte 5 Backups werden aufbewahrt
|
||||||
|
- Automatischer Rollback bei Fehlern
|
||||||
|
|
||||||
|
## Erweiterte Konfiguration
|
||||||
|
|
||||||
|
### Multi-Stage Deployments
|
||||||
|
|
||||||
|
Für staging und production environments:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
jobs:
|
||||||
|
deploy-staging:
|
||||||
|
if: github.ref == 'refs/heads/develop'
|
||||||
|
# ... deploy to staging ...
|
||||||
|
|
||||||
|
deploy-production:
|
||||||
|
if: github.ref == 'refs/heads/main'
|
||||||
|
needs: [test, deploy-staging]
|
||||||
|
# ... deploy to production ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Caching
|
||||||
|
|
||||||
|
Um Build-Zeiten zu verkürzen:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Cache Composer
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: vendor
|
||||||
|
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
|
||||||
|
|
||||||
|
- name: Cache NPM
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: node_modules
|
||||||
|
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Weitere Ressourcen
|
||||||
|
|
||||||
|
- [Gitea Actions Dokumentation](https://docs.gitea.com/usage/actions/overview)
|
||||||
|
- [Act Runner Dokumentation](https://gitea.com/gitea/act_runner)
|
||||||
|
- [Docker Compose Dokumentation](https://docs.docker.com/compose/)
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Bei Problemen:
|
||||||
|
1. Prüfe Runner Logs: `docker logs gitea-runner`
|
||||||
|
2. Prüfe Workflow Logs in Gitea Actions Tab
|
||||||
|
3. Verifiziere alle Secrets sind korrekt gesetzt
|
||||||
|
4. Teste SSH-Verbindung zur Synology manuell
|
||||||
@@ -0,0 +1,435 @@
|
|||||||
|
# Synology NAS Deployment Anleitung
|
||||||
|
|
||||||
|
Diese Anleitung beschreibt, wie du diese Laravel-Anwendung auf deiner Synology NAS mit Portainer deployen kannst.
|
||||||
|
|
||||||
|
## 📋 Inhaltsverzeichnis
|
||||||
|
|
||||||
|
1. [Voraussetzungen](#voraussetzungen)
|
||||||
|
2. [Manuelles Deployment](#-vorbereitung)
|
||||||
|
3. [Automatisches CI/CD Deployment](#-automatisches-deployment-mit-gitea-actions)
|
||||||
|
4. [Monitoring & Wartung](#-monitoring--wartung)
|
||||||
|
5. [Troubleshooting](#-troubleshooting)
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
- Synology NAS mit Docker-Unterstützung
|
||||||
|
- Portainer läuft bereits auf deiner NAS
|
||||||
|
- SSH-Zugriff auf die Synology NAS (optional, aber empfohlen)
|
||||||
|
- Mindestens 2GB freier RAM
|
||||||
|
- Mindestens 5GB freier Speicherplatz
|
||||||
|
- (Optional) Gitea für automatisches CI/CD Deployment
|
||||||
|
|
||||||
|
## 📦 Vorbereitung
|
||||||
|
|
||||||
|
### 1. Projekt-Dateien auf die NAS übertragen
|
||||||
|
|
||||||
|
Es gibt mehrere Möglichkeiten, die Dateien auf deine Synology zu übertragen:
|
||||||
|
|
||||||
|
#### Option A: Via Git (empfohlen)
|
||||||
|
```bash
|
||||||
|
# SSH auf die Synology NAS
|
||||||
|
ssh admin@your-synology-ip
|
||||||
|
|
||||||
|
# Navigiere zu einem geeigneten Verzeichnis (z.B. /volume1/docker/laravel)
|
||||||
|
cd /volume1/docker
|
||||||
|
git clone <dein-repository-url> laravel-app
|
||||||
|
cd laravel-app
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option B: Via File Station
|
||||||
|
1. Öffne die Synology File Station
|
||||||
|
2. Erstelle einen Ordner: `/docker/laravel-app`
|
||||||
|
3. Lade alle Projekt-Dateien in diesen Ordner hoch
|
||||||
|
|
||||||
|
#### Option C: Via rsync/scp
|
||||||
|
```bash
|
||||||
|
# Vom lokalen Rechner aus
|
||||||
|
rsync -avz --exclude 'node_modules' --exclude 'vendor' \
|
||||||
|
/Users/sebastianfrohlich/Herd/frontend/ \
|
||||||
|
admin@your-synology-ip:/volume1/docker/laravel-app/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Umgebungsvariablen konfigurieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH auf der NAS
|
||||||
|
cd /volume1/docker/laravel-app
|
||||||
|
|
||||||
|
# Kopiere die Synology-Beispiel-Datei
|
||||||
|
cp .env.synology.example .env.synology
|
||||||
|
|
||||||
|
# Bearbeite die Datei mit deinen spezifischen Einstellungen
|
||||||
|
nano .env.synology
|
||||||
|
```
|
||||||
|
|
||||||
|
**Wichtige Anpassungen in `.env.synology`:**
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Ersetze mit deiner Synology IP-Adresse
|
||||||
|
APP_URL=http://192.168.1.100:8080
|
||||||
|
|
||||||
|
# Setze APP_DEBUG auf false für Produktion
|
||||||
|
APP_DEBUG=false
|
||||||
|
|
||||||
|
# Generiere einen neuen APP_KEY (wichtig für Sicherheit!)
|
||||||
|
# Dies kann später mit: docker exec laravel_app php artisan key:generate gemacht werden
|
||||||
|
|
||||||
|
# PostgreSQL Passwort - ändere dies!
|
||||||
|
DB_PASSWORD2=dein_sicheres_passwort_hier
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Deployment mit Portainer
|
||||||
|
|
||||||
|
### Methode 1: Docker Compose Stack (empfohlen)
|
||||||
|
|
||||||
|
1. **Öffne Portainer** in deinem Browser: `http://your-synology-ip:9000`
|
||||||
|
|
||||||
|
2. **Navigiere zu "Stacks"**:
|
||||||
|
- Klicke auf "Stacks" im linken Menü
|
||||||
|
- Klicke auf "+ Add stack"
|
||||||
|
|
||||||
|
3. **Stack konfigurieren**:
|
||||||
|
- **Name**: `laravel-app`
|
||||||
|
- **Build method**: Wähle "Repository"
|
||||||
|
- **Repository URL**: Gib deine Git-Repository-URL ein (falls vorhanden)
|
||||||
|
- Oder wähle "Upload" und lade `docker-compose.synology.yml` hoch
|
||||||
|
- Oder wähle "Web editor" und kopiere den Inhalt von `docker-compose.synology.yml`
|
||||||
|
|
||||||
|
4. **Umgebungsvariablen setzen**:
|
||||||
|
Klicke auf "Add an environment variable" und füge folgende Variablen hinzu:
|
||||||
|
|
||||||
|
```
|
||||||
|
APP_NAME=Laravel
|
||||||
|
APP_ENV=production
|
||||||
|
APP_KEY=base64:L9RVZ3pNFyAvTbMqicT1rL5GbgE+7lJerkU9wyc95H8=
|
||||||
|
APP_DEBUG=false
|
||||||
|
APP_URL=http://your-synology-ip:8080
|
||||||
|
DB_CONNECTION2=pgsql
|
||||||
|
DB_HOST2=postgres
|
||||||
|
DB_PORT2=5432
|
||||||
|
DB_DATABASE2=ingest_db
|
||||||
|
DB_USERNAME2=ingest_user
|
||||||
|
DB_PASSWORD2=dein_sicheres_passwort
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Stack deployen**:
|
||||||
|
- Klicke auf "Deploy the stack"
|
||||||
|
- Warte, bis der Build-Prozess abgeschlossen ist (kann 5-10 Minuten dauern)
|
||||||
|
|
||||||
|
### Methode 2: Build und Deploy manuell via SSH
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH auf die Synology
|
||||||
|
ssh admin@your-synology-ip
|
||||||
|
|
||||||
|
# Navigiere zum Projekt-Verzeichnis
|
||||||
|
cd /volume1/docker/laravel-app
|
||||||
|
|
||||||
|
# Baue das Docker Image
|
||||||
|
docker build -t laravel-app:latest .
|
||||||
|
|
||||||
|
# Starte die Services mit docker-compose
|
||||||
|
docker-compose -f docker-compose.synology.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔍 Verifikation
|
||||||
|
|
||||||
|
### 1. Überprüfe den Container-Status
|
||||||
|
|
||||||
|
In Portainer:
|
||||||
|
- Gehe zu "Containers"
|
||||||
|
- Du solltest zwei laufende Container sehen:
|
||||||
|
- `laravel_app` (Status: running, Port: 0.0.0.0:8080->80/tcp)
|
||||||
|
- `laravel_postgres` (Status: running, Port: 5432/tcp)
|
||||||
|
|
||||||
|
Via SSH:
|
||||||
|
```bash
|
||||||
|
docker ps
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Überprüfe die Logs
|
||||||
|
|
||||||
|
In Portainer:
|
||||||
|
- Klicke auf den Container `laravel_app`
|
||||||
|
- Wähle "Logs"
|
||||||
|
- Du solltest keine Fehler sehen
|
||||||
|
|
||||||
|
Via SSH:
|
||||||
|
```bash
|
||||||
|
# Laravel App Logs
|
||||||
|
docker logs laravel_app
|
||||||
|
|
||||||
|
# PostgreSQL Logs
|
||||||
|
docker logs laravel_postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Teste die Anwendung
|
||||||
|
|
||||||
|
Öffne deinen Browser und navigiere zu:
|
||||||
|
```
|
||||||
|
http://your-synology-ip:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
Du solltest die Laravel-Anwendung sehen!
|
||||||
|
|
||||||
|
## 🔧 Nützliche Befehle
|
||||||
|
|
||||||
|
### Artisan-Befehle ausführen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Laravel Cache leeren
|
||||||
|
docker exec laravel_app php artisan cache:clear
|
||||||
|
|
||||||
|
# Neuen APP_KEY generieren
|
||||||
|
docker exec laravel_app php artisan key:generate
|
||||||
|
|
||||||
|
# Migrationen ausführen
|
||||||
|
docker exec laravel_app php artisan migrate
|
||||||
|
|
||||||
|
# Seeder ausführen
|
||||||
|
docker exec laravel_app php artisan db:seed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Container neustarten
|
||||||
|
|
||||||
|
Via Portainer:
|
||||||
|
- Gehe zu "Containers"
|
||||||
|
- Wähle den Container aus
|
||||||
|
- Klicke auf "Restart"
|
||||||
|
|
||||||
|
Via SSH:
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose.synology.yml restart
|
||||||
|
```
|
||||||
|
|
||||||
|
### Container stoppen und entfernen
|
||||||
|
|
||||||
|
Via Portainer:
|
||||||
|
- Gehe zu "Stacks"
|
||||||
|
- Wähle den Stack "laravel-app"
|
||||||
|
- Klicke auf "Stop" oder "Delete"
|
||||||
|
|
||||||
|
Via SSH:
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose.synology.yml down
|
||||||
|
|
||||||
|
# Mit Volumes löschen (Achtung: Löscht die Datenbank!)
|
||||||
|
docker-compose -f docker-compose.synology.yml down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logs live verfolgen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Alle Container
|
||||||
|
docker-compose -f docker-compose.synology.yml logs -f
|
||||||
|
|
||||||
|
# Nur Laravel App
|
||||||
|
docker logs -f laravel_app
|
||||||
|
|
||||||
|
# Nur PostgreSQL
|
||||||
|
docker logs -f laravel_postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔐 Sicherheitshinweise
|
||||||
|
|
||||||
|
1. **APP_KEY ändern**: Generiere einen neuen APP_KEY für die Produktion:
|
||||||
|
```bash
|
||||||
|
docker exec laravel_app php artisan key:generate
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Datenbank-Passwort**: Ändere das Standard-PostgreSQL-Passwort in `.env.synology`
|
||||||
|
|
||||||
|
3. **APP_DEBUG**: Stelle sicher, dass `APP_DEBUG=false` in der Produktion
|
||||||
|
|
||||||
|
4. **Firewall**: Konfiguriere die Synology-Firewall, um nur benötigte Ports zu öffnen
|
||||||
|
|
||||||
|
5. **SSL/HTTPS**: Für den Produktionsbetrieb solltest du einen Reverse Proxy (z.B. Synology DSM Reverse Proxy) mit SSL-Zertifikat einrichten
|
||||||
|
|
||||||
|
## 🌐 Reverse Proxy einrichten (optional, aber empfohlen)
|
||||||
|
|
||||||
|
Für den Zugriff über eine Domain mit HTTPS:
|
||||||
|
|
||||||
|
1. **In Synology DSM**:
|
||||||
|
- Gehe zu "Systemsteuerung" → "Anmeldungsportal" → "Erweitert"
|
||||||
|
- Klicke auf "Reverse Proxy" → "Erstellen"
|
||||||
|
|
||||||
|
2. **Konfiguration**:
|
||||||
|
- **Protokoll**: HTTPS
|
||||||
|
- **Hostname**: your-domain.com
|
||||||
|
- **Port**: 443
|
||||||
|
- **Zielprotokoll**: HTTP
|
||||||
|
- **Zielhost**: localhost
|
||||||
|
- **Zielport**: 8080
|
||||||
|
|
||||||
|
3. **SSL-Zertifikat**:
|
||||||
|
- Gehe zu "Systemsteuerung" → "Sicherheit" → "Zertifikat"
|
||||||
|
- Füge ein Let's Encrypt-Zertifikat hinzu
|
||||||
|
|
||||||
|
## 📊 Monitoring & Wartung
|
||||||
|
|
||||||
|
### Container-Ressourcen überwachen
|
||||||
|
|
||||||
|
In Portainer:
|
||||||
|
- Gehe zu "Containers"
|
||||||
|
- Wähle einen Container
|
||||||
|
- Klicke auf "Stats" für Echtzeit-Metriken (CPU, RAM, Netzwerk)
|
||||||
|
|
||||||
|
### Backup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# PostgreSQL Datenbank sichern
|
||||||
|
docker exec laravel_postgres pg_dump -U ingest_user ingest_db > backup_$(date +%Y%m%d).sql
|
||||||
|
|
||||||
|
# Gesamten Stack sichern (inkl. Volumes)
|
||||||
|
docker run --rm \
|
||||||
|
-v laravel-app_postgres-data:/data \
|
||||||
|
-v /volume1/docker/backups:/backup \
|
||||||
|
alpine tar czf /backup/postgres-backup-$(date +%Y%m%d).tar.gz /data
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updates
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Projekt-Code aktualisieren (wenn via Git)
|
||||||
|
cd /volume1/docker/laravel-app
|
||||||
|
git pull
|
||||||
|
|
||||||
|
# Neu bauen und deployen
|
||||||
|
docker-compose -f docker-compose.synology.yml up -d --build
|
||||||
|
|
||||||
|
# Migrationen ausführen
|
||||||
|
docker exec laravel_app php artisan migrate --force
|
||||||
|
```
|
||||||
|
|
||||||
|
## ❓ Troubleshooting
|
||||||
|
|
||||||
|
### Problem: Container startet nicht
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Logs prüfen
|
||||||
|
docker logs laravel_app
|
||||||
|
|
||||||
|
# Container interaktiv starten für Debugging
|
||||||
|
docker exec -it laravel_app sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: Datenbank-Verbindung fehlgeschlagen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# PostgreSQL-Container prüfen
|
||||||
|
docker exec laravel_postgres pg_isready -U ingest_user
|
||||||
|
|
||||||
|
# Umgebungsvariablen prüfen
|
||||||
|
docker exec laravel_app env | grep DB_
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: Permissions-Fehler
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Storage-Permissions korrigieren
|
||||||
|
docker exec laravel_app chmod -R 775 storage bootstrap/cache
|
||||||
|
docker exec laravel_app chown -R nginx:nginx storage bootstrap/cache
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: Port bereits belegt
|
||||||
|
|
||||||
|
Wenn Port 8080 bereits verwendet wird:
|
||||||
|
1. Öffne `docker-compose.synology.yml`
|
||||||
|
2. Ändere die Port-Mapping: `"8081:80"` statt `"8080:80"`
|
||||||
|
3. Aktualisiere `APP_URL` in `.env.synology` entsprechend
|
||||||
|
|
||||||
|
## 🤖 Automatisches Deployment mit Gitea Actions
|
||||||
|
|
||||||
|
Wenn du Gitea auf deiner Synology NAS verwendest, kannst du den gesamten Build- und Deployment-Prozess automatisieren!
|
||||||
|
|
||||||
|
### Vorteile von CI/CD
|
||||||
|
|
||||||
|
- ✅ Automatischer Build bei jedem Git Push
|
||||||
|
- ✅ Automatische Tests vor Deployment
|
||||||
|
- ✅ Automatisches Deployment auf die NAS
|
||||||
|
- ✅ Rollback bei Fehlern
|
||||||
|
- ✅ Keine manuellen Schritte mehr nötig
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
1. **Gitea Runner einrichten**
|
||||||
|
- Siehe detaillierte Anleitung: [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md)
|
||||||
|
- Kurz: Runner Docker Container auf NAS deployen
|
||||||
|
- Runner in Gitea registrieren
|
||||||
|
|
||||||
|
2. **Repository Secrets konfigurieren**
|
||||||
|
|
||||||
|
Gehe in Gitea zu: **Repository → Settings → Secrets**
|
||||||
|
|
||||||
|
Füge folgende Secrets hinzu:
|
||||||
|
```
|
||||||
|
SYNOLOGY_HOST=192.168.1.100
|
||||||
|
SYNOLOGY_USER=admin
|
||||||
|
SYNOLOGY_SSH_KEY=<dein-ssh-private-key>
|
||||||
|
APP_KEY=<dein-laravel-app-key>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Workflow pushen**
|
||||||
|
|
||||||
|
Der Workflow in [`.gitea/workflows/deploy-synology.yml`](.gitea/workflows/deploy-synology.yml) ist bereits vorkonfiguriert.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add .gitea/workflows/deploy-synology.yml
|
||||||
|
git commit -m "ci: add automated deployment workflow"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Automatisches Deployment genießen! 🎉**
|
||||||
|
|
||||||
|
Bei jedem Push auf `main` oder `develop`:
|
||||||
|
- Tests werden ausgeführt
|
||||||
|
- Docker Image wird gebaut
|
||||||
|
- Deployment auf NAS erfolgt automatisch
|
||||||
|
- Health Check verifiziert Deployment
|
||||||
|
|
||||||
|
### Workflow-Ablauf
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[Git Push] --> B[Run Tests]
|
||||||
|
B --> C{Tests OK?}
|
||||||
|
C -->|Ja| D[Build Docker Image]
|
||||||
|
C -->|Nein| E[Abbruch]
|
||||||
|
D --> F[Transfer zu NAS]
|
||||||
|
F --> G[Deploy auf NAS]
|
||||||
|
G --> H[Health Check]
|
||||||
|
H --> I{Healthy?}
|
||||||
|
I -->|Ja| J[✅ Success]
|
||||||
|
I -->|Nein| K[Rollback]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Workflow überwachen
|
||||||
|
|
||||||
|
1. Gehe zu deinem Repository in Gitea
|
||||||
|
2. Klicke auf **Actions**
|
||||||
|
3. Siehe alle Workflow-Runs mit Status
|
||||||
|
4. Klicke auf einen Run für Details und Logs
|
||||||
|
|
||||||
|
### Erweiterte Konfiguration
|
||||||
|
|
||||||
|
Weitere Details zur CI/CD-Konfiguration findest du in:
|
||||||
|
- [GITEA_RUNNER_SETUP.md](GITEA_RUNNER_SETUP.md) - Detaillierte Runner-Setup Anleitung
|
||||||
|
- [`.gitea/workflows/deploy-synology.yml`](.gitea/workflows/deploy-synology.yml) - Workflow-Konfiguration
|
||||||
|
- [`scripts/deploy-synology.sh`](scripts/deploy-synology.sh) - Deployment-Script
|
||||||
|
|
||||||
|
## 📝 Weitere Ressourcen
|
||||||
|
|
||||||
|
- [Laravel Dokumentation](https://laravel.com/docs)
|
||||||
|
- [Docker Dokumentation](https://docs.docker.com/)
|
||||||
|
- [Portainer Dokumentation](https://docs.portainer.io/)
|
||||||
|
- [Synology Docker Anleitung](https://www.synology.com/en-us/dsm/packages/Docker)
|
||||||
|
- [Gitea Actions Dokumentation](https://docs.gitea.com/usage/actions/overview)
|
||||||
|
|
||||||
|
## 🆘 Support
|
||||||
|
|
||||||
|
Bei Problemen:
|
||||||
|
1. Prüfe die Container-Logs
|
||||||
|
2. Überprüfe die Umgebungsvariablen
|
||||||
|
3. Stelle sicher, dass alle Ports verfügbar sind
|
||||||
|
4. Prüfe die Synology-Firewall-Einstellungen
|
||||||
|
5. Bei CI/CD: Prüfe Gitea Actions Logs und Runner Status
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+10
-10
@@ -86,10 +86,10 @@ return [
|
|||||||
'driver' => 'pgsql',
|
'driver' => 'pgsql',
|
||||||
'url' => env('DB_URL'),
|
'url' => env('DB_URL'),
|
||||||
'host' => env('DB_HOST2', '127.0.0.1'),
|
'host' => env('DB_HOST2', '127.0.0.1'),
|
||||||
'port' => env('DB_PORT2', '5433'),
|
'port' => env('DB_PORT2', '5432'),
|
||||||
'database' => env('DB_DATABASE2', 'risk_ingest_db'),
|
'database' => env('DB_DATABASE2', 'ingest_db'),
|
||||||
'username' => env('DB_USERNAME2', 'risk_ingest_user'),
|
'username' => env('DB_USERNAME2', 'ingest_user'),
|
||||||
'password' => env('DB_PASSWORD2', ''),
|
'password' => env('DB_PASSWORD2', 'ingest_pwd'),
|
||||||
'charset' => env('DB_CHARSET', 'utf8'),
|
'charset' => env('DB_CHARSET', 'utf8'),
|
||||||
'prefix' => '',
|
'prefix' => '',
|
||||||
'prefix_indexes' => true,
|
'prefix_indexes' => true,
|
||||||
@@ -101,9 +101,9 @@ return [
|
|||||||
'driver' => env('DB_CONNECTION2'),
|
'driver' => env('DB_CONNECTION2'),
|
||||||
'host' => env('DB_HOST2', '127.0.0.1'),
|
'host' => env('DB_HOST2', '127.0.0.1'),
|
||||||
'port' => env('DB_PORT2', '5432'),
|
'port' => env('DB_PORT2', '5432'),
|
||||||
'database' => env('DB_DATABASE2', 'laravel'),
|
'database' => env('DB_DATABASE2', 'ingest_db'),
|
||||||
'username' => env('DB_USERNAME2', 'root'),
|
'username' => env('DB_USERNAME2', 'ingest_user'),
|
||||||
'password' => env('DB_PASSWORD2', ''),
|
'password' => env('DB_PASSWORD2', 'ingest_pwd'),
|
||||||
'charset' => env('DB_CHARSET', 'utf8'),
|
'charset' => env('DB_CHARSET', 'utf8'),
|
||||||
'prefix' => '',
|
'prefix' => '',
|
||||||
'prefix_indexes' => true,
|
'prefix_indexes' => true,
|
||||||
@@ -115,9 +115,9 @@ return [
|
|||||||
'driver' => env('DB_CONNECTION2'),
|
'driver' => env('DB_CONNECTION2'),
|
||||||
'host' => env('DB_HOST2', '127.0.0.1'),
|
'host' => env('DB_HOST2', '127.0.0.1'),
|
||||||
'port' => env('DB_PORT2', '5432'),
|
'port' => env('DB_PORT2', '5432'),
|
||||||
'database' => env('DB_DATABASE2', 'laravel'),
|
'database' => env('DB_DATABASE2', 'ingest_db'),
|
||||||
'username' => env('DB_USERNAME2', 'root'),
|
'username' => env('DB_USERNAME2', 'ingest_user'),
|
||||||
'password' => env('DB_PASSWORD2', ''),
|
'password' => env('DB_PASSWORD2', 'ingest_pwd'),
|
||||||
'charset' => env('DB_CHARSET', 'utf8'),
|
'charset' => env('DB_CHARSET', 'utf8'),
|
||||||
'prefix' => '',
|
'prefix' => '',
|
||||||
'prefix_indexes' => true,
|
'prefix_indexes' => true,
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
# Gitea Runner für automatische CI/CD Deployments
|
||||||
|
# Dieses Compose-File wird auf der Synology NAS deployed
|
||||||
|
|
||||||
|
services:
|
||||||
|
gitea-runner:
|
||||||
|
image: gitea/act_runner:latest
|
||||||
|
container_name: gitea-runner
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
environment:
|
||||||
|
# Gitea Instance URL - Passe dies an deine Gitea-Installation an
|
||||||
|
- GITEA_INSTANCE_URL=${GITEA_URL:-http://gitea:3000}
|
||||||
|
|
||||||
|
# Runner Registration Token - Wird aus Gitea UI generiert
|
||||||
|
- GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN}
|
||||||
|
|
||||||
|
# Runner Name - Wird in Gitea angezeigt
|
||||||
|
- GITEA_RUNNER_NAME=${RUNNER_NAME:-synology-runner}
|
||||||
|
|
||||||
|
# Runner Labels - Definiert welche Workflows dieser Runner ausführen kann
|
||||||
|
# Format: label:docker://image
|
||||||
|
- GITEA_RUNNER_LABELS=ubuntu-latest:docker://catthehacker/ubuntu:act-latest,ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04,ubuntu-20.04:docker://catthehacker/ubuntu:act-20.04
|
||||||
|
|
||||||
|
# Runner Capacity - Maximale Anzahl gleichzeitiger Jobs
|
||||||
|
- GITEA_RUNNER_CAPACITY=${RUNNER_CAPACITY:-1}
|
||||||
|
|
||||||
|
# Log Level
|
||||||
|
- GITEA_RUNNER_LOG_LEVEL=${LOG_LEVEL:-info}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
# Runner Daten (Config, Cache, etc.)
|
||||||
|
- runner-data:/data
|
||||||
|
|
||||||
|
# Docker Socket - Ermöglicht dem Runner Docker-Container zu starten
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
|
||||||
|
# Optional: Workspace für Job-Artefakte
|
||||||
|
- runner-workspace:/workspace
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- gitea-network
|
||||||
|
|
||||||
|
# Health Check
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "pgrep", "-f", "act_runner"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# Resource Limits (optional, aber empfohlen)
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: '2'
|
||||||
|
memory: 2G
|
||||||
|
reservations:
|
||||||
|
cpus: '1'
|
||||||
|
memory: 512M
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
runner-data:
|
||||||
|
driver: local
|
||||||
|
runner-workspace:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
gitea-network:
|
||||||
|
# Wenn Gitea in einem separaten Netzwerk läuft, verwende:
|
||||||
|
# external: true
|
||||||
|
# Ansonsten:
|
||||||
|
driver: bridge
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: laravel-app:latest
|
||||||
|
container_name: laravel_app
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- "8080:80" # Angepasst für Synology (Port 81 oft belegt)
|
||||||
|
|
||||||
|
environment:
|
||||||
|
# Laravel Environment
|
||||||
|
- APP_NAME=${APP_NAME:-Laravel}
|
||||||
|
- APP_ENV=${APP_ENV:-production}
|
||||||
|
- APP_KEY=${APP_KEY}
|
||||||
|
- APP_DEBUG=${APP_DEBUG:-false}
|
||||||
|
- APP_URL=${APP_URL:-http://localhost:8080}
|
||||||
|
|
||||||
|
# Database - PostgreSQL
|
||||||
|
- DB_CONNECTION2=${DB_CONNECTION2:-pgsql}
|
||||||
|
- DB_HOST2=${DB_HOST2:-postgres}
|
||||||
|
- DB_PORT2=${DB_PORT2:-5432}
|
||||||
|
- DB_DATABASE2=${DB_DATABASE2:-ingest_db}
|
||||||
|
- DB_USERNAME2=${DB_USERNAME2:-ingest_user}
|
||||||
|
- DB_PASSWORD2=${DB_PASSWORD2:-ingest_pwd}
|
||||||
|
|
||||||
|
# Session & Cache
|
||||||
|
- SESSION_DRIVER=${SESSION_DRIVER:-file}
|
||||||
|
- CACHE_STORE=${CACHE_STORE:-file}
|
||||||
|
- QUEUE_CONNECTION=${QUEUE_CONNECTION:-sync}
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
- LOG_CHANNEL=${LOG_CHANNEL:-stack}
|
||||||
|
- LOG_LEVEL=${LOG_LEVEL:-info}
|
||||||
|
|
||||||
|
# Mail
|
||||||
|
- MAIL_MAILER=${MAIL_MAILER:-log}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- app-storage:/var/www/html/storage
|
||||||
|
- app-bootstrap-cache:/var/www/html/bootstrap/cache
|
||||||
|
- ./database:/var/www/html/database
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- laravel-network
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: laravel_postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=${DB_DATABASE2:-ingest_db}
|
||||||
|
- POSTGRES_USER=${DB_USERNAME2:-ingest_user}
|
||||||
|
- POSTGRES_PASSWORD=${DB_PASSWORD2:-ingest_pwd}
|
||||||
|
- PGDATA=/var/lib/postgresql/data/pgdata
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- "5432:5432" # Optional: Direktzugriff auf PostgreSQL
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- laravel-network
|
||||||
|
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME2:-ingest_user}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres-data:
|
||||||
|
driver: local
|
||||||
|
app-storage:
|
||||||
|
driver: local
|
||||||
|
app-bootstrap-cache:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
laravel-network:
|
||||||
|
driver: bridge
|
||||||
@@ -0,0 +1,999 @@
|
|||||||
|
# API-Dokumentation: Risk Intelligence Platform
|
||||||
|
|
||||||
|
## 📋 Inhaltsverzeichnis
|
||||||
|
|
||||||
|
1. [Übersicht](#übersicht)
|
||||||
|
2. [API-Spezifikation](#api-spezifikation)
|
||||||
|
3. [Authentication](#authentication)
|
||||||
|
4. [Endpoints](#endpoints)
|
||||||
|
5. [Datenmodelle](#datenmodelle)
|
||||||
|
6. [Beispiele](#beispiele)
|
||||||
|
7. [Error Handling](#error-handling)
|
||||||
|
8. [Rate Limiting](#rate-limiting)
|
||||||
|
9. [Changelog](#changelog)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Übersicht
|
||||||
|
|
||||||
|
Die **Trusted AI Analyst Data API** stellt Daten für das Analyst Dashboard, Transaction Review, Company Search und Company Drill-Down bereit.
|
||||||
|
|
||||||
|
### API-Version
|
||||||
|
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Format:** JSON
|
||||||
|
**Authentifizierung:** Session-basiert (Laravel Session Cookie)
|
||||||
|
|
||||||
|
### Base URLs
|
||||||
|
|
||||||
|
| Environment | URL |
|
||||||
|
|-------------|-----|
|
||||||
|
| **Development** | `http://trusted_ai.test/api` |
|
||||||
|
| **Production** | `https://afc.trai.sft.comstack.de/api` |
|
||||||
|
|
||||||
|
### OpenAPI Spezifikation
|
||||||
|
|
||||||
|
Die vollständige API-Spezifikation ist in [swagger.yaml](../swagger.yaml) dokumentiert.
|
||||||
|
|
||||||
|
**Swagger UI:** Die Spezifikation kann mit [Swagger Editor](https://editor.swagger.io) oder Swagger UI visualisiert werden.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API-Spezifikation
|
||||||
|
|
||||||
|
### API-Kategorien
|
||||||
|
|
||||||
|
| Tag | Beschreibung | Endpoints |
|
||||||
|
|-----|--------------|-----------|
|
||||||
|
| **Dashboard** | KPIs und Alert-Übersichten | 1 Endpoint |
|
||||||
|
| **Transactions** | Portfolio-weite Transaction Review | 2 Endpoints |
|
||||||
|
| **Companies** | Company Discovery & Drill-Down | 4 Endpoints |
|
||||||
|
|
||||||
|
**Gesamt:** 7 API-Endpoints
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
### Session-basierte Authentifizierung
|
||||||
|
|
||||||
|
Die API nutzt **Laravel Session Cookies** für die Authentifizierung.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
securitySchemes:
|
||||||
|
sessionCookie:
|
||||||
|
type: apiKey
|
||||||
|
in: cookie
|
||||||
|
name: laravel_session
|
||||||
|
```
|
||||||
|
|
||||||
|
### Login-Flow
|
||||||
|
|
||||||
|
1. **Login via Web-Interface:**
|
||||||
|
```http
|
||||||
|
POST /login HTTP/1.1
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
email=user@example.com&password=secret
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Session Cookie erhalten:**
|
||||||
|
```http
|
||||||
|
HTTP/1.1 302 Found
|
||||||
|
Set-Cookie: laravel_session=eyJ....; Path=/; HttpOnly; SameSite=lax
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **API-Request mit Cookie:**
|
||||||
|
```http
|
||||||
|
GET /api/dashboard/overview HTTP/1.1
|
||||||
|
Cookie: laravel_session=eyJ....
|
||||||
|
```
|
||||||
|
|
||||||
|
### Authentifizierungs-Fehler
|
||||||
|
|
||||||
|
```json
|
||||||
|
HTTP/1.1 401 Unauthorized
|
||||||
|
{
|
||||||
|
"message": "Unauthenticated."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Wichtig:** Alle API-Endpoints erfordern eine gültige Session!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
### 1. Dashboard
|
||||||
|
|
||||||
|
#### GET /dashboard/overview
|
||||||
|
|
||||||
|
Liefert aggregierte KPIs und Alert-Übersichten für das Dashboard.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```http
|
||||||
|
GET /api/dashboard/overview HTTP/1.1
|
||||||
|
Cookie: laravel_session=...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:** `200 OK`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"generatedAt": "2025-01-19T07:30:00Z",
|
||||||
|
"activeAnalysts": 24,
|
||||||
|
"totalTransactions": 312,
|
||||||
|
"totalVolume": 98765432.10,
|
||||||
|
"alertsToday": 56,
|
||||||
|
"averageAlertsPerAnalyst": 3,
|
||||||
|
"precisionRate": 84,
|
||||||
|
"activeAlerts": {
|
||||||
|
"count": 128,
|
||||||
|
"highRiskCount": 19
|
||||||
|
},
|
||||||
|
"riskSegments": [
|
||||||
|
{
|
||||||
|
"label": "Kritisch (≥80)",
|
||||||
|
"count": 17,
|
||||||
|
"volume": 8900000.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Hoch (60-79)",
|
||||||
|
"count": 42,
|
||||||
|
"volume": 15200000.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Mittel (40-59)",
|
||||||
|
"count": 89,
|
||||||
|
"volume": 32100000.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"topCompanies": [
|
||||||
|
{
|
||||||
|
"companyId": 24,
|
||||||
|
"companyName": "Allianz SE",
|
||||||
|
"ticker": "ALV",
|
||||||
|
"sector": "Insurance",
|
||||||
|
"alerts": 6,
|
||||||
|
"alertVolume": 1450000.0,
|
||||||
|
"avgRiskScore": 82
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"runbooksExecutedToday": 41
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Transactions
|
||||||
|
|
||||||
|
#### GET /transactions
|
||||||
|
|
||||||
|
Liste alle Transaktionen mit globalen Filtern (Portfolio-weite Transaction Review).
|
||||||
|
|
||||||
|
**Query Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Typ | Default | Beschreibung |
|
||||||
|
|-----------|-----|---------|--------------|
|
||||||
|
| `search` | string | - | Match gegen Reference, Counterparty, Company |
|
||||||
|
| `status` | enum | `all` | `all`, `true_positive`, `false_positive`, `cleared` |
|
||||||
|
| `page` | integer | `1` | Seiten-Nummer (min: 1) |
|
||||||
|
| `perPage` | integer | `12` | Items pro Seite (min: 1, max: 100) |
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```http
|
||||||
|
GET /api/transactions?status=true_positive&page=1&perPage=12 HTTP/1.1
|
||||||
|
Cookie: laravel_session=...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:** `200 OK`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"filters": {
|
||||||
|
"statusOptions": [
|
||||||
|
{
|
||||||
|
"value": "true_positive",
|
||||||
|
"label": "Bestätigte Treffer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "false_positive",
|
||||||
|
"label": "Fehlalarme"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "cleared",
|
||||||
|
"label": "Freigegeben"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"perPage": 12
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"total": {
|
||||||
|
"count": 312,
|
||||||
|
"amount": 98765432.10
|
||||||
|
},
|
||||||
|
"byStatus": {
|
||||||
|
"true_positive": {
|
||||||
|
"count": 42,
|
||||||
|
"amount": 15200000.0
|
||||||
|
},
|
||||||
|
"false_positive": {
|
||||||
|
"count": 89,
|
||||||
|
"amount": 32100000.0
|
||||||
|
},
|
||||||
|
"cleared": {
|
||||||
|
"count": 181,
|
||||||
|
"amount": 51465432.10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": 512,
|
||||||
|
"company": {
|
||||||
|
"id": 12,
|
||||||
|
"name": "Allianz",
|
||||||
|
"legalName": "Allianz SE",
|
||||||
|
"ticker": "ALV",
|
||||||
|
"sector": "Insurance",
|
||||||
|
"country": "Germany",
|
||||||
|
"headquarters": "Munich",
|
||||||
|
"kycRiskLevel": "high",
|
||||||
|
"summary": "Multinational insurance provider with EMEA focus."
|
||||||
|
},
|
||||||
|
"counterparty": "Alpine Holdings Ltd.",
|
||||||
|
"counterpartyCountry": "Switzerland",
|
||||||
|
"status": "true_positive",
|
||||||
|
"statusLabel": "Bestätigter Treffer",
|
||||||
|
"requiresReview": true,
|
||||||
|
"riskScore": 87,
|
||||||
|
"amount": 245000.75,
|
||||||
|
"currency": "EUR",
|
||||||
|
"reference": "PAY-2024-10-1942",
|
||||||
|
"channel": "SWIFT",
|
||||||
|
"executedAt": "2025-01-18T09:14:00Z",
|
||||||
|
"flaggedReason": "Counterparty on sanctions watchlist"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pagination": {
|
||||||
|
"page": 1,
|
||||||
|
"perPage": 12,
|
||||||
|
"total": 128,
|
||||||
|
"lastPage": 11
|
||||||
|
},
|
||||||
|
"selectedTransactionId": null,
|
||||||
|
"selectedTransaction": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### GET /transactions/{transactionId}
|
||||||
|
|
||||||
|
Hole detaillierte Transaction Case File.
|
||||||
|
|
||||||
|
**Path Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Typ | Beschreibung |
|
||||||
|
|-----------|-----|--------------|
|
||||||
|
| `transactionId` | integer | Transaction ID |
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```http
|
||||||
|
GET /api/transactions/512 HTTP/1.1
|
||||||
|
Cookie: laravel_session=...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:** `200 OK`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 512,
|
||||||
|
"company": { ... },
|
||||||
|
"counterparty": "Alpine Holdings Ltd.",
|
||||||
|
"status": "true_positive",
|
||||||
|
"statusLabel": "Bestätigter Treffer",
|
||||||
|
"requiresReview": true,
|
||||||
|
"riskScore": 87,
|
||||||
|
"amount": 245000.75,
|
||||||
|
"currency": "EUR",
|
||||||
|
"reference": "PAY-2024-10-1942",
|
||||||
|
"channel": "SWIFT",
|
||||||
|
"executedAt": "2025-01-18T09:14:00Z",
|
||||||
|
"flaggedBy": "Screening Engine",
|
||||||
|
"flaggedReason": "Counterparty matched to EU sanctions list",
|
||||||
|
"signals": [
|
||||||
|
{
|
||||||
|
"type": "Adverse Media",
|
||||||
|
"value": "Enforcement action reported in 2024-11",
|
||||||
|
"weight": 0.8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Sanctions",
|
||||||
|
"value": "EU Sanctions List Match",
|
||||||
|
"weight": 1.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Errors:**
|
||||||
|
- `401 Unauthorized` - Session ungültig
|
||||||
|
- `404 Not Found` - Transaction existiert nicht
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Companies
|
||||||
|
|
||||||
|
#### GET /companies/search
|
||||||
|
|
||||||
|
Suche Companies und erhalte Screening-Übersicht.
|
||||||
|
|
||||||
|
**Query Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Typ | Default | Beschreibung |
|
||||||
|
|-----------|-----|---------|--------------|
|
||||||
|
| `q` | string | - | Freitext-Suche (Name, Legal Name, Ticker, Sector) |
|
||||||
|
| `limit` | integer | `6` | Max. Ergebnisse (min: 1, max: 25) |
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```http
|
||||||
|
GET /api/companies/search?q=Allianz&limit=6 HTTP/1.1
|
||||||
|
Cookie: laravel_session=...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:** `200 OK`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"overview": {
|
||||||
|
"totalCompanies": 40,
|
||||||
|
"openAlerts": 112,
|
||||||
|
"openAlertVolume": 5640000.0,
|
||||||
|
"averageRiskScore": 71,
|
||||||
|
"watchlistHits": 9,
|
||||||
|
"automationShare": 82
|
||||||
|
},
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"name": "Allianz",
|
||||||
|
"legalName": "Allianz SE",
|
||||||
|
"ticker": "ALV",
|
||||||
|
"sector": "Insurance",
|
||||||
|
"country": "Germany",
|
||||||
|
"headquarters": "Munich",
|
||||||
|
"kycRiskLevel": "high",
|
||||||
|
"summary": "Multinational insurance provider with EMEA focus.",
|
||||||
|
"alertCount": 7,
|
||||||
|
"alertVolume": 980000.0,
|
||||||
|
"alertRiskScore": 79,
|
||||||
|
"latestAlert": {
|
||||||
|
"transactionId": 731,
|
||||||
|
"counterparty": "Baltic Commodities LLC",
|
||||||
|
"executedAt": "2025-01-17T11:48:00Z",
|
||||||
|
"channel": "SWIFT",
|
||||||
|
"flaggedReason": "Pattern matches sanctions typology",
|
||||||
|
"riskScore": 88
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"query": "Allianz",
|
||||||
|
"resultCount": 6,
|
||||||
|
"limit": 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### GET /companies/{companyId}
|
||||||
|
|
||||||
|
Hole Company-Profil.
|
||||||
|
|
||||||
|
**Path Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Typ | Beschreibung |
|
||||||
|
|-----------|-----|--------------|
|
||||||
|
| `companyId` | integer | Company ID |
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```http
|
||||||
|
GET /api/companies/12 HTTP/1.1
|
||||||
|
Cookie: laravel_session=...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:** `200 OK`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"name": "Allianz",
|
||||||
|
"legalName": "Allianz SE",
|
||||||
|
"ticker": "ALV",
|
||||||
|
"sector": "Insurance",
|
||||||
|
"country": "Germany",
|
||||||
|
"headquarters": "Munich",
|
||||||
|
"kycRiskLevel": "high",
|
||||||
|
"summary": "Multinational insurance provider with EMEA focus.",
|
||||||
|
"createdAt": "2024-10-15T08:30:00Z",
|
||||||
|
"updatedAt": "2025-01-18T14:22:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Errors:**
|
||||||
|
- `401 Unauthorized` - Session ungültig
|
||||||
|
- `404 Not Found` - Company existiert nicht
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### GET /companies/{companyId}/transactions
|
||||||
|
|
||||||
|
Liste alle Transactions für eine Company.
|
||||||
|
|
||||||
|
**Path Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Typ | Beschreibung |
|
||||||
|
|-----------|-----|--------------|
|
||||||
|
| `companyId` | integer | Company ID |
|
||||||
|
|
||||||
|
**Query Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Typ | Default | Beschreibung |
|
||||||
|
|-----------|-----|---------|--------------|
|
||||||
|
| `status` | enum | `all` | `all`, `true_positive`, `false_positive`, `cleared` |
|
||||||
|
| `channel` | string | `all` | Channel-Filter (z.B. `SWIFT`, `SEPA`) |
|
||||||
|
| `page` | integer | `1` | Seiten-Nummer |
|
||||||
|
| `perPage` | integer | `10` | Items pro Seite (min: 1, max: 100) |
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```http
|
||||||
|
GET /api/companies/12/transactions?status=true_positive&page=1&perPage=10 HTTP/1.1
|
||||||
|
Cookie: laravel_session=...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:** `200 OK`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"company": {
|
||||||
|
"id": 12,
|
||||||
|
"name": "Allianz",
|
||||||
|
"legalName": "Allianz SE",
|
||||||
|
"ticker": "ALV",
|
||||||
|
"sector": "Insurance",
|
||||||
|
"country": "Germany",
|
||||||
|
"headquarters": "Munich",
|
||||||
|
"kycRiskLevel": "high",
|
||||||
|
"summary": "Multinational insurance provider..."
|
||||||
|
},
|
||||||
|
"filters": {
|
||||||
|
"statusOptions": [
|
||||||
|
{
|
||||||
|
"value": "true_positive",
|
||||||
|
"label": "Bestätigte Treffer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"channelOptions": [
|
||||||
|
{
|
||||||
|
"value": "SWIFT",
|
||||||
|
"label": "SWIFT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "SEPA",
|
||||||
|
"label": "SEPA"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"totalCount": 96,
|
||||||
|
"totalVolume": 7200000.0,
|
||||||
|
"openAlerts": {
|
||||||
|
"count": 12,
|
||||||
|
"amount": 1850000.0
|
||||||
|
},
|
||||||
|
"highRiskShare": 28,
|
||||||
|
"last30Days": {
|
||||||
|
"count": 15,
|
||||||
|
"amount": 980000.0
|
||||||
|
},
|
||||||
|
"byStatus": {
|
||||||
|
"true_positive": {
|
||||||
|
"count": 12,
|
||||||
|
"amount": 1850000.0
|
||||||
|
},
|
||||||
|
"false_positive": {
|
||||||
|
"count": 24,
|
||||||
|
"amount": 2100000.0
|
||||||
|
},
|
||||||
|
"cleared": {
|
||||||
|
"count": 60,
|
||||||
|
"amount": 3250000.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": 877,
|
||||||
|
"company": { ... },
|
||||||
|
"counterparty": "Alpine Holdings Ltd.",
|
||||||
|
"status": "true_positive",
|
||||||
|
"riskScore": 87,
|
||||||
|
"amount": 245000.75,
|
||||||
|
"currency": "EUR",
|
||||||
|
"reference": "PAY-2024-10-1942",
|
||||||
|
"channel": "SWIFT",
|
||||||
|
"executedAt": "2025-01-18T09:14:00Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pagination": {
|
||||||
|
"page": 1,
|
||||||
|
"perPage": 10,
|
||||||
|
"total": 12,
|
||||||
|
"lastPage": 2
|
||||||
|
},
|
||||||
|
"selectedTransactionId": null,
|
||||||
|
"selectedTransaction": null,
|
||||||
|
"recentAlerts": [
|
||||||
|
{
|
||||||
|
"id": 911,
|
||||||
|
"counterparty": "Northbridge Trading Ltd.",
|
||||||
|
"executedAt": "2025-01-18T14:52:00Z",
|
||||||
|
"channel": "SWIFT",
|
||||||
|
"status": "true_positive",
|
||||||
|
"statusLabel": "Bestätigter Treffer",
|
||||||
|
"riskScore": 92
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Errors:**
|
||||||
|
- `401 Unauthorized` - Session ungültig
|
||||||
|
- `404 Not Found` - Company nicht gefunden oder keine Transactions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### GET /companies/{companyId}/transactions/{transactionId}
|
||||||
|
|
||||||
|
Hole Transaction Case File mit Company-Context und History.
|
||||||
|
|
||||||
|
**Path Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Typ | Beschreibung |
|
||||||
|
|-----------|-----|--------------|
|
||||||
|
| `companyId` | integer | Company ID |
|
||||||
|
| `transactionId` | integer | Transaction ID |
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```http
|
||||||
|
GET /api/companies/12/transactions/877 HTTP/1.1
|
||||||
|
Cookie: laravel_session=...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:** `200 OK`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 877,
|
||||||
|
"company": { ... },
|
||||||
|
"counterparty": "Alpine Holdings Ltd.",
|
||||||
|
"status": "true_positive",
|
||||||
|
"statusLabel": "Bestätigter Treffer",
|
||||||
|
"requiresReview": true,
|
||||||
|
"riskScore": 87,
|
||||||
|
"amount": 245000.75,
|
||||||
|
"currency": "EUR",
|
||||||
|
"reference": "PAY-2024-10-1942",
|
||||||
|
"channel": "SWIFT",
|
||||||
|
"executedAt": "2025-01-18T09:14:00Z",
|
||||||
|
"flaggedBy": "Screening Engine",
|
||||||
|
"flaggedReason": "Counterparty matched to EU sanctions list",
|
||||||
|
"signals": [
|
||||||
|
{
|
||||||
|
"type": "Adverse Media",
|
||||||
|
"value": "Enforcement action reported in 2024-11",
|
||||||
|
"weight": 0.8
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recommendedActions": [
|
||||||
|
{
|
||||||
|
"title": "Verdachtsmeldung vorbereiten",
|
||||||
|
"description": "Erstellen Sie den Meldeentwurf für die FIU und sichern Sie Belege."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Enhanced Due Diligence",
|
||||||
|
"description": "Prüfen Sie zusätzliche Informationsquellen zur Counterparty."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"counterpartyHistory": [
|
||||||
|
{
|
||||||
|
"id": 765,
|
||||||
|
"executedAt": "2024-12-22T15:37:00Z",
|
||||||
|
"channel": "SWIFT",
|
||||||
|
"reference": "PAY-2024-12-1187",
|
||||||
|
"amount": 99000.0,
|
||||||
|
"currency": "EUR",
|
||||||
|
"riskScore": 74
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Errors:**
|
||||||
|
- `401 Unauthorized` - Session ungültig
|
||||||
|
- `404 Not Found` - Transaction nicht gefunden für diese Company
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Datenmodelle
|
||||||
|
|
||||||
|
### Transaction Status
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
enum TransactionStatus {
|
||||||
|
TRUE_POSITIVE = 'true_positive', // Kritisches Risiko
|
||||||
|
FALSE_POSITIVE = 'false_positive', // Hohes Risiko
|
||||||
|
CLEARED = 'cleared' // Geringes Risiko
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### KYC Risk Level
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
enum KycRiskLevel {
|
||||||
|
LOW = 'low',
|
||||||
|
HIGH = 'high',
|
||||||
|
CRITICAL = 'critical'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pagination Meta
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"page": 1,
|
||||||
|
"perPage": 12,
|
||||||
|
"total": 128,
|
||||||
|
"lastPage": 11
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Count Amount Summary
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"count": 42,
|
||||||
|
"amount": 2750000.50
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Transaction Signal
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "Adverse Media",
|
||||||
|
"value": "Enforcement action reported in 2024-11",
|
||||||
|
"weight": 0.8
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Recommended Action
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"title": "Verdachtsmeldung vorbereiten",
|
||||||
|
"description": "Erstellen Sie den Meldeentwurf für die FIU..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Beispiele
|
||||||
|
|
||||||
|
### cURL-Beispiele
|
||||||
|
|
||||||
|
#### Login & Session Cookie erhalten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Login
|
||||||
|
curl -c cookies.txt -X POST http://trusted_ai.test/login \
|
||||||
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||||
|
-d "email=user@example.com&password=secret"
|
||||||
|
|
||||||
|
# Session Cookie ist jetzt in cookies.txt gespeichert
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Dashboard Overview abrufen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -b cookies.txt http://trusted_ai.test/api/dashboard/overview
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Transactions filtern
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -b cookies.txt "http://trusted_ai.test/api/transactions?status=true_positive&page=1&perPage=12"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Company suchen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -b cookies.txt "http://trusted_ai.test/api/companies/search?q=Allianz&limit=6"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Company Transactions abrufen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -b cookies.txt "http://trusted_ai.test/api/companies/12/transactions?status=all&page=1"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### JavaScript (Fetch API)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Session Cookie wird automatisch vom Browser gesendet
|
||||||
|
|
||||||
|
// Dashboard Overview
|
||||||
|
const overview = await fetch('/api/dashboard/overview', {
|
||||||
|
credentials: 'include' // Wichtig: Session Cookie mitsenden
|
||||||
|
}).then(r => r.json());
|
||||||
|
|
||||||
|
console.log(overview);
|
||||||
|
|
||||||
|
// Transactions mit Filter
|
||||||
|
const transactions = await fetch('/api/transactions?status=true_positive&page=1&perPage=12', {
|
||||||
|
credentials: 'include'
|
||||||
|
}).then(r => r.json());
|
||||||
|
|
||||||
|
console.log(transactions.data);
|
||||||
|
|
||||||
|
// Company Search
|
||||||
|
const companies = await fetch('/api/companies/search?q=Allianz', {
|
||||||
|
credentials: 'include'
|
||||||
|
}).then(r => r.json());
|
||||||
|
|
||||||
|
console.log(companies.results);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TypeScript Types
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Dashboard Overview Response
|
||||||
|
interface DashboardOverview {
|
||||||
|
generatedAt: string;
|
||||||
|
activeAnalysts: number;
|
||||||
|
totalTransactions: number;
|
||||||
|
totalVolume: number;
|
||||||
|
alertsToday: number;
|
||||||
|
averageAlertsPerAnalyst: number;
|
||||||
|
precisionRate: number;
|
||||||
|
activeAlerts: {
|
||||||
|
count: number;
|
||||||
|
highRiskCount: number;
|
||||||
|
};
|
||||||
|
riskSegments: RiskSegment[];
|
||||||
|
topCompanies: TopCompanyAlert[];
|
||||||
|
runbooksExecutedToday: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transaction Collection Response
|
||||||
|
interface TransactionCollectionResponse {
|
||||||
|
filters: {
|
||||||
|
statusOptions: StatusOption[];
|
||||||
|
perPage: number;
|
||||||
|
};
|
||||||
|
metrics: TransactionMetrics;
|
||||||
|
data: TransactionPreview[];
|
||||||
|
pagination: PaginationMeta;
|
||||||
|
selectedTransactionId: number | null;
|
||||||
|
selectedTransaction: TransactionDetail | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Company Search Response
|
||||||
|
interface CompanySearchResponse {
|
||||||
|
overview: CompanySearchOverview;
|
||||||
|
results: CompanySearchResult[];
|
||||||
|
meta: {
|
||||||
|
query: string | null;
|
||||||
|
resultCount: number;
|
||||||
|
limit: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Standard Error Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "Error message",
|
||||||
|
"errors": {
|
||||||
|
"field": ["Validation error"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP Status Codes
|
||||||
|
|
||||||
|
| Code | Bedeutung | Beschreibung |
|
||||||
|
|------|-----------|--------------|
|
||||||
|
| `200` | OK | Request erfolgreich |
|
||||||
|
| `401` | Unauthorized | Session ungültig oder abgelaufen |
|
||||||
|
| `404` | Not Found | Resource nicht gefunden |
|
||||||
|
| `422` | Unprocessable Entity | Validierungsfehler |
|
||||||
|
| `500` | Internal Server Error | Server-Fehler |
|
||||||
|
|
||||||
|
### Beispiel: 401 Unauthorized
|
||||||
|
|
||||||
|
```json
|
||||||
|
HTTP/1.1 401 Unauthorized
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"message": "Unauthenticated."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Aktion:** Redirect zu `/login`
|
||||||
|
|
||||||
|
### Beispiel: 404 Not Found
|
||||||
|
|
||||||
|
```json
|
||||||
|
HTTP/1.1 404 Not Found
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"message": "Company not found."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Beispiel: 422 Validation Error
|
||||||
|
|
||||||
|
```json
|
||||||
|
HTTP/1.1 422 Unprocessable Entity
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"message": "The given data was invalid.",
|
||||||
|
"errors": {
|
||||||
|
"status": ["The selected status is invalid."],
|
||||||
|
"page": ["The page must be at least 1."]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
### Aktueller Status
|
||||||
|
|
||||||
|
**Aktuell:** Kein Rate Limiting implementiert.
|
||||||
|
|
||||||
|
### Geplant (Future)
|
||||||
|
|
||||||
|
```
|
||||||
|
Rate Limit: 60 Requests pro Minute pro User
|
||||||
|
Header: X-RateLimit-Limit, X-RateLimit-Remaining
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response bei Überschreitung:**
|
||||||
|
```json
|
||||||
|
HTTP/1.1 429 Too Many Requests
|
||||||
|
Content-Type: application/json
|
||||||
|
Retry-After: 60
|
||||||
|
|
||||||
|
{
|
||||||
|
"message": "Too many requests. Please try again later."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
### Version 1.0.0 (2025-01-19)
|
||||||
|
|
||||||
|
**Initial Release**
|
||||||
|
|
||||||
|
**Endpoints:**
|
||||||
|
- ✅ `GET /dashboard/overview` - Dashboard KPIs
|
||||||
|
- ✅ `GET /transactions` - Portfolio-wide Transactions
|
||||||
|
- ✅ `GET /transactions/{id}` - Transaction Detail
|
||||||
|
- ✅ `GET /companies/search` - Company Search
|
||||||
|
- ✅ `GET /companies/{id}` - Company Profile
|
||||||
|
- ✅ `GET /companies/{id}/transactions` - Company Transactions
|
||||||
|
- ✅ `GET /companies/{id}/transactions/{id}` - Company Transaction Detail
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Session-basierte Authentifizierung
|
||||||
|
- Pagination Support
|
||||||
|
- Filter & Search
|
||||||
|
- Metrics & Aggregationen
|
||||||
|
- OpenAPI 3.1 Spezifikation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementierungs-Status
|
||||||
|
|
||||||
|
### ⚠️ Wichtig: API noch nicht implementiert!
|
||||||
|
|
||||||
|
Die in diesem Dokument beschriebenen Endpoints sind **aktuell noch nicht implementiert**.
|
||||||
|
|
||||||
|
**Status:**
|
||||||
|
- ✅ OpenAPI Spezifikation vorhanden ([swagger.yaml](../swagger.yaml))
|
||||||
|
- ❌ API Routes noch nicht definiert (`routes/api.php` ist leer)
|
||||||
|
- ❌ API Controllers noch nicht erstellt
|
||||||
|
- ❌ API Responses noch nicht implementiert
|
||||||
|
|
||||||
|
### Nächste Schritte zur Implementierung
|
||||||
|
|
||||||
|
1. **API Routes definieren:**
|
||||||
|
```php
|
||||||
|
// routes/api.php
|
||||||
|
Route::middleware(['auth:sanctum'])->group(function () {
|
||||||
|
Route::get('/dashboard/overview', [DashboardController::class, 'overview']);
|
||||||
|
Route::get('/transactions', [TransactionController::class, 'index']);
|
||||||
|
Route::get('/transactions/{transaction}', [TransactionController::class, 'show']);
|
||||||
|
Route::get('/companies/search', [CompanyController::class, 'search']);
|
||||||
|
Route::get('/companies/{company}', [CompanyController::class, 'show']);
|
||||||
|
Route::get('/companies/{company}/transactions', [CompanyController::class, 'transactions']);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **API Controllers erstellen:**
|
||||||
|
```bash
|
||||||
|
php artisan make:controller Api/DashboardController
|
||||||
|
php artisan make:controller Api/TransactionController
|
||||||
|
php artisan make:controller Api/CompanyController
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **API Resources erstellen:**
|
||||||
|
```bash
|
||||||
|
php artisan make:resource TransactionResource
|
||||||
|
php artisan make:resource CompanyResource
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Tests schreiben:**
|
||||||
|
```bash
|
||||||
|
php artisan make:test Api/DashboardTest
|
||||||
|
php artisan make:test Api/TransactionTest
|
||||||
|
php artisan make:test Api/CompanyTest
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Zusammenfassung
|
||||||
|
|
||||||
|
### API-Übersicht
|
||||||
|
|
||||||
|
| Kategorie | Endpoints | Status |
|
||||||
|
|-----------|-----------|--------|
|
||||||
|
| Dashboard | 1 | ⚠️ Spezifiziert, nicht implementiert |
|
||||||
|
| Transactions | 2 | ⚠️ Spezifiziert, nicht implementiert |
|
||||||
|
| Companies | 4 | ⚠️ Spezifiziert, nicht implementiert |
|
||||||
|
| **Gesamt** | **7** | - |
|
||||||
|
|
||||||
|
### Datenmodelle
|
||||||
|
|
||||||
|
- **DashboardOverview** - Dashboard-KPIs
|
||||||
|
- **TransactionCollectionResponse** - Paginierte Transactions
|
||||||
|
- **TransactionDetail** - Detaillierte Transaction
|
||||||
|
- **CompanySearchResponse** - Company-Suchergebnisse
|
||||||
|
- **CompanyDetail** - Company-Profil
|
||||||
|
- **CompanyTransactionsResponse** - Company-spezifische Transactions
|
||||||
|
|
||||||
|
### Authentifizierung
|
||||||
|
|
||||||
|
**Session-basiert** via Laravel Session Cookie
|
||||||
|
- Login erforderlich
|
||||||
|
- Cookie-basierte Authentifizierung
|
||||||
|
- CSRF-Protection
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Erstellt:** 2025-11-24
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Autor:** Risk Intelligence Platform Team
|
||||||
|
**OpenAPI Spec:** [swagger.yaml](../swagger.yaml)
|
||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,991 @@
|
|||||||
|
# Entwickler-Setup-Guide: Risk Intelligence Platform
|
||||||
|
|
||||||
|
## 📋 Inhaltsverzeichnis
|
||||||
|
|
||||||
|
1. [Voraussetzungen](#voraussetzungen)
|
||||||
|
2. [Schnellstart](#schnellstart)
|
||||||
|
3. [Detaillierte Installation](#detaillierte-installation)
|
||||||
|
4. [Datenbank-Setup](#datenbank-setup)
|
||||||
|
5. [Environment-Konfiguration](#environment-konfiguration)
|
||||||
|
6. [Frontend-Assets](#frontend-assets)
|
||||||
|
7. [Erste Schritte](#erste-schritte)
|
||||||
|
8. [Development-Workflow](#development-workflow)
|
||||||
|
9. [Troubleshooting](#troubleshooting)
|
||||||
|
10. [Nützliche Commands](#nützliche-commands)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
### Erforderliche Software
|
||||||
|
|
||||||
|
| Software | Mindestversion | Empfohlen | Installation |
|
||||||
|
|----------|---------------|-----------|--------------|
|
||||||
|
| **PHP** | 8.2 | 8.4.14+ | [Laravel Herd](https://herd.laravel.com) |
|
||||||
|
| **Composer** | 2.0 | Latest | Via Herd oder [getcomposer.org](https://getcomposer.org) |
|
||||||
|
| **Node.js** | 18.x | 20.x+ | [nodejs.org](https://nodejs.org) |
|
||||||
|
| **npm** | 9.x | Latest | Mit Node.js installiert |
|
||||||
|
| **PostgreSQL** | 14.x | 16.x+ | [postgresql.org](https://www.postgresql.org) |
|
||||||
|
| **Git** | 2.x | Latest | [git-scm.com](https://git-scm.com) |
|
||||||
|
|
||||||
|
### Empfohlene Tools
|
||||||
|
|
||||||
|
- **Laravel Herd** - Lokale PHP-Entwicklungsumgebung (macOS)
|
||||||
|
- **TablePlus** / **pgAdmin** - PostgreSQL GUI
|
||||||
|
- **VS Code** - Editor mit PHP/Laravel Extensions
|
||||||
|
- **Postman** / **Insomnia** - API Testing (optional)
|
||||||
|
|
||||||
|
### PHP Extensions
|
||||||
|
|
||||||
|
Folgende PHP Extensions werden benötigt:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Prüfe installierte Extensions
|
||||||
|
php -m
|
||||||
|
|
||||||
|
# Benötigte Extensions:
|
||||||
|
- pdo_pgsql # PostgreSQL Driver
|
||||||
|
- mbstring # Multibyte String
|
||||||
|
- xml # XML Support
|
||||||
|
- curl # HTTP Client
|
||||||
|
- bcmath # Precision Math
|
||||||
|
- fileinfo # File Information
|
||||||
|
- json # JSON Support
|
||||||
|
- openssl # Encryption
|
||||||
|
- tokenizer # PHP Tokenizer
|
||||||
|
- zip # ZIP Archive
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schnellstart
|
||||||
|
|
||||||
|
Für erfahrene Entwickler - vollständige Installation in 5 Minuten:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Repository klonen
|
||||||
|
git clone <repository-url> risk-platform
|
||||||
|
cd risk-platform
|
||||||
|
|
||||||
|
# 2. Dependencies installieren & Setup ausführen
|
||||||
|
composer setup
|
||||||
|
|
||||||
|
# 3. PostgreSQL-Datenbank erstellen (siehe unten)
|
||||||
|
# Anpassen: .env mit DB-Credentials
|
||||||
|
|
||||||
|
# 4. Migrations ausführen
|
||||||
|
php artisan migrate --seed
|
||||||
|
|
||||||
|
# 5. Development-Server starten
|
||||||
|
composer run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fertig!** Die Applikation läuft auf [http://localhost:8000](http://localhost:8000)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Detaillierte Installation
|
||||||
|
|
||||||
|
### Schritt 1: Repository klonen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Via HTTPS
|
||||||
|
git clone https://github.com/your-org/risk-platform.git
|
||||||
|
cd risk-platform
|
||||||
|
|
||||||
|
# Oder via SSH
|
||||||
|
git clone git@github.com:your-org/risk-platform.git
|
||||||
|
cd risk-platform
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schritt 2: PHP Dependencies installieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer install
|
||||||
|
```
|
||||||
|
|
||||||
|
**Was passiert dabei?**
|
||||||
|
- Installiert alle Laravel-Pakete
|
||||||
|
- Installiert Livewire, Flux UI, Fortify
|
||||||
|
- Installiert Dev-Dependencies (Pest, Pint, Boost)
|
||||||
|
- Generiert Autoload-Files
|
||||||
|
|
||||||
|
### Schritt 3: Environment-Datei erstellen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env.example nach .env kopieren
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# Application Key generieren
|
||||||
|
php artisan key:generate
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schritt 4: Node Dependencies installieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
**Was passiert dabei?**
|
||||||
|
- Installiert Vite
|
||||||
|
- Installiert Tailwind CSS v4
|
||||||
|
- Installiert Build-Tools
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Datenbank-Setup
|
||||||
|
|
||||||
|
### PostgreSQL Installation
|
||||||
|
|
||||||
|
#### macOS (mit Homebrew)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# PostgreSQL installieren
|
||||||
|
brew install postgresql@16
|
||||||
|
|
||||||
|
# Als Service starten
|
||||||
|
brew services start postgresql@16
|
||||||
|
|
||||||
|
# Verbindung testen
|
||||||
|
psql postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
#### macOS (mit Postgres.app)
|
||||||
|
|
||||||
|
1. Download von [postgresapp.com](https://postgresapp.com)
|
||||||
|
2. App starten
|
||||||
|
3. Default Server initialisieren
|
||||||
|
|
||||||
|
#### Ubuntu/Debian
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install postgresql postgresql-contrib
|
||||||
|
sudo systemctl start postgresql
|
||||||
|
sudo systemctl enable postgresql
|
||||||
|
```
|
||||||
|
|
||||||
|
### Datenbank erstellen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Als postgres User einloggen
|
||||||
|
psql postgres
|
||||||
|
|
||||||
|
# Oder direkt mit spezifischem User
|
||||||
|
sudo -u postgres psql
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Datenbank erstellen
|
||||||
|
CREATE DATABASE risk_platform_db;
|
||||||
|
|
||||||
|
-- User erstellen (optional)
|
||||||
|
CREATE USER risk_user WITH ENCRYPTED PASSWORD 'your_secure_password';
|
||||||
|
|
||||||
|
-- Rechte vergeben
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE risk_platform_db TO risk_user;
|
||||||
|
|
||||||
|
-- In PostgreSQL 15+ auch Schema-Rechte vergeben
|
||||||
|
\c risk_platform_db
|
||||||
|
GRANT ALL ON SCHEMA public TO risk_user;
|
||||||
|
|
||||||
|
-- Exit
|
||||||
|
\q
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schemas erstellen
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Verbindung zur DB
|
||||||
|
psql -U risk_user -d risk_platform_db
|
||||||
|
|
||||||
|
-- PUBLIC Schema (wird automatisch erstellt)
|
||||||
|
-- BACKEND Schema erstellen
|
||||||
|
CREATE SCHEMA IF NOT EXISTS backend;
|
||||||
|
|
||||||
|
-- Rechte für BACKEND Schema
|
||||||
|
GRANT ALL ON SCHEMA backend TO risk_user;
|
||||||
|
|
||||||
|
-- Exit
|
||||||
|
\q
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verbindung testen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Direkter Connect
|
||||||
|
psql -h 127.0.0.1 -p 5432 -U risk_user -d risk_platform_db
|
||||||
|
|
||||||
|
# Mit Laravel Tinker
|
||||||
|
php artisan tinker
|
||||||
|
>>> DB::connection('pgsql_second')->select('SELECT version()');
|
||||||
|
>>> DB::connection('backend')->select('SELECT current_schema()');
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment-Konfiguration
|
||||||
|
|
||||||
|
### .env Datei anpassen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env öffnen und anpassen
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Grundkonfiguration
|
||||||
|
|
||||||
|
```ini
|
||||||
|
APP_NAME="Risk Intelligence Platform"
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=base64:xxx # Wird von key:generate erstellt
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost:8000
|
||||||
|
|
||||||
|
APP_LOCALE=de
|
||||||
|
APP_FALLBACK_LOCALE=en
|
||||||
|
APP_FAKER_LOCALE=de_DE
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Datenbank-Konfiguration (Wichtig!)
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# Default Connection (PUBLIC Schema)
|
||||||
|
DB_CONNECTION=pgsql
|
||||||
|
DB_CONNECTION2=pgsql
|
||||||
|
DB_HOST2=127.0.0.1
|
||||||
|
DB_PORT2=5432
|
||||||
|
DB_DATABASE2=risk_platform_db
|
||||||
|
DB_USERNAME2=risk_user
|
||||||
|
DB_PASSWORD2=your_secure_password
|
||||||
|
```
|
||||||
|
|
||||||
|
**Wichtig:** Die Applikation nutzt `DB_*2` Variablen für PostgreSQL!
|
||||||
|
|
||||||
|
#### Cache & Session
|
||||||
|
|
||||||
|
```ini
|
||||||
|
CACHE_STORE=database
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
QUEUE_CONNECTION=database
|
||||||
|
```
|
||||||
|
|
||||||
|
**Warum database?**
|
||||||
|
- Einfaches Setup ohne Redis
|
||||||
|
- Funktioniert out-of-the-box
|
||||||
|
- Für Produktion: Wechsel zu Redis empfohlen
|
||||||
|
|
||||||
|
#### Mail-Konfiguration (Development)
|
||||||
|
|
||||||
|
```ini
|
||||||
|
MAIL_MAILER=log
|
||||||
|
MAIL_FROM_ADDRESS="noreply@risk-platform.test"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
```
|
||||||
|
|
||||||
|
Mails werden in `storage/logs/laravel.log` gespeichert.
|
||||||
|
|
||||||
|
#### Optional: Redis (für bessere Performance)
|
||||||
|
|
||||||
|
```ini
|
||||||
|
CACHE_STORE=redis
|
||||||
|
SESSION_DRIVER=redis
|
||||||
|
QUEUE_CONNECTION=redis
|
||||||
|
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vollständige .env Vorlage
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Klicken für vollständige .env Beispiel-Datei</summary>
|
||||||
|
|
||||||
|
```ini
|
||||||
|
APP_NAME="Risk Intelligence Platform"
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=base64:xxx
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost:8000
|
||||||
|
|
||||||
|
APP_LOCALE=de
|
||||||
|
APP_FALLBACK_LOCALE=en
|
||||||
|
APP_FAKER_LOCALE=de_DE
|
||||||
|
|
||||||
|
APP_MAINTENANCE_DRIVER=file
|
||||||
|
PHP_CLI_SERVER_WORKERS=4
|
||||||
|
BCRYPT_ROUNDS=12
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_STACK=single
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
# PostgreSQL Configuration
|
||||||
|
DB_CONNECTION=pgsql
|
||||||
|
DB_CONNECTION2=pgsql
|
||||||
|
DB_HOST2=127.0.0.1
|
||||||
|
DB_PORT2=5432
|
||||||
|
DB_DATABASE2=risk_platform_db
|
||||||
|
DB_USERNAME2=risk_user
|
||||||
|
DB_PASSWORD2=your_secure_password
|
||||||
|
|
||||||
|
# Session & Cache
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
SESSION_ENCRYPT=false
|
||||||
|
SESSION_PATH=/
|
||||||
|
SESSION_DOMAIN=null
|
||||||
|
|
||||||
|
CACHE_STORE=database
|
||||||
|
QUEUE_CONNECTION=database
|
||||||
|
|
||||||
|
# Broadcasting & Filesystem
|
||||||
|
BROADCAST_CONNECTION=log
|
||||||
|
FILESYSTEM_DISK=local
|
||||||
|
|
||||||
|
# Mail
|
||||||
|
MAIL_MAILER=log
|
||||||
|
MAIL_FROM_ADDRESS="noreply@risk-platform.test"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
# Vite
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Frontend-Assets
|
||||||
|
|
||||||
|
### Assets kompilieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development Build (einmalig)
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Development mit Hot Reload
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Was macht `npm run dev`?
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────┐
|
||||||
|
│ VITE v7.0.4 ready in X ms │
|
||||||
|
│ │
|
||||||
|
│ ➜ Local: http://localhost:5173/ │
|
||||||
|
│ ➜ Network: use --host to expose │
|
||||||
|
│ │
|
||||||
|
│ ➜ Laravel: http://localhost:8000 │
|
||||||
|
└─────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
✓ compiled successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
- Startet Vite Dev-Server auf Port 5173
|
||||||
|
- Hot Module Replacement (HMR) aktiviert
|
||||||
|
- Tailwind CSS v4 wird kompiliert
|
||||||
|
- Livewire-Assets werden gebundled
|
||||||
|
|
||||||
|
### Production Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Output:
|
||||||
|
# dist/assets/app-xxxxx.js
|
||||||
|
# dist/assets/app-xxxxx.css
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Erste Schritte
|
||||||
|
|
||||||
|
### 1. Migrations ausführen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Alle Migrations ausführen
|
||||||
|
php artisan migrate
|
||||||
|
|
||||||
|
# Mit Seeding (Test-Daten)
|
||||||
|
php artisan migrate --seed
|
||||||
|
|
||||||
|
# Migration-Status prüfen
|
||||||
|
php artisan migrate:status
|
||||||
|
```
|
||||||
|
|
||||||
|
**Erwartete Tabellen nach Migration:**
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────┬────────┐
|
||||||
|
│ Migration │ Ran? │
|
||||||
|
├──────────────────────────────────┼────────┤
|
||||||
|
│ 0001_01_01_000000_create_users │ Yes │
|
||||||
|
│ 0001_01_01_000001_create_cache │ Yes │
|
||||||
|
│ 0001_01_01_000002_create_jobs │ Yes │
|
||||||
|
│ 2025_09_02_075243_add_two_factor │ Yes │
|
||||||
|
│ 2025_10_20_181750_create_companies │ Yes │
|
||||||
|
│ 2025_10_20_181753_create_transactions │ Yes │
|
||||||
|
│ 2025_11_16_140224_add_output_columns │ Yes │
|
||||||
|
│ 2025_11_16_150000_create_backend_data_pool │ Yes │
|
||||||
|
│ ... │ │
|
||||||
|
└──────────────────────────────────┴────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Test-User erstellen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan tinker
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Test-User erstellen
|
||||||
|
$user = App\Models\User::create([
|
||||||
|
'name' => 'Admin User',
|
||||||
|
'email' => 'admin@example.com',
|
||||||
|
'password' => bcrypt('password'),
|
||||||
|
'email_verified_at' => now(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Oder mit Factory
|
||||||
|
App\Models\User::factory()->create([
|
||||||
|
'email' => 'test@example.com',
|
||||||
|
]);
|
||||||
|
|
||||||
|
exit
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Development-Server starten
|
||||||
|
|
||||||
|
#### Option A: Composer Dev Command (Empfohlen)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
**Startet parallel:**
|
||||||
|
- `php artisan serve` → http://localhost:8000
|
||||||
|
- `php artisan queue:listen` → Queue Worker
|
||||||
|
- `php artisan pail` → Live Logs
|
||||||
|
- `npm run dev` → Vite Dev Server
|
||||||
|
|
||||||
|
#### Option B: Einzelne Services manuell
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Terminal 1: Laravel Server
|
||||||
|
php artisan serve
|
||||||
|
|
||||||
|
# Terminal 2: Vite Dev Server
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# Terminal 3 (optional): Queue Worker
|
||||||
|
php artisan queue:work
|
||||||
|
|
||||||
|
# Terminal 4 (optional): Logs
|
||||||
|
php artisan pail
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option C: Laravel Herd (macOS)
|
||||||
|
|
||||||
|
Wenn du Laravel Herd nutzt:
|
||||||
|
|
||||||
|
1. Projekt in Herd-Verzeichnis verschieben
|
||||||
|
2. Automatische Domain: `risk-platform.test`
|
||||||
|
3. HTTPS automatisch aktiviert
|
||||||
|
4. Kein `php artisan serve` notwendig
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In Herd-Verzeichnis verschieben
|
||||||
|
mv ~/risk-platform ~/Herd/risk-platform
|
||||||
|
|
||||||
|
# Browser öffnen
|
||||||
|
open https://risk-platform.test
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Applikation öffnen
|
||||||
|
|
||||||
|
Browser öffnen: [http://localhost:8000](http://localhost:8000)
|
||||||
|
|
||||||
|
**Login-Credentials:**
|
||||||
|
- Email: `test@example.com`
|
||||||
|
- Password: `password`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development-Workflow
|
||||||
|
|
||||||
|
### Typischer Entwicklungstag
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Morgen: Repository aktualisieren
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
# 2. Dependencies aktualisieren (falls composer.lock geändert)
|
||||||
|
composer install
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# 3. Neue Migrations (falls vorhanden)
|
||||||
|
php artisan migrate
|
||||||
|
|
||||||
|
# 4. Dev-Server starten
|
||||||
|
composer run dev
|
||||||
|
|
||||||
|
# 5. Am Ende: Code formatieren
|
||||||
|
vendor/bin/pint
|
||||||
|
|
||||||
|
# 6. Tests ausführen
|
||||||
|
php artisan test
|
||||||
|
|
||||||
|
# 7. Commit & Push
|
||||||
|
git add .
|
||||||
|
git commit -m "feat: neue feature"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code-Formatierung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Alle Dateien formatieren
|
||||||
|
vendor/bin/pint
|
||||||
|
|
||||||
|
# Nur geänderte Dateien
|
||||||
|
vendor/bin/pint --dirty
|
||||||
|
|
||||||
|
# Test-Modus (ohne Änderungen)
|
||||||
|
vendor/bin/pint --test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tests ausführen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Alle Tests
|
||||||
|
php artisan test
|
||||||
|
|
||||||
|
# Nur Feature Tests
|
||||||
|
php artisan test --testsuite=Feature
|
||||||
|
|
||||||
|
# Nur Unit Tests
|
||||||
|
php artisan test --testsuite=Unit
|
||||||
|
|
||||||
|
# Spezifische Test-Datei
|
||||||
|
php artisan test tests/Feature/CompanyTest.php
|
||||||
|
|
||||||
|
# Mit Filter
|
||||||
|
php artisan test --filter=testCompanyCreation
|
||||||
|
|
||||||
|
# Mit Coverage (benötigt Xdebug)
|
||||||
|
php artisan test --coverage
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backend-Daten synchronisieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stats anzeigen (kein Sync)
|
||||||
|
php artisan backend:sync-data-pool --stats
|
||||||
|
|
||||||
|
# Incremental Sync
|
||||||
|
php artisan backend:sync-data-pool --incremental
|
||||||
|
|
||||||
|
# Full Sync
|
||||||
|
php artisan backend:sync-data-pool --full
|
||||||
|
|
||||||
|
# Transformation
|
||||||
|
php artisan backend:transform-data-pool
|
||||||
|
|
||||||
|
# Kompletter Rebuild
|
||||||
|
php artisan backend:rebuild
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scheduler lokal testen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Schedule Worker (läuft dauerhaft)
|
||||||
|
php artisan schedule:work
|
||||||
|
|
||||||
|
# Oder: Nächste Due-Tasks anzeigen
|
||||||
|
php artisan schedule:list
|
||||||
|
|
||||||
|
# Einzelnen Task testen
|
||||||
|
php artisan schedule:test sync-backend-data-pool-incremental
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Problem: "SQLSTATE[08006] Connection refused"
|
||||||
|
|
||||||
|
**Ursache:** PostgreSQL läuft nicht oder falsche Credentials
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# PostgreSQL-Status prüfen
|
||||||
|
brew services list | grep postgresql
|
||||||
|
|
||||||
|
# PostgreSQL starten
|
||||||
|
brew services start postgresql@16
|
||||||
|
|
||||||
|
# Verbindung testen
|
||||||
|
psql -h 127.0.0.1 -p 5432 -U risk_user -d risk_platform_db
|
||||||
|
|
||||||
|
# .env prüfen
|
||||||
|
cat .env | grep DB_
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problem: "Class 'PDO' not found"
|
||||||
|
|
||||||
|
**Ursache:** PHP PostgreSQL Extension fehlt
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# Installierte Extensions prüfen
|
||||||
|
php -m | grep pdo
|
||||||
|
|
||||||
|
# Mit Herd (macOS)
|
||||||
|
# Extensions sind normalerweise vorinstalliert
|
||||||
|
|
||||||
|
# Oder PHP neu installieren via Homebrew
|
||||||
|
brew reinstall php@8.4
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problem: "Vite manifest not found"
|
||||||
|
|
||||||
|
**Ursache:** Frontend-Assets nicht kompiliert
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# Development Build
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Oder Dev-Server starten
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problem: "419 Page Expired" bei Forms
|
||||||
|
|
||||||
|
**Ursache:** CSRF-Token ungültig (Session abgelaufen)
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# Cache leeren
|
||||||
|
php artisan config:clear
|
||||||
|
php artisan cache:clear
|
||||||
|
php artisan view:clear
|
||||||
|
|
||||||
|
# Browser: Hard Refresh (Cmd+Shift+R / Ctrl+Shift+R)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problem: Migrations laufen nicht
|
||||||
|
|
||||||
|
**Ursache:** Datenbank-Schema fehlt oder keine Rechte
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# Schema-Rechte prüfen
|
||||||
|
psql -U risk_user -d risk_platform_db
|
||||||
|
|
||||||
|
# In psql:
|
||||||
|
SELECT schema_name FROM information_schema.schemata;
|
||||||
|
|
||||||
|
# Rechte vergeben
|
||||||
|
GRANT ALL ON SCHEMA public TO risk_user;
|
||||||
|
GRANT ALL ON ALL TABLES IN SCHEMA public TO risk_user;
|
||||||
|
|
||||||
|
# Migration erneut versuchen
|
||||||
|
php artisan migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problem: Queue-Jobs laufen nicht
|
||||||
|
|
||||||
|
**Ursache:** Queue-Worker läuft nicht
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# Queue-Worker starten
|
||||||
|
php artisan queue:work
|
||||||
|
|
||||||
|
# Oder mit Auto-Restart bei Code-Änderungen
|
||||||
|
php artisan queue:listen
|
||||||
|
|
||||||
|
# Failed Jobs anzeigen
|
||||||
|
php artisan queue:failed
|
||||||
|
|
||||||
|
# Failed Jobs erneut versuchen
|
||||||
|
php artisan queue:retry all
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problem: "Class not found" Fehler
|
||||||
|
|
||||||
|
**Ursache:** Autoload-Cache veraltet
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# Autoload neu generieren
|
||||||
|
composer dump-autoload
|
||||||
|
|
||||||
|
# Alle Caches leeren
|
||||||
|
php artisan optimize:clear
|
||||||
|
|
||||||
|
# Oder einzeln:
|
||||||
|
php artisan config:clear
|
||||||
|
php artisan cache:clear
|
||||||
|
php artisan route:clear
|
||||||
|
php artisan view:clear
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problem: Livewire-Components laden nicht
|
||||||
|
|
||||||
|
**Ursache:** Volt-Components nicht registriert
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# Volt Provider prüfen
|
||||||
|
cat bootstrap/providers.php | grep Volt
|
||||||
|
|
||||||
|
# Cache leeren
|
||||||
|
php artisan optimize:clear
|
||||||
|
|
||||||
|
# Browser Cache leeren
|
||||||
|
# Cmd+Shift+R (macOS) oder Ctrl+Shift+R (Windows/Linux)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problem: Styling fehlt / Tailwind funktioniert nicht
|
||||||
|
|
||||||
|
**Ursache:** Vite-Server läuft nicht oder falsche Konfiguration
|
||||||
|
|
||||||
|
**Lösung:**
|
||||||
|
```bash
|
||||||
|
# Vite Dev-Server neu starten
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# Oder Production-Build
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Tailwind-Config prüfen
|
||||||
|
cat tailwind.config.js
|
||||||
|
|
||||||
|
# Node-Modules neu installieren
|
||||||
|
rm -rf node_modules package-lock.json
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nützliche Commands
|
||||||
|
|
||||||
|
### Laravel Artisan
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Liste aller Commands
|
||||||
|
php artisan list
|
||||||
|
|
||||||
|
# Command-Hilfe
|
||||||
|
php artisan help migrate
|
||||||
|
|
||||||
|
# Interaktive Shell
|
||||||
|
php artisan tinker
|
||||||
|
|
||||||
|
# Cache Management
|
||||||
|
php artisan cache:clear
|
||||||
|
php artisan config:clear
|
||||||
|
php artisan route:clear
|
||||||
|
php artisan view:clear
|
||||||
|
php artisan optimize:clear # Alle Caches auf einmal
|
||||||
|
|
||||||
|
# Database
|
||||||
|
php artisan db:show # DB-Info anzeigen
|
||||||
|
php artisan migrate:status # Migration-Status
|
||||||
|
php artisan migrate:fresh --seed # DB neu aufsetzen + Seeds
|
||||||
|
|
||||||
|
# Make Commands
|
||||||
|
php artisan make:model Company
|
||||||
|
php artisan make:controller CompanyController
|
||||||
|
php artisan make:migration create_companies_table
|
||||||
|
php artisan make:livewire CompanySearch
|
||||||
|
php artisan make:test CompanyTest
|
||||||
|
php artisan make:class Services/MyService
|
||||||
|
|
||||||
|
# Routes
|
||||||
|
php artisan route:list # Alle Routes anzeigen
|
||||||
|
php artisan route:list --path=companies # Gefiltert
|
||||||
|
```
|
||||||
|
|
||||||
|
### Composer
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Dependencies installieren
|
||||||
|
composer install
|
||||||
|
|
||||||
|
# Development-Dependencies überspringen
|
||||||
|
composer install --no-dev
|
||||||
|
|
||||||
|
# Einzelnes Package installieren
|
||||||
|
composer require laravel/telescope
|
||||||
|
|
||||||
|
# Package entfernen
|
||||||
|
composer remove laravel/telescope
|
||||||
|
|
||||||
|
# Autoload regenerieren
|
||||||
|
composer dump-autoload
|
||||||
|
|
||||||
|
# Setup ausführen (custom script)
|
||||||
|
composer setup
|
||||||
|
|
||||||
|
# Dev-Server starten (custom script)
|
||||||
|
composer run dev
|
||||||
|
|
||||||
|
# Tests ausführen (custom script)
|
||||||
|
composer test
|
||||||
|
```
|
||||||
|
|
||||||
|
### NPM
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Dependencies installieren
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Dev-Server starten
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# Production Build
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Package installieren
|
||||||
|
npm install alpine.js
|
||||||
|
|
||||||
|
# Package entfernen
|
||||||
|
npm uninstall alpine.js
|
||||||
|
|
||||||
|
# Outdated Packages prüfen
|
||||||
|
npm outdated
|
||||||
|
|
||||||
|
# Updates installieren
|
||||||
|
npm update
|
||||||
|
```
|
||||||
|
|
||||||
|
### Git
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Aktueller Branch
|
||||||
|
git branch
|
||||||
|
|
||||||
|
# Neuen Branch erstellen
|
||||||
|
git checkout -b feature/neue-funktion
|
||||||
|
|
||||||
|
# Änderungen anzeigen
|
||||||
|
git status
|
||||||
|
git diff
|
||||||
|
|
||||||
|
# Commit
|
||||||
|
git add .
|
||||||
|
git commit -m "feat: neue funktion"
|
||||||
|
git push origin feature/neue-funktion
|
||||||
|
|
||||||
|
# Main aktualisieren
|
||||||
|
git checkout main
|
||||||
|
git pull origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verbinden
|
||||||
|
psql -U risk_user -d risk_platform_db
|
||||||
|
|
||||||
|
# In psql:
|
||||||
|
\dt # Alle Tabellen
|
||||||
|
\d companies # Tabellen-Schema anzeigen
|
||||||
|
\dn # Alle Schemas
|
||||||
|
\du # Alle User
|
||||||
|
\l # Alle Datenbanken
|
||||||
|
\q # Exit
|
||||||
|
|
||||||
|
# Backup erstellen
|
||||||
|
pg_dump -U risk_user risk_platform_db > backup.sql
|
||||||
|
|
||||||
|
# Backup einspielen
|
||||||
|
psql -U risk_user risk_platform_db < backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nächste Schritte
|
||||||
|
|
||||||
|
Nach erfolgreichem Setup:
|
||||||
|
|
||||||
|
1. **Architektur-Dokumentation lesen** → [docs/architecture-overview.md](architecture-overview.md)
|
||||||
|
2. **Backend-Sync Commands kennenlernen** → [docs/backend-sync-commands.md](backend-sync-commands.md)
|
||||||
|
3. **Code-Konventionen studieren** → [CLAUDE.md](../CLAUDE.md)
|
||||||
|
4. **Tests schreiben & ausführen** → `php artisan test`
|
||||||
|
5. **Erste Änderungen committen** → `git commit`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Hilfe & Support
|
||||||
|
|
||||||
|
### Dokumentation
|
||||||
|
|
||||||
|
- **Architektur-Übersicht:** [docs/architecture-overview.md](architecture-overview.md)
|
||||||
|
- **Backend-Sync:** [docs/backend-sync-commands.md](backend-sync-commands.md)
|
||||||
|
- **Scheduling:** [docs/scheduling-setup.md](scheduling-setup.md)
|
||||||
|
- **Migration:** [docs/sync-migration-instructions.md](sync-migration-instructions.md)
|
||||||
|
|
||||||
|
### Laravel Dokumentation
|
||||||
|
|
||||||
|
- **Laravel 12:** [https://laravel.com/docs/12.x](https://laravel.com/docs/12.x)
|
||||||
|
- **Livewire 3:** [https://livewire.laravel.com](https://livewire.laravel.com)
|
||||||
|
- **Flux UI:** [https://flux.laravel.com](https://flux.laravel.com)
|
||||||
|
- **Pest Testing:** [https://pestphp.com](https://pestphp.com)
|
||||||
|
|
||||||
|
### Logs prüfen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Application Logs (Live)
|
||||||
|
tail -f storage/logs/laravel.log
|
||||||
|
|
||||||
|
# Nur Fehler
|
||||||
|
tail -f storage/logs/laravel.log | grep ERROR
|
||||||
|
|
||||||
|
# Mit Laravel Pail (farbig)
|
||||||
|
php artisan pail
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debugging
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Laravel Debugbar (installiert)
|
||||||
|
# Aktiviert automatisch wenn APP_DEBUG=true
|
||||||
|
# Erscheint am unteren Bildschirmrand im Browser
|
||||||
|
|
||||||
|
# Tinker für schnelle Tests
|
||||||
|
php artisan tinker
|
||||||
|
>>> App\Models\Company::count()
|
||||||
|
>>> DB::table('transactions')->latest()->first()
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Setup-Zeit:** ~15-30 Minuten
|
||||||
|
**Erstellt:** 2025-11-24
|
||||||
|
**Version:** 1.0
|
||||||
|
**Autor:** Risk Intelligence Platform Team
|
||||||
|
|
||||||
|
Viel Erfolg beim Entwickeln! 🚀
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -8,6 +8,15 @@ Route::get('/', function () {
|
|||||||
return view('welcome');
|
return view('welcome');
|
||||||
})->name('home');
|
})->name('home');
|
||||||
|
|
||||||
|
Route::get('/health', function () {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'healthy',
|
||||||
|
'timestamp' => now()->toIso8601String(),
|
||||||
|
'app' => config('app.name'),
|
||||||
|
'env' => config('app.env'),
|
||||||
|
]);
|
||||||
|
})->name('health');
|
||||||
|
|
||||||
Route::view('dashboard', 'dashboard')
|
Route::view('dashboard', 'dashboard')
|
||||||
->middleware(['auth', 'verified'])
|
->middleware(['auth', 'verified'])
|
||||||
->name('dashboard');
|
->name('dashboard');
|
||||||
|
|||||||
Executable
+258
@@ -0,0 +1,258 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Deployment Script für Synology NAS
|
||||||
|
# Dieses Script wird auf der Synology NAS ausgeführt
|
||||||
|
|
||||||
|
set -e # Exit on error
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Configuration
|
||||||
|
# ============================================
|
||||||
|
PROJECT_DIR="/volume1/docker/laravel-app"
|
||||||
|
DOCKER_IMAGE="laravel-app"
|
||||||
|
COMPOSE_FILE="docker-compose.synology.yml"
|
||||||
|
ENV_FILE=".env.synology"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Helper Functions
|
||||||
|
# ============================================
|
||||||
|
log_info() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warn() {
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Pre-deployment Checks
|
||||||
|
# ============================================
|
||||||
|
log_info "Starting deployment process..."
|
||||||
|
|
||||||
|
# Check if running on Synology
|
||||||
|
if [ ! -d "/volume1" ]; then
|
||||||
|
log_error "This script should be run on Synology NAS"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Navigate to project directory
|
||||||
|
cd "$PROJECT_DIR" || {
|
||||||
|
log_error "Project directory not found: $PROJECT_DIR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if Docker is installed
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
log_error "Docker is not installed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if docker-compose is installed
|
||||||
|
if ! command -v docker-compose &> /dev/null; then
|
||||||
|
log_error "docker-compose is not installed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Load Docker Image
|
||||||
|
# ============================================
|
||||||
|
if [ -f "laravel-app.tar.gz" ]; then
|
||||||
|
log_info "Loading Docker image from artifact..."
|
||||||
|
gunzip -c laravel-app.tar.gz | docker load
|
||||||
|
|
||||||
|
# Tag the image appropriately
|
||||||
|
LOADED_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep laravel-app | head -n1)
|
||||||
|
if [ -n "$LOADED_IMAGE" ]; then
|
||||||
|
docker tag "$LOADED_IMAGE" "${DOCKER_IMAGE}:latest"
|
||||||
|
log_info "Tagged image as ${DOCKER_IMAGE}:latest"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_warn "No Docker image artifact found. Using existing image or building..."
|
||||||
|
|
||||||
|
# Check if Dockerfile exists and build if necessary
|
||||||
|
if [ -f "Dockerfile" ]; then
|
||||||
|
log_info "Building Docker image..."
|
||||||
|
docker build -t "${DOCKER_IMAGE}:latest" .
|
||||||
|
else
|
||||||
|
log_error "Neither Docker artifact nor Dockerfile found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Environment Configuration
|
||||||
|
# ============================================
|
||||||
|
if [ ! -f "$ENV_FILE" ]; then
|
||||||
|
log_warn "Environment file not found: $ENV_FILE"
|
||||||
|
|
||||||
|
if [ -f ".env.synology.example" ]; then
|
||||||
|
log_info "Copying from .env.synology.example..."
|
||||||
|
cp .env.synology.example "$ENV_FILE"
|
||||||
|
log_warn "⚠️ Please configure $ENV_FILE with your settings!"
|
||||||
|
else
|
||||||
|
log_error "No environment configuration found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Backup Current Deployment
|
||||||
|
# ============================================
|
||||||
|
log_info "Creating backup of current deployment..."
|
||||||
|
|
||||||
|
BACKUP_DIR="/volume1/docker/backups/laravel-app"
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||||
|
BACKUP_FILE="$BACKUP_DIR/backup_${TIMESTAMP}.tar.gz"
|
||||||
|
|
||||||
|
# Backup database if container is running
|
||||||
|
if docker ps --format '{{.Names}}' | grep -q "laravel_postgres"; then
|
||||||
|
log_info "Backing up PostgreSQL database..."
|
||||||
|
docker exec laravel_postgres pg_dump -U ingest_user ingest_db > "$BACKUP_DIR/db_${TIMESTAMP}.sql"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Keep only last 5 backups
|
||||||
|
log_info "Cleaning old backups (keeping last 5)..."
|
||||||
|
ls -t "$BACKUP_DIR"/db_*.sql 2>/dev/null | tail -n +6 | xargs -r rm
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Stop Current Containers
|
||||||
|
# ============================================
|
||||||
|
log_info "Stopping current containers..."
|
||||||
|
|
||||||
|
if [ -f "$COMPOSE_FILE" ]; then
|
||||||
|
docker-compose -f "$COMPOSE_FILE" down || log_warn "No containers to stop"
|
||||||
|
else
|
||||||
|
log_warn "Compose file not found: $COMPOSE_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Clean up old images (optional)
|
||||||
|
# ============================================
|
||||||
|
log_info "Cleaning up old Docker images..."
|
||||||
|
docker image prune -f
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Start New Deployment
|
||||||
|
# ============================================
|
||||||
|
log_info "Starting new deployment..."
|
||||||
|
|
||||||
|
if [ ! -f "$COMPOSE_FILE" ]; then
|
||||||
|
log_error "Docker Compose file not found: $COMPOSE_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Pull/use latest images and start services
|
||||||
|
docker-compose -f "$COMPOSE_FILE" up -d --build
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Wait for Services to Start
|
||||||
|
# ============================================
|
||||||
|
log_info "Waiting for services to start..."
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Check if containers are running
|
||||||
|
if ! docker ps --format '{{.Names}}' | grep -q "laravel_app"; then
|
||||||
|
log_error "Laravel app container failed to start"
|
||||||
|
|
||||||
|
# Show logs
|
||||||
|
log_info "Container logs:"
|
||||||
|
docker-compose -f "$COMPOSE_FILE" logs --tail=50
|
||||||
|
|
||||||
|
# Rollback
|
||||||
|
log_warn "Attempting rollback..."
|
||||||
|
docker-compose -f "$COMPOSE_FILE" down
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Post-deployment Tasks
|
||||||
|
# ============================================
|
||||||
|
log_info "Running post-deployment tasks..."
|
||||||
|
|
||||||
|
# Wait for database to be ready
|
||||||
|
log_info "Waiting for database to be ready..."
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Run migrations
|
||||||
|
log_info "Running database migrations..."
|
||||||
|
docker exec laravel_app php artisan migrate --force || log_warn "Migrations failed"
|
||||||
|
|
||||||
|
# Clear caches
|
||||||
|
log_info "Clearing caches..."
|
||||||
|
docker exec laravel_app php artisan cache:clear || log_warn "Cache clear failed"
|
||||||
|
docker exec laravel_app php artisan config:clear || log_warn "Config clear failed"
|
||||||
|
docker exec laravel_app php artisan view:clear || log_warn "View clear failed"
|
||||||
|
|
||||||
|
# Optimize
|
||||||
|
log_info "Optimizing application..."
|
||||||
|
docker exec laravel_app php artisan config:cache || log_warn "Config cache failed"
|
||||||
|
docker exec laravel_app php artisan route:cache || log_warn "Route cache failed"
|
||||||
|
docker exec laravel_app php artisan view:cache || log_warn "View cache failed"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Health Check
|
||||||
|
# ============================================
|
||||||
|
log_info "Performing health check..."
|
||||||
|
|
||||||
|
MAX_RETRIES=30
|
||||||
|
RETRY_COUNT=0
|
||||||
|
HEALTH_CHECK_URL="http://localhost:8080"
|
||||||
|
|
||||||
|
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
|
||||||
|
if curl -f -s "$HEALTH_CHECK_URL" > /dev/null 2>&1; then
|
||||||
|
log_info "✅ Application is healthy!"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "⏳ Waiting for application... ($RETRY_COUNT/$MAX_RETRIES)"
|
||||||
|
sleep 5
|
||||||
|
RETRY_COUNT=$((RETRY_COUNT + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
|
||||||
|
log_error "Health check failed after $MAX_RETRIES attempts"
|
||||||
|
|
||||||
|
# Show recent logs
|
||||||
|
log_info "Recent application logs:"
|
||||||
|
docker-compose -f "$COMPOSE_FILE" logs --tail=100
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Display Status
|
||||||
|
# ============================================
|
||||||
|
log_info "Deployment completed successfully! 🚀"
|
||||||
|
log_info "Container status:"
|
||||||
|
docker-compose -f "$COMPOSE_FILE" ps
|
||||||
|
|
||||||
|
log_info ""
|
||||||
|
log_info "==================================="
|
||||||
|
log_info "Application URL: http://$(hostname -I | awk '{print $1}'):8080"
|
||||||
|
log_info "==================================="
|
||||||
|
log_info ""
|
||||||
|
log_info "Useful commands:"
|
||||||
|
log_info " - View logs: docker-compose -f $COMPOSE_FILE logs -f"
|
||||||
|
log_info " - Restart: docker-compose -f $COMPOSE_FILE restart"
|
||||||
|
log_info " - Stop: docker-compose -f $COMPOSE_FILE down"
|
||||||
|
log_info " - Shell access: docker exec -it laravel_app sh"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Cleanup
|
||||||
|
# ============================================
|
||||||
|
log_info "Cleaning up deployment artifacts..."
|
||||||
|
rm -f laravel-app.tar.gz
|
||||||
|
|
||||||
|
log_info "Deployment script completed!"
|
||||||
|
exit 0
|
||||||
Reference in new issue
Block a user