# BizNode Local Restart Guide

This document explains how to restart all BizNode services locally on Windows when Docker Desktop is unavailable or the Docker engine is disconnected.

---

## Services Overview

| Service | Default Port | What It Does |
|---------|-------------|--------------|
| Ollama (LLM) | 11434 | Local language model for AI replies and script generation |
| Qdrant (Vector DB) | 6333 | Semantic memory and support KB search |
| Dashboard (FastAPI) | 7777 | Web UI, REST API, owner notifications |
| Telegram Bot | — | @biznode_bot, polls Telegram API for messages |
| Scheduler | — | APScheduler inside the bot process (backups, digest, IMAP, video tasks) |

---

## Common Problems and Solutions

### 1. Docker Engine Not Connected

**Symptom:** Docker Desktop is open but containers won't start. Error:
```
open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified
```

**Cause:** Docker Desktop GUI is running but the backend engine is disconnected. This happens after Windows updates, sleep/hibernate, or Docker Desktop crashes.

**Fix:**
1. Quit Docker Desktop completely (system tray > right-click > Quit)
2. Wait 10 seconds
3. Reopen Docker Desktop
4. Wait for the engine status to show "Running" (bottom-left indicator)
5. If it still fails, restart Windows

**Workaround:** Run all services locally without Docker (see sections below).

---

### 2. Qdrant Not Running

**Symptom:** Bot replies are generic (no memory/context). Dashboard KB search returns empty. Error in logs:
```
Connection refused on localhost:6333
```

**Check:**
```bash
curl http://localhost:6333/collections
```

**Fix — Option A: Docker**
```bash
docker start qdrant
```

**Fix — Option B: Local Binary**

Download `qdrant.exe` from https://github.com/qdrant/qdrant/releases (Windows x86_64 zip).

Place `qdrant.exe` in a known location (e.g., `C:\qdrant\qdrant.exe`), then start it:

```bash
set QDRANT__STORAGE__STORAGE_PATH=C:\nodesrunning\biznodemainnode\memory\qdrant\storage
set QDRANT__SERVICE__HTTP_PORT=6333
C:\qdrant\qdrant.exe
```

Or from Git Bash / WSL:
```bash
QDRANT__STORAGE__STORAGE_PATH="C:/nodesrunning/biznodemainnode/memory/qdrant/storage" \
QDRANT__SERVICE__HTTP_PORT=6333 \
/c/qdrant/qdrant.exe
```

**Note:** Do NOT use `--storage-path` CLI flags — Qdrant v1.13+ only accepts configuration via environment variables or config file.

**Verify:**
```bash
curl http://localhost:6333/collections
```
Expected: `{"result":{"collections":[{"name":"biznode_memory"},...]}}` with status `"ok"`.

---

### 3. Ollama Not Running

**Symptom:** Bot replies with fallback text, video scripts use the 3-scene fallback instead of LLM-generated scripts.

**Check:**
```bash
curl http://localhost:11434/api/tags
```

**Fix:**
```bash
ollama serve
```
Ollama typically auto-starts on Windows. If not, launch it from the Start menu or run the command above.

**Verify:**
```bash
curl http://localhost:11434/api/generate -d "{\"model\":\"qwen3.5:4b\",\"prompt\":\"hello\",\"stream\":false}"
```

---

### 4. Dashboard Not Running

**Symptom:** `localhost:7777` unreachable. Bot can't send owner notifications. Video task API unavailable.

**Check:**
```bash
curl http://localhost:7777/api/health
```

**Fix:**
```bash
cd C:\nodesrunning\biznodemainnode
python run_dashboard.py
```

Or in background (Git Bash):
```bash
cd /c/nodesrunning/biznodemainnode
python run_dashboard.py > logs/dashboard.log 2>&1 &
```

**Verify:**
```bash
curl http://localhost:7777/api/health
```

---

### 5. Telegram Bot Not Running

**Symptom:** @biznode_bot does not respond to any messages on Telegram.

**Check:** Look for a running Python process:
```bash
tasklist | findstr python
```

**Fix:**

The bot normally runs inside Docker. To run it locally, the `.env` file must be loaded into the environment first because the bot reads `BOT_TOKEN`, `OLLAMA_URL`, etc. from environment variables.

Create a file `restart/start_bot.py` (already provided below) or run directly:

```bash
cd C:\nodesrunning\biznodemainnode
python restart/start_bot.py
```

**In background (Git Bash):**
```bash
cd /c/nodesrunning/biznodemainnode
python restart/start_bot.py > logs/bot_local.log 2>&1 &
```

**Verify:**
```bash
tail -10 logs/bot_local.log
```
Look for:
```
[INFO] biznode.bot: BizNode bot starting...
[INFO] telegram.ext.Application: Application started
```

---

### 6. Bot Conflict Error

**Symptom:** Bot log shows:
```
telegram.error.Conflict: Conflict: terminated by other getUpdates request;
make sure that only one bot instance is running
```

**Cause:** Two processes are polling the same bot token. This happens when:
- A Docker container is still running the bot AND you started it locally
- A previous local bot process was not killed before starting a new one

**Fix:**
1. Kill ALL Python processes running the bot:
   ```bash
   # Find the bot process
   powershell -Command "Get-CimInstance Win32_Process -Filter \"name='python.exe'\" | Select-Object ProcessId, CommandLine | Format-List"

   # Kill the old one by PID
   taskkill /PID <old_pid> /F
   ```
2. Also check Docker:
   ```bash
   docker ps | grep bot
   docker stop biznode-bot
   ```
3. Wait 5 seconds, then start the bot again
4. Only ONE instance of the bot can run at a time per token

---

### 7. .env Not Loaded

**Symptom:** Bot starts but can't connect to Telegram (empty token). LLM service uses wrong model. SMTP notifications fail.

**Cause:** The project does not use `python-dotenv`. Environment variables must be loaded manually before running services outside Docker.

**Fix:** The `restart/start_bot.py` script handles this automatically. For other scripts, load `.env` at the top:

```python
import os
with open('.env', 'r', encoding='utf-8') as f:
    for line in f:
        line = line.strip()
        if not line or line.startswith('#') or '=' not in line:
            continue
        k, _, v = line.partition('=')
        k, v = k.strip(), v.strip().strip('"').strip("'")
        if k:
            os.environ[k] = v
```

---

## Full Restart Sequence

When everything is down, start services in this order:

```
1. Ollama        (LLM must be up before bot starts)
2. Qdrant        (Vector DB must be up before bot starts)
3. Dashboard     (API server must be up before bot sends notifications)
4. Telegram Bot  (depends on all of the above)
```

### Quick Start (Git Bash)

```bash
cd /c/nodesrunning/biznodemainnode

# 1. Ollama — usually auto-starts, but verify
curl -s http://localhost:11434/api/tags > /dev/null && echo "Ollama: OK" || echo "Ollama: DOWN — run 'ollama serve'"

# 2. Qdrant
curl -s http://localhost:6333/collections > /dev/null && echo "Qdrant: OK" || (
  echo "Starting Qdrant..."
  QDRANT__STORAGE__STORAGE_PATH="C:/nodesrunning/biznodemainnode/memory/qdrant/storage" \
  QDRANT__SERVICE__HTTP_PORT=6333 \
  /c/qdrant/qdrant.exe &
  sleep 3
)

# 3. Dashboard
curl -s http://localhost:7777/api/health > /dev/null && echo "Dashboard: OK" || (
  echo "Starting Dashboard..."
  python run_dashboard.py > logs/dashboard.log 2>&1 &
  sleep 3
)

# 4. Bot
python restart/start_bot.py > logs/bot_local.log 2>&1 &
sleep 5
tail -5 logs/bot_local.log
```

### Quick Start (Windows CMD)

```cmd
cd C:\nodesrunning\biznodemainnode

REM 1. Verify Ollama
curl http://localhost:11434/api/tags

REM 2. Start Qdrant (if needed)
set QDRANT__STORAGE__STORAGE_PATH=C:\nodesrunning\biznodemainnode\memory\qdrant\storage
set QDRANT__SERVICE__HTTP_PORT=6333
start "" C:\qdrant\qdrant.exe

REM 3. Start Dashboard (if needed)
start "" python run_dashboard.py

REM 4. Start Bot
start "" python restart\start_bot.py
```

---

## Health Check

Run this to verify all services:

```bash
echo "=== BizNode Health Check ==="
curl -s http://localhost:11434/api/tags > /dev/null 2>&1 && echo "Ollama:    OK" || echo "Ollama:    DOWN"
curl -s http://localhost:6333/collections > /dev/null 2>&1 && echo "Qdrant:    OK" || echo "Qdrant:    DOWN"
curl -s http://localhost:7777/ > /dev/null 2>&1 && echo "Dashboard: OK" || echo "Dashboard: DOWN"
tasklist 2>/dev/null | grep -q python && echo "Bot:       RUNNING (check logs)" || echo "Bot:       DOWN"
```

---

## Log Files

| Log | Location |
|-----|----------|
| Bot | `logs/bot_local.log` |
| Dashboard | `logs/dashboard.log` |
| Qdrant | Terminal output (or redirect to `logs/qdrant.log`) |
| Ollama | `%LOCALAPPDATA%\Ollama\logs\server.log` |

---

## Port Conflicts

If a port is already in use:

```bash
# Find what's using a port (e.g., 7777)
netstat -ano | findstr :7777

# Kill the process by PID
taskkill /PID <pid> /F
```

---

## Bugs Found and Fixed (2026-03-07)

### PostgreSQL INSERT silently lost — LASTVAL() transaction abort

**Root cause:** `memory/db_adapter.py` `CompatCursor.execute()` called `SELECT LASTVAL()` after every INSERT on PostgreSQL to cache `lastrowid`. For tables with TEXT primary keys (like `video_tasks`), no sequence exists, so `LASTVAL()` raises an error. In PostgreSQL, **any error aborts the entire transaction**, meaning the INSERT is silently rolled back even though `conn.commit()` doesn't raise an error.

**Symptom:** Video tasks were created (`/videotask` returned a task ID) but never persisted. `/videostatus` showed "No video tasks found."

**Fix:** Wrapped the `LASTVAL()` call in a `SAVEPOINT` so that its failure doesn't abort the outer transaction. See `memory/db_adapter.py` lines around the `_lastval_check` savepoint.

### db_adapter.py env vars frozen at import time

**Root cause:** `DB_TYPE`, `DB_HOST`, etc. were read once at module import time. If `db_adapter` was imported before `.env` was loaded into `os.environ`, it would default to `sqlite` forever.

**Fix:** Added `_refresh_config()` function called at the top of `get_connection()` that re-reads all DB env vars from `os.environ`.

### videoautomation/models.py used fragile _load_db() pattern

**Root cause:** `models.py` loaded `memory/database.py` as a fresh module via `importlib.util.spec_from_file_location()` each time, which could resolve `db_adapter` imports inconsistently.

**Fix:** Replaced `_load_db()` with direct `from memory.db_adapter import get_connection` after ensuring project root is on `sys.path`.

### BOT_SECRET read at module import time (ui/server.py)

**Root cause:** `_BOT_SECRET = os.getenv("BOT_SECRET", "")` was executed at module level in `ui/server.py` (line 347). Since `run_dashboard.py` doesn't load `.env` before importing `ui.server`, the variable was always empty, causing all `X-Bot-Secret` authenticated requests to fail.

**Symptom:** Bot's internal API calls to dashboard returned 401 "Not authenticated" even with the correct `X-Bot-Secret` header. Affected video task creation and status queries from the Telegram bot.

**Fix:** Replaced module-level `_BOT_SECRET` with `_get_bot_secret()` function that reads `os.getenv()` at call time, after `startup_event()` has loaded `.env`.

### LLM script generation silently falling back to generic templates

**Root cause:** `videoautomation/script_generator.py` used `importlib.util` to load the LLM service, which was fragile and inconsistent. Combined with qwen3.5's `<think>` mode consuming time and short timeout (120s), the LLM often returned empty responses, triggering the 3-scene fallback.

**Fix:** Direct Ollama HTTP calls with `/no_think` prefix for qwen3.5, 300s timeout, 3-attempt retry, `<think>` tag stripping, and flexible JSON key normalization for varying LLM output formats.

---

## Key Environment Variables

These are read from `.env` and must be present for the bot to work:

| Variable | Used By |
|----------|---------|
| `TELEGRAM_BOT_TOKEN` | Bot — Telegram API authentication |
| `LLM_MODEL` | Bot, Video — which Ollama model to use |
| `EMBEDDING_MODEL` | Bot — Qdrant embedding model |
| `OWNER_TELEGRAM_ID` | Bot — restricts owner commands |
| `OWNER_EMAIL` | Video, Digest — email notification recipient |
| `SMTP_HOST/PORT/USER/PASSWORD` | Email sending |
| `DB_TYPE/HOST/PORT/NAME/USER/PASSWORD` | Database connection (MySQL) |
| `BOT_SECRET` | Dashboard API authentication |
