Lesson #1478

← Back to Knowledge Board
flyspray-integration-2026-05-12
ID
1478
Author
ai
Agent
agent-claude
Reviewed
✓ Yes
Source authority
75 / 100
Source
Flyspray bug-tracker für bug.joelduss.xyz — Docker-Stack live, REST-API-plugin + rag-sync + triage-classifier in Phasen 2-6
Source issue
Created at
2026-05-12T12:53:28.373970+00:00
Valid until
Deprecated at
Supersedes
Obsidian path
/root/.claude/projects/-nvmetank1-projects/memory/project_flyspray_integration.md
Obsidian hash
f4272b7375235510c84ad4b5d0f4d9df
Tags
claude-memory,project

Content

**Started 2026-05-12** per user-direktive: bug.joelduss.xyz hostet Flyspray, REST-API custom-Plugin, rag-stack-Sync, Triage real-bug vs user-error, autonomous agent-pickup.

## EPIC + Phases (ubuadmin/rag-stack)

- **#117** EPIC: Flyspray-Integration für bug.joelduss.xyz
- **#118** Phase 1: Docker-Setup ✅ **DONE** (Container live, Caddy proxying, installer pending)
- **#119** Phase 2: REST-API Plugin (PHP, in /persistent/flyspray/plugins/rest-api/)
- **#120** Phase 3: Project-Sync mit /nvmetank1/projects/*
- **#121** Phase 4: Caddy-vhost umstellen ✅ **DONE** (https://bug.joelduss.xyz aktiv)
- **#122** Phase 5: RAG-Sync + Triage-Classifier (claude --print: real-bug/user-error/unclear)
- **#123** Phase 6: Gitea-Bridge (real-bug → Gitea-Issue → agent dispatches)

## Container-Stack

| Container | Image | Port | Volume |
|---|---|---|---|
| flyspray | `flyspray-flyspray` (custom-built, php:8.2-apache + composer) | 127.0.0.1:8820 | /persistent/flyspray/{attachments,avatars,plugins} |
| flyspray-db | mariadb:11 | (internal) | /persistent/flyspray/db |

Stack-File: `/nvmetank1/docker/flyspray/docker-compose.yml` + `Dockerfile`
DB-Creds: `/persistent/flyspray/db_password.txt` (root-only, 600)

## Caddy

```caddy
bug.joelduss.xyz {
    encode gzip
    reverse_proxy 127.0.0.1:8820
}
```

LE-Cert auto-issued via tls-alpn-01. DNS GoDaddy → 51.154.18.97 (public) + pi-hole → 192.168.1.216 (LAN).

## Open: Installer-Wizard

✅ Installer DONE 2026-05-12 14:57 via auto-POST. (Diese Sektion war: Installer MUSS manuell oder via curl-POST gemacht werden:
- URL: https://bug.joelduss.xyz/setup.php
- DB-Host: `db`
- DB-Database: `flyspray`
- DB-User: `flyspray`
- DB-Password: `cat /persistent/flyspray/db_password.txt` (root)
- Admin-User: nach Wahl

Danach kann Phase 2 (REST-API-Plugin) starten.

## Triage-Logic (Phase 5)

```
new Flyspray-Task
   │
   ▼
rag-stack /api/v1/flyspray/webhook
   │
   ▼
Triage-Classifier (claude --print mit triage-prompt)
   │
   ├── "user-error" → poste hilfreiche Antwort + close task
   ├── "real-bug"   → erstelle Gitea-Issue + label agent-X + dispatch
   └── "unclear"    → label needs-review-human, wait
```

## Project-Mapping (Phase 3)

Jedes /nvmetank1/projects/<name> bekommt ein Flyspray-Project. Tag-Konvention pro Project mit Subsystem-Tags (yoga-frontend, yoga-deploy, etc.).

## Was als nächstes manuell zu tun ist (vor Phase 2)

1. Installer öffnen + ausfüllen
2. Admin-API-Token in Flyspray erstellen (für rag-stack zum POST)
3. Token in `/etc/flyspray-api.token` ablegen (root:root 600)
4. Phase 2 (#119) dispatchen — Plugin wird im laufenden Container in /var/www/html/plugins/rest-api/ entwickelt

## CSS-Fix für Caddy-reverse-proxy (2026-05-12)

**Symptom:** CSS lädt nicht, browser blocks mixed-content (Flyspray generierte http://... URLs trotz HTTPS).

**Root cause:** PHP `$_SERVER['HTTPS']` nicht gesetzt + `SERVER_PORT=80` (von Apache internal).

**Fix:** PHP `auto_prepend_file` der die Server-Vars patcht basierend auf X-Forwarded-Proto:
```php
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
    $_SERVER['SERVER_PORT'] = 443;
}
```

Files persistent in:
- `/persistent/flyspray/proxy-fix.php` → mounted `/var/www/html/proxy-fix.php`
- `/persistent/flyspray/apache-conf/php-auto-prepend.conf` → mounted `/etc/apache2/conf-enabled/php-auto-prepend.conf`


## Login-Credentials (2026-05-12)

Beide haben Admin-Rechte:

| Username | Password-File (root:600) |
|---|---|
| `joel` | /persistent/flyspray/admin_password.txt |
| `ubuadmin` | /persistent/flyspray/ubuadmin_password.txt |

joel war original installer-Admin (user_id=1, email war initial = user_name, jetzt korrigiert).
ubuadmin per direkt-INSERT als zusätzlicher Admin angelegt (user_id=2, group_id=1).

## Phase 3 — DONE 2026-05-12

`/usr/local/bin/flyspray-project-sync` läuft via systemd-timer (daily 04:00).
Mapped 15 Projekte aus /nvmetank1/projects/* (skip docs, ruflo-reference, .*).

flyspray_projects: 16 (1 Default + 15 synced).

## Lessons-Learned 2026-05-12 (gefundene Bugs + Fixes)

1. **`syntax_plugin='text'` ist INVALID** in Flyspray-conf
   - Symptom: "Unsupported output plugin text! Couldn't call text_TextFormatter::render()"
   - Fix: in flyspray.conf.php zu `none` (oder `dokuwiki`/`html`) ändern.
   - **Lesson:** Installer-Dropdown gibt nur diese 3 Werte; Free-text-input würde Default lassen sollen.

2. **`sed -i` auf bind-mounted Files = KAPUTT**
   - Symptom: Container-Sicht der Datei wird 0 bytes (sed rename trennt vom mount-inode).
   - Fix: Editieren direkt im Container ODER full-write via `cat > host-file` (kein rename).
   - **Lesson:** Bei bind-mounted Single-File-mounts NIE sed -i nutzen.

3. **DB-INSERT'd projects brauchen Default-Categories**
   - Symptom: "Warning: Trying to access array offset on value of type bool in class.project.php:258"
   - Fix: `INSERT INTO flyspray_list_category (project_id, 'root', 0, 1, 4)` + `(... 'Backend / Core', 1, 2, 3)` pro Projekt.
   - **Lesson:** Flyspray's Installer macht das pro Projekt; mein DB-bypass auch.

4. **`others_view=0` macht Projekt unsichtbar** für Non-Project-Members.
   - Default neuer Projekte muss `1` sein.

5. **`default_entry='all'`** ist INVALID — valid sind `index` (Tasklist), `newtask`, `newmultitasks`, etc.

6. **Setup-dir entfernen lockt aus** wenn `$conf` empty wird
   - Symptom: 302 → /setup/index.php → 404 endlos
   - Root cause war hier `sed -i` (s.o.). Setup-dir-Removal an sich ist OK wenn config valid.

Sync-Skript `flyspray-project-sync.py` enthält alle Fixes — neue Projekte bekommen sofort:
- others_view=1
- default_entry='index'  
- Default 2 Categories (root + Backend/Core)