genten anpassungen
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: coder
|
||||
description: "Use this agent when new Go features need to be implemented or existing Go code needs to be modified. This agent writes maintainable, idiomatic Go code that adheres to all project requirements. Examples:\n\n<example>\nContext: The user wants a new agent or command.\nuser: 'Füge einen neuen /status Command zum Discord-Bot hinzu'\nassistant: 'Ich starte den coder Agenten für die Implementierung.'\n<commentary>\nNeue Funktionalität in Go → coder Agent.\n</commentary>\n</example>\n\n<example>\nContext: The user wants to refactor existing code.\nuser: 'Extrahiere die Email-Logik in ein eigenes Package'\nassistant: 'Ich nutze den coder Agenten für das Refactoring.'\n<commentary>\nCode-Änderung in Go → coder Agent.\n</commentary>\n</example>"
|
||||
model: sonnet
|
||||
color: green
|
||||
---
|
||||
|
||||
@@ -9,7 +8,7 @@ Du bist ein erfahrener Go-Entwickler. Du implementierst Features, behebst Bugs u
|
||||
|
||||
## Workflow
|
||||
|
||||
1. `CLAUDE.md` lesen – Architektur und Konventionen verstehen
|
||||
1. `CLAUDE.md` und `doc/architecture.md` lesen – Architektur und Konventionen verstehen
|
||||
2. Betroffene Quelldateien lesen, bevor du Änderungen vornimmst
|
||||
3. Implementieren nach den Qualitätskriterien unten
|
||||
4. Prüfen: Kompiliert der Code? (`go build ./...`)
|
||||
@@ -37,6 +36,13 @@ Du bist ein erfahrener Go-Entwickler. Du implementierst Features, behebst Bugs u
|
||||
- Keine sensitiven Daten (Passwörter, Tokens) in Logs
|
||||
- Input-Validierung an Systemgrenzen (externe Eingaben, API-Calls)
|
||||
|
||||
## Projektspezifische Hinweise
|
||||
|
||||
- **`config.Cfg`** ist eine globale Variable — bei Tests muss `config.LoadConfig()` aufgerufen oder `Cfg` direkt gesetzt werden
|
||||
- **Defer-first Pattern**: Discord-Handlers senden sofort `InteractionResponseDeferredChannelMessageWithSource`, dann berechnen — nie >3s warten
|
||||
- **Agent Interface**: Alle Agenten implementieren `Handle(Request) Response` (siehe `internal/agents/agent.go`)
|
||||
- **Deployment**: Binary wird lokal cross-compiliert (`CGO_ENABLED=0 GOOS=linux GOARCH=amd64`) — kein CGO erlaubt
|
||||
|
||||
## Constraints
|
||||
|
||||
- Keine neuen externen Abhängigkeiten ohne expliziten Auftrag
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: software-architect
|
||||
description: "Use this agent to verify or enforce software architecture, review structural decisions, or ensure new code fits the existing design. Invoke after larger changes, when adding new files/packages, or when the user asks for an architecture review. Examples:\n\n<example>\nContext: A new feature was implemented and the user wants to verify it fits the architecture.\nuser: 'Prüf ob der neue Code zur Architektur passt'\nassistant: 'Ich starte den software-architect Agenten für eine Architekturprüfung.'\n<commentary>\nArchitekturprüfung → software-architect Agent.\n</commentary>\n</example>\n\n<example>\nContext: The user plans a larger refactoring.\nuser: 'Ich will die Email-Logik umstrukturieren'\nassistant: 'Lass mich den software-architect Agenten fragen, ob das zur Architektur passt.'\n<commentary>\nStrukturelle Entscheidung → software-architect Agent.\n</commentary>\n</example>"
|
||||
model: sonnet
|
||||
color: blue
|
||||
---
|
||||
|
||||
@@ -10,7 +9,7 @@ Du bist Softwarearchitekt für dieses Projekt. Du überwachst die Softwarestrukt
|
||||
## Workflow
|
||||
|
||||
### Architekturprüfung
|
||||
1. `CLAUDE.md` lesen – Soll-Architektur verstehen
|
||||
1. `CLAUDE.md` und `doc/architecture.md` lesen – Soll-Architektur verstehen
|
||||
2. Alle relevanten Go-Quelldateien lesen
|
||||
3. Verantwortlichkeiten prüfen: Liegt Code im richtigen Package/Datei?
|
||||
4. Neue Dateien/Packages prüfen: Sind sie gerechtfertigt?
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: tester
|
||||
description: "Use this agent when new Go code has been written or modified and needs unit tests, or when existing tests need review and improvement. Examples:\n\n<example>\nContext: A new function was added.\nuser: 'Ich habe eine neue Funktion in brain/ingest.go hinzugefügt'\nassistant: 'Ich starte den tester Agenten für Unit-Tests.'\n<commentary>\nNeuer Go-Code → tester Agent für Tests.\n</commentary>\n</example>\n\n<example>\nContext: The user wants a quality check.\nuser: 'Kannst du die Testabdeckung für den Task-Agent prüfen?'\nassistant: 'Ich starte den tester Agenten für eine Testüberprüfung.'\n<commentary>\nQualitätssicherung → tester Agent.\n</commentary>\n</example>"
|
||||
model: sonnet
|
||||
color: red
|
||||
---
|
||||
|
||||
@@ -36,6 +35,12 @@ Du bist ein erfahrener Go-Entwickler spezialisiert auf das Schreiben hochwertige
|
||||
6. Self-Review: kein Test der trivialerweise immer besteht
|
||||
7. Zusammenfassung: Was wurde getestet, welche Coverage-Lücken bleiben
|
||||
|
||||
## Projektspezifische Hinweise
|
||||
|
||||
- **`config.Cfg`** muss in Tests initialisiert werden — entweder `config.LoadConfig()` aufrufen oder `config.Cfg` direkt mit Testwerten setzen
|
||||
- **Existierende Tests als Referenz**: `internal/brain/ingest_test.go`, `internal/agents/task/store_test.go`, `internal/agents/agent_test.go`, `internal/config/config_test.go`
|
||||
- **Externe Services** (Qdrant, LocalAI, IMAP) sind in Tests nicht verfügbar — nur reine Logik testen (Chunking, ID-Generierung, Formatierung, Parsing)
|
||||
|
||||
## Constraints
|
||||
|
||||
- Nur Go stdlib – keine externen Test-Frameworks (kein testify, gomock, etc.)
|
||||
|
||||
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
||||
bin/
|
||||
*.exe
|
||||
deploy.env
|
||||
.git
|
||||
.claude
|
||||
47
CLAUDE.md
47
CLAUDE.md
@@ -29,12 +29,21 @@ go run ./cmd/mailtest/ -llm-only
|
||||
# Run tests
|
||||
go test ./...
|
||||
|
||||
# Run a single test
|
||||
go test ./internal/brain/ -run TestChunk -v
|
||||
|
||||
# Debug-Logging (LLM-Prompts + Antworten)
|
||||
DEBUG=1 go run ./cmd/discord/
|
||||
|
||||
# Tidy dependencies
|
||||
go mod tidy
|
||||
|
||||
# Deployment auf Remote-Server (192.168.1.118)
|
||||
# Integration test (prüft Erreichbarkeit aller externen Dienste + Unit-Tests)
|
||||
bash test-integration.sh
|
||||
|
||||
# Deployment auf Remote-Server via Docker
|
||||
cp deploy.env.example deploy.env # einmalig: Credentials eintragen
|
||||
bash deploy.sh # build + upload + systemctl restart
|
||||
bash deploy.sh # rsync source + docker compose build + up
|
||||
```
|
||||
|
||||
Binaries are output to `./bin/`. The `config.yml` file must exist in the working directory at runtime.
|
||||
@@ -87,6 +96,7 @@ Qdrant (gRPC) + LocalAI (HTTP, OpenAI-kompatibel)
|
||||
| Slash-Command | @Mention | Funktion |
|
||||
|---------------|----------|---------|
|
||||
| `/ask`, `/research` | `@bot <frage>` | Wissensdatenbank abfragen (mit Chat-Gedächtnis) |
|
||||
| `/deepask` | – | Tiefe Recherche mit Multi-Step Reasoning (max 3 iterative RAG-Suchen) |
|
||||
| `/asknobrain` | – | Direkt an LLM (kein RAG) |
|
||||
| `/memory store` | `@bot remember <text>` | Text speichern |
|
||||
| `/memory ingest` | `@bot ingest` | Markdown neu einlesen |
|
||||
@@ -121,7 +131,7 @@ Qdrant (gRPC) + LocalAI (HTTP, OpenAI-kompatibel)
|
||||
- **Email processed_folder**: Nach Zusammenfassung werden ungelesene Emails in konfigurierten IMAP-Ordner verschoben (leer = deaktiviert)
|
||||
- **Morgen-Briefing**: `dailyBriefing()` kombiniert offene Tasks (mit Fälligkeits-Highlighting) + ungelesene Emails täglich um 8:00
|
||||
- **Archiv-Cleanup**: `email.CleanupArchiveFolders()` läuft täglich um `cleanup_hour` (Standard: 2:00) — iteriert alle Accounts/`archive_folders`, löscht Emails älter als `retention_days` via IMAP `\Deleted` + `EXPUNGE`. `retention_days: 0` = dauerhaft behalten (No-op).
|
||||
- **Email-Triage**: `email.triageUnread()` klassifiziert ungelesene Emails sequentiell (eine nach der anderen) als wichtig/unwichtig via LLM. Unwichtige Emails werden in `triage_folder` verschoben. Jede Entscheidung wird in Qdrant gespeichert (`type: email_triage`). Bei nächster Klassifizierung sucht `triage.SearchSimilar()` ähnliche Entscheidungen (Score ≥ 0.7) als Few-Shot-Kontext — das Modell lernt aus der Geschichte. Triage läuft vor `SummarizeUnreadAccount()`.
|
||||
- **Email-Triage**: `email.triageUnread()` klassifiziert ungelesene Emails sequentiell (eine nach der anderen) als wichtig/unwichtig via LLM. Wichtige Emails werden in `triage_important_folder`, unwichtige in `triage_unimportant_folder` verschoben. Jede Entscheidung wird in Qdrant gespeichert (`type: email_triage`). Bei nächster Klassifizierung sucht `triage.SearchSimilar()` ähnliche Entscheidungen (Score ≥ 0.7) als Few-Shot-Kontext — das Modell lernt aus der Geschichte. Triage läuft vor `SummarizeUnreadAccount()`.
|
||||
- **Nacht-Ingest**: `nightlyIngest()` läuft täglich um `ingest_hour` (Standard: 23:00) — importiert alle Emails aller Archiv-Ordner in Qdrant via `brain.IngestEmailFolder()`.
|
||||
- **User-Permissions**: `discord.allowed_users: ["user-id1", "user-id2"]` — wenn gesetzt, dürfen nur diese Discord-User-IDs den Bot nutzen. Leer = keine Einschränkung.
|
||||
- **URL-Ingest**: `brain.IngestURL(url)` — fetcht URL, extrahiert sichtbaren HTML-Text (skippt script/style/nav/footer), chunked und importiert in Qdrant. Via `/memory url <url>`.
|
||||
@@ -148,7 +158,8 @@ email:
|
||||
starttls: true # oder tls: true für implizites TLS (Port 993)
|
||||
folder: INBOX # optional, Standard: INBOX
|
||||
processed_folder: "Processed" # nach Zusammenfassung verschieben (leer = deaktiviert)
|
||||
triage_folder: "Unwichtig" # LLM-Triage: unwichtige Emails hier ablegen (leer = deaktiviert)
|
||||
triage_important_folder: "Wichtig" # LLM-Triage: wichtige Emails hierhin (leer = in INBOX lassen)
|
||||
triage_unimportant_folder: "Unwichtig" # LLM-Triage: unwichtige Emails hierhin (leer = deaktiviert)
|
||||
model: "" # optional: eigenes LLM-Modell für Email-Analyse
|
||||
archive_folders: # optional: Archivordner mit automatischer Bereinigung
|
||||
- name: "Archiv"
|
||||
@@ -205,20 +216,38 @@ rss_feeds:
|
||||
|
||||
## Deployment
|
||||
|
||||
Deployment läuft über Docker auf dem Remote-Server. `deploy.sh` cross-compiliert das Binary **lokal** (`CGO_ENABLED=0 GOOS=linux GOARCH=amd64`), überträgt Binary + Dockerfile + docker-compose.yml + config.yml per `sshpass`/`scp` und startet den Container auf dem Server via `docker compose up -d --build`. Kein Go-Toolchain auf dem Server nötig.
|
||||
|
||||
```bash
|
||||
# deploy.env (nicht in Git):
|
||||
DEPLOY_HOST=192.168.1.118
|
||||
DEPLOY_USER=christoph
|
||||
DEPLOY_PASS=...
|
||||
DEPLOY_DIR=/home/christoph/brain-bot
|
||||
SERVICE_NAME=brain-bot
|
||||
DEPLOY_CONFIG=true
|
||||
|
||||
# Systemd-Service (einmalig):
|
||||
sudo systemctl unmask brain-bot # falls masked
|
||||
# Deploy: lokal bauen + scp + docker compose up
|
||||
bash deploy.sh
|
||||
|
||||
# Status/Logs auf dem Server:
|
||||
ssh user@host 'cd /home/christoph/brain-bot && docker compose ps'
|
||||
ssh user@host 'cd /home/christoph/brain-bot && docker compose logs -f'
|
||||
```
|
||||
|
||||
Script `deploy.sh` baut das Linux-Binary, überträgt es per `sshpass`/`scp` und startet den systemd-Service neu.
|
||||
Docker-Setup: Minimales Runtime-Image (`alpine:3.21`), `Dockerfile` kopiert nur das fertige Binary. `docker-compose.yml` mountet `config.yml`, `tasks.json` und `brain_data/`.
|
||||
|
||||
### Systemd (DEPRECATED)
|
||||
|
||||
Der alte Systemd-Ansatz wird nicht mehr aktiv genutzt. `deploy.sh` deaktiviert einen vorhandenen systemd-Service automatisch bei der Migration zu Docker.
|
||||
|
||||
```bash
|
||||
# Einmalig auf dem Server (falls noch nicht migriert):
|
||||
sudo systemctl stop brain-bot
|
||||
sudo systemctl disable brain-bot
|
||||
|
||||
# Manueller Fallback ohne Docker:
|
||||
scp bin/discord-bot user@host:/home/christoph/brain-bot/
|
||||
ssh user@host 'sudo systemctl restart brain-bot'
|
||||
```
|
||||
|
||||
## Model Limitations
|
||||
|
||||
|
||||
6
Dockerfile
Normal file
6
Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
||||
# Minimales Runtime-Image – Binary wird lokal cross-compiliert und per scp übertragen
|
||||
FROM alpine:3.21
|
||||
RUN apk add --no-cache ca-certificates tzdata
|
||||
WORKDIR /app
|
||||
COPY discord-bot .
|
||||
CMD ["./discord-bot"]
|
||||
@@ -6,11 +6,7 @@ DEPLOY_USER=todo
|
||||
DEPLOY_PASS=geheim
|
||||
|
||||
# Zielverzeichnis auf dem Server
|
||||
DEPLOY_DIR=/home/jacek/brain-bot
|
||||
DEPLOY_DIR=/home/todo/brain-bot
|
||||
|
||||
# Systemd-Servicename
|
||||
SERVICE_NAME=brain-bot
|
||||
|
||||
# config.yml mitdeployen? (true/false)
|
||||
# false = config.yml bleibt auf dem Server unangetastet
|
||||
DEPLOY_CONFIG=true
|
||||
# Docker-Image-Name (optional)
|
||||
IMAGE_NAME=brain-bot
|
||||
|
||||
96
deploy.sh
96
deploy.sh
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy.sh – Baut den Bot und deployt ihn per SSH auf den Server
|
||||
# deploy.sh – Baut Binary lokal (cross-compile) und deployt es per scp auf den Server
|
||||
set -euo pipefail
|
||||
|
||||
# Credentials aus deploy.env laden
|
||||
@@ -14,8 +14,6 @@ source "$ENV_FILE"
|
||||
: "${DEPLOY_USER:?DEPLOY_USER fehlt in deploy.env}"
|
||||
: "${DEPLOY_PASS:?DEPLOY_PASS fehlt in deploy.env}"
|
||||
: "${DEPLOY_DIR:=/home/${DEPLOY_USER}/brain-bot}"
|
||||
: "${SERVICE_NAME:=brain-bot}"
|
||||
: "${DEPLOY_CONFIG:=true}"
|
||||
|
||||
# Sudo-Passwort: standardmäßig gleich wie SSH-Passwort
|
||||
SUDO_PASS="${SUDO_PASS:-$DEPLOY_PASS}"
|
||||
@@ -35,73 +33,51 @@ scp_cmd() {
|
||||
sshpass -p "$DEPLOY_PASS" scp $SSH_OPTS "$@"
|
||||
}
|
||||
|
||||
# sudo ohne TTY: Passwort per stdin (-S), -p '' unterdrückt den Prompt auf stderr
|
||||
sudo_cmd() {
|
||||
ssh_cmd "echo '${SUDO_PASS}' | sudo -S -p '' $*"
|
||||
}
|
||||
|
||||
# ── Build ────────────────────────────────────────────────────────────────────
|
||||
echo "🔨 Baue Linux-Binary (amd64)..."
|
||||
GOOS=linux GOARCH=amd64 go build -o bin/discord-linux ./cmd/discord/
|
||||
echo "✅ Binary gebaut"
|
||||
# ── Lokaler Cross-Compile-Build ─────────────────────────────────────────────
|
||||
echo "🔨 Baue Linux/amd64-Binary lokal..."
|
||||
mkdir -p bin
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/discord-bot ./cmd/discord/
|
||||
echo "✅ Binary gebaut: bin/discord-bot"
|
||||
|
||||
# ── Systemd-Service deaktivieren (einmalige Migration) ──────────────────────
|
||||
if ssh_cmd "systemctl is-enabled --quiet brain-bot 2>/dev/null"; then
|
||||
echo "🔄 Migriere von systemd zu Docker..."
|
||||
sudo_cmd "systemctl stop brain-bot" 2>/dev/null || true
|
||||
sudo_cmd "systemctl disable brain-bot" 2>/dev/null || true
|
||||
echo "✅ Systemd-Service deaktiviert"
|
||||
fi
|
||||
|
||||
# ── Alten Container stoppen ─────────────────────────────────────────────────
|
||||
echo "⏹️ Stoppe laufenden Container..."
|
||||
ssh_cmd "cd '${DEPLOY_DIR}' && docker compose down 2>/dev/null" || true
|
||||
echo "✅ Container gestoppt"
|
||||
|
||||
# ── Zielverzeichnis anlegen ─────────────────────────────────────────────────
|
||||
echo "📁 Stelle Zielverzeichnis sicher: ${DEPLOY_DIR}..."
|
||||
ssh_cmd "mkdir -p '${DEPLOY_DIR}'"
|
||||
|
||||
# ── Dateien übertragen ───────────────────────────────────────────────────────
|
||||
echo "📁 Zielverzeichnis ${DEPLOY_DIR} auf ${DEPLOY_HOST}..."
|
||||
if ! ssh_cmd "mkdir -p ${DEPLOY_DIR}"; then
|
||||
echo "❌ Verzeichnis konnte nicht erstellt werden – prüfe Rechte auf ${DEPLOY_HOST}"
|
||||
exit 1
|
||||
fi
|
||||
echo "📦 Übertrage Binary..."
|
||||
scp_cmd bin/discord-bot "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_DIR}/discord-bot"
|
||||
|
||||
echo "🚀 Übertrage Binary..."
|
||||
# Als temporäre Datei hochladen, dann atomar ersetzen (laufendes Binary kann nicht überschrieben werden)
|
||||
if ! scp_cmd bin/discord-linux "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_DIR}/discord.new"; then
|
||||
echo "❌ SCP fehlgeschlagen"
|
||||
exit 1
|
||||
fi
|
||||
ssh_cmd "chmod +x '${DEPLOY_DIR}/discord.new' && mv '${DEPLOY_DIR}/discord.new' '${DEPLOY_DIR}/discord'"
|
||||
echo "📋 Übertrage Dockerfile + docker-compose.yml..."
|
||||
scp_cmd Dockerfile docker-compose.yml "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_DIR}/"
|
||||
|
||||
if [[ "$DEPLOY_CONFIG" == "true" ]]; then
|
||||
echo "📋 Übertrage config.yml..."
|
||||
scp_cmd config.yml "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_DIR}/config.yml"
|
||||
fi
|
||||
echo "📋 Übertrage config.yml..."
|
||||
scp_cmd config.yml "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_DIR}/config.yml"
|
||||
|
||||
# ── Systemd-Service ──────────────────────────────────────────────────────────
|
||||
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
# tasks.json anlegen falls nicht vorhanden (Volume-Mount braucht existierende Datei)
|
||||
ssh_cmd "test -f '${DEPLOY_DIR}/tasks.json' || echo '[]' > '${DEPLOY_DIR}/tasks.json'"
|
||||
|
||||
if ! ssh_cmd "test -f '${SERVICE_FILE}'" 2>/dev/null; then
|
||||
echo "📝 Installiere systemd-Service..."
|
||||
|
||||
# Service-Datei zuerst in /tmp schreiben (kein sudo nötig), dann verschieben
|
||||
TMP_SERVICE="/tmp/${SERVICE_NAME}.service"
|
||||
ssh_cmd "cat > '${TMP_SERVICE}'" <<EOF
|
||||
[Unit]
|
||||
Description=my-brain-importer Discord Bot
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=${DEPLOY_DIR}/discord
|
||||
WorkingDirectory=${DEPLOY_DIR}
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
User=${DEPLOY_USER}
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
sudo_cmd "mv '${TMP_SERVICE}' '${SERVICE_FILE}'"
|
||||
sudo_cmd "systemctl daemon-reload"
|
||||
sudo_cmd "systemctl enable '${SERVICE_NAME}'"
|
||||
echo "✅ Service installiert und aktiviert"
|
||||
fi
|
||||
|
||||
# ── Neustart ─────────────────────────────────────────────────────────────────
|
||||
echo "🔄 Starte Service neu..."
|
||||
# unmask falls der Service als masked markiert ist
|
||||
sudo_cmd "systemctl unmask '${SERVICE_NAME}'" 2>/dev/null || true
|
||||
sudo_cmd "systemctl restart '${SERVICE_NAME}'"
|
||||
# ── Docker-Image auf Server bauen und starten ────────────────────────────────
|
||||
echo "🚀 Baue Image und starte Container..."
|
||||
ssh_cmd "cd '${DEPLOY_DIR}' && docker compose up -d --build"
|
||||
|
||||
echo ""
|
||||
echo "✅ Deployment abgeschlossen!"
|
||||
echo " Status: ssh ${DEPLOY_USER}@${DEPLOY_HOST} 'systemctl status ${SERVICE_NAME}'"
|
||||
echo " Logs: ssh ${DEPLOY_USER}@${DEPLOY_HOST} 'journalctl -u ${SERVICE_NAME} -f'"
|
||||
echo " Status: ssh ${DEPLOY_USER}@${DEPLOY_HOST} 'cd ${DEPLOY_DIR} && docker compose ps'"
|
||||
echo " Logs: ssh ${DEPLOY_USER}@${DEPLOY_HOST} 'cd ${DEPLOY_DIR} && docker compose logs -f'"
|
||||
|
||||
@@ -208,13 +208,13 @@ Discord-Token wird separat in `main()` geprüft.
|
||||
```
|
||||
Entwickler-PC (WSL2)
|
||||
│ bash deploy.sh
|
||||
│ sshpass + scp
|
||||
│ 1. CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build (lokal)
|
||||
│ 2. sshpass + scp (Binary + Dockerfile + docker-compose.yml + config.yml)
|
||||
│ 3. docker compose up -d --build (remote)
|
||||
▼
|
||||
Home-Server (192.168.1.118)
|
||||
├── systemd: brain-bot.service
|
||||
│ ExecStart: /home/christoph/brain-bot/brain-bot
|
||||
│ WorkingDirectory: /home/christoph/brain-bot/
|
||||
│ (config.yml liegt hier)
|
||||
├── Docker: brain-bot Container (alpine:3.21 + Binary)
|
||||
│ Volumes: config.yml, tasks.json, brain_data/
|
||||
│
|
||||
├── LocalAI (Port 8080) — Embeddings + Chat
|
||||
└── Qdrant (auf 192.168.1.4, Port 6334) — Vektordatenbank
|
||||
|
||||
14
docker-compose.yml
Normal file
14
docker-compose.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
services:
|
||||
bot:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: brain-bot:latest
|
||||
container_name: brain-bot
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
volumes:
|
||||
- ./config.yml:/app/config.yml:ro
|
||||
- ./tasks.json:/app/tasks.json
|
||||
- ./brain_data:/app/brain_data
|
||||
Reference in New Issue
Block a user