# o‑Byte QA – Testprotokoll‑Tool (Full README) **Stand:** 2025-09-04 **Stack:** PHP 8.3 ( Apache ), JS (Vanilla), MariaDB, Docker & Compose, Portainer Dieses Repository enthält ein vollwertiges QA‑Tool mit Login (OIDC), GitLab‑Template‑Loader, DocBee‑Posting, PDF‑Erzeugung im Browser und persistenter Speicherung (DB + PDF‑Ablage). Diese README basiert ausschließlich auf dem mitgelieferten Projektstand. --- ## Inhaltsverzeichnis 1. [Überblick](#überblick) 2. [Architektur & Verzeichnisstruktur](#architektur--verzeichnisstruktur) 3. [Funktionen](#funktionen) 4. [UI‑Bedienung (Kurzüberblick)](#ui-bedienung-kurzüberblick) 5. [Datenmodell (DB)](#datenmodell-db) 6. [API‑Endpunkte](#api-endpunkte) 7. [Konfiguration per Umgebungsvariablen (.env)](#konfiguration-per-umgebungsvariablen-env) 8. [Lokale Entwicklung](#lokale-entwicklung) 9. [Deployment mit Docker Compose](#deployment-mit-docker-compose) 10. [Deployment mit Portainer (Stack)](#deployment-mit-portainer-stack) 11. [GitLab‑Vorlagen](#gitlab-vorlagen) 12. [DocBee‑Integration](#docbee-integration) 13. [PDF‑Export](#pdf-export) 14. [Troubleshooting](#troubleshooting) 15. [Sicherheitshinweise](#sicherheitshinweise) 16. [Lizenz / Nutzung](#lizenz--nutzung) --- ## Überblick - **Ziel:** Manuelle QA‑Testläufe effizient vorbereiten, durchführen und revisionssicher exportieren. - **Workflow:** Vorlage laden → Metadaten eintragen (inkl. **OLM‑Nummer**) → Schritte bearbeiten (Gruppen, Status, Evidenzen) → **Exportieren (DocBee, DB, PDF)**. - **Login:** OpenID Connect (konfigurierbar), optional **bypassbar** über `AUTH_DISABLED=true` für lokale Tests. - **Persistenz:** Reports (Metadaten & Steps) in MariaDB, PDFs serverseitig abgelegt. - **Integrationen:** GitLab (YAML‑Vorlagen), DocBee (Login + Notiz‑Erzeugung via REST). --- ## Architektur & Verzeichnisstruktur ``` o-byte-qa-tool/ ├─ compose/ │ ├─ Dockerfile # PHP 8.3 + Apache, Composer │ └─ docker-compose.yml # app, mariadb, schema-loader, phpmyadmin, fix-pdf-perms └─ htdocs/ # Webroot ├─ index.php # App-Entry, Token-Bootstrap für DocBee, UI ├─ app.js # UI-Logik, Exporte, DocBee-Push, GitLab-Loader ├─ style.css # Styles ├─ api/ │ ├─ export.php # Report+Steps in DB speichern, PDF entgegennehmen │ ├─ echo.php # einfache Echo-Route (Debug) │ └─ health.php # Health‑Check (DB/PDF‑Pfad) ├─ config/config.php # ENV‑Konfiguration (OIDC, DocBee, DB, APP_BASE_URL, …) ├─ login.php # OIDC‑Start ├─ callback.php # OIDC‑Callback, Session‑Bootstrap ├─ logout.php # Session reset (OLM beibehalten) ├─ logo.png / logo_light.png ├─ favicon.ico ├─ vendor/ # Composer (z. B. jumbojett/openid-connect-php, phpseclib, …) └─ oidc/ # phpseclib Assets (lokal eingebunden) ``` --- ## Funktionen ### Vorlagen & Schritte - **Vorlagen laden**: YAML/JSON (lokal per Datei **oder** aus **GitLab**‑Repo/Pfad/Ref). - **Gruppen**: Gruppenzeilen, ein-/ausklappbar; Schritte via Drag‑Handle verschiebbar (innerhalb und zwischen Gruppen). - **Automatische Neu‑Nummerierung** der Steps bei Änderungen/Verschieben. - **Pflichtschritte** (📌) werden geprüft – Export blockiert, wenn offen. - **Gruppenstatus setzen** auf *pass/fail/skip/blocked*, inkl. **Warnung** bei Überschreiben bestehender Stati. - **Kommentare & Evidenzen** (Freitext + URL). ### Metadaten - **Module**, **Modul‑Version**, **PBX‑Version**, **Tester** (aus Session), **DocBee‑Ticket‑URL**, **OLM‑Nummer** (`olm_nummer`). ### Exporte - **Exportieren (DocBee, DB, PDF)** per **einem** Button: 1. DocBee‑Notiz erstellen (falls Token vorhanden) → Ticket‑URL ggf. aktualisiert. 2. **PDF** im Browser generieren (jsPDF+AutoTable). 3. **/api/export.php**: JSON (Run) + PDF (multipart) an Server → DB‑Speicherung + PDF‑Ablage. 4. Server sendet `report_id` und `pdf_path` zurück. - **Lauf speichern / laden** als JSON (Zwischenspeichern/Weiterarbeiten). - **Template als YAML exportieren** (inkl. `olm_nummer`, Gruppen & Steps). > Hinweis: Dedizierte Buttons für CSV/MD/PDF wurden in dieser Version **konsolidiert** – CSV/MD‑Funktionen existieren noch im Code, UI‑seitig aber nicht exponiert. --- ## UI‑Bedienung (Kurzüberblick) - **GitLab Vorlage**: Dropdown befüllen (`GitLab: …` Tag zeigt Status), Datei wählen → Vorlage wird geladen. - **Metadaten**: Felder ausfüllen (**OLM‑Nummer** nicht vergessen). - **Steps**: `+ Step` / `+ Gruppe`, per Griff `⋮⋮` ziehen, Status setzen, Kommentare/Evidenzen pflegen. - **Exportieren (DocBee, DB, PDF)**: Startet kompletten Lauf‑Export. Ergebnisdialog zeigt Ticket/PDF‑Pfad/Report‑ID. --- ## Datenmodell (DB) Beim Export werden folgende Tabellen (idempotent) angelegt/aktualisiert: **reports** - `id` BIGINT (PK) - `created_at` TIMESTAMP (Default `CURRENT_TIMESTAMP`) - `module` VARCHAR(255) - `module_version` VARCHAR(100) - `pbx_version` VARCHAR(100) - `olm_nummer` VARCHAR(100) - `tester` VARCHAR(255) - `docbee_url` TEXT - `summary` VARCHAR(255)  → z. B. `12/15 pass, 2 fail, 1 skip` - `pdf_path` TEXT **steps** - `id` BIGINT (PK) - `report_id` BIGINT (FK → reports.id, ON DELETE CASCADE) - `step_index` INT - `step_id` VARCHAR(50) - `title` TEXT - `expected` TEXT - `status` ENUM('pass','fail','skip','na','') - `comment` TEXT - `evidence` TEXT - `group_title` VARCHAR(255) - `group_index` INT Der **schema‑loader** Service in `docker-compose.yml` erstellt die Tabellen automatisch beim ersten Start. --- ## API‑Endpunkte - `GET /api/health.php` - Prüft PDO / MariaDB‑Erreichbarkeit, Schreibrechte des PDF‑Ordners. - `POST /api/export.php` (multipart/form-data) - **Felder:** - `run` – JSON mit Metadaten (`module`, `module_version`, `pbx_version`, `olm_nummer`, `tester`, `docbee_url`, `ts`, `steps`[…]) - `pdf` – erzeugte PDF‑Datei (optional; Export läuft auch ohne PDF durch) - **Antwort:** `{{"ok":true,"report_id":,"pdf_path":"…","summary":"…"}}` - `POST /api/echo.php` - Debug/Echo. --- ## Konfiguration per Umgebungsvariablen (.env) Beispiel **.env** (für Compose/Portainer): ```env # App APP_PORT=8009 APP_BASE_URL=http://localhost:8009 AUTH_DISABLED=false # true = Login-BYPASS (nur lokal verwenden) # OpenID Connect (Login) OIDC_PROVIDER=https://auth.o-byte.com/realms/o-byte.com OIDC_CLIENT=qa-tool OIDC_SECRET= # MariaDB DB_HOST=mariadb DB_PORT=3306 DB_NAME=qa_tool DB_USER=qa DB_PASS=change_me DB_ROOT_PASS=change_me_root # Persistenz PDF_STORAGE_DIR=/var/reports # DocBee DOCBEE_BASEURL=https://obyte.docbee.com DOCBEE_USER=OBYTE/service DOCBEE_PASS= DOCBEE_TIME=1440 # Minuten Token-Gültigkeit # GitLab Templates GITLAB_HOST=https://git.steinert.cc GITLAB_PROJECT_ID=qa/templates # oder numerische ID GITLAB_REF=main GITLAB_PATH=templates GITLAB_TOKEN= # optional (PRIVATE-TOKEN) # Container-User (Dateirechte) APP_UID=0 APP_GID=0 # phpMyAdmin Port (optional) PHPMYADMIN_PORT=8010 ``` > **Wichtig:** Keine Secrets in Repos commiten. Für Produktion Token/Passwörter über Portainer‑UI/Secrets setzen. --- ## Lokale Entwicklung 1. **Composer‑Abhängigkeiten** sind bereits im Repo (`vendor/`). Falls nötig: ```bash cd htdocs && composer install ``` 2. **PHP‑Built‑in** (nur für schnellen Test, ohne DB/PDF‑Ablage): ```bash php -S 127.0.0.1:8009 -t htdocs ``` 3. **Login‑Bypass** lokal aktivieren: ```bash export AUTH_DISABLED=true ``` 4. Browser: `http://127.0.0.1:8009` --- ## Deployment mit Docker Compose Im Ordner `compose/` befindet sich ein funktionsfähiges Setup mit: - **app** (Apache+PHP 8.3), bind‑mountet `htdocs` und nutzt `PDF_STORAGE_DIR` Volume - **mariadb** (11.x) - **schema-loader** (initialisiert Tabellen) - **phpmyadmin** (optional) - **fix-pdf-perms** (setzt 0777 auf PDF‑Volume) **Starten:** ```bash cd compose cp ../.env .env # eigene Werte setzen docker compose up -d ``` **Zugriff:** `http://:${APP_PORT:-8009}` **phpMyAdmin:** `http://:${PHPMYADMIN_PORT:-8010}` --- ## Deployment mit Portainer (Stack) 1. **Stack → Add Stack** 2. **Environment Vars** nach obiger `.env` setzen (oder Datei hochladen). 3. **Compose** verwenden (aus `compose/docker-compose.yml`), z. B.: ```yaml version: "3.8" services: app: image: thecodingmachine/php:8.3-v4-apache user: "${APP_UID:-0}:${APP_GID:-0}" ports: - "${APP_PORT:-8009}:80" environment: PHP_EXTENSION_PDO_MYSQL: "1" APP_BASE_URL: ${APP_BASE_URL} AUTH_DISABLED: ${AUTH_DISABLED} DB_HOST: ${DB_HOST} DB_PORT: ${DB_PORT} DB_NAME: ${DB_NAME} DB_USER: ${DB_USER} DB_PASS: ${DB_PASS} PDF_STORAGE_DIR: ${PDF_STORAGE_DIR} OIDC_PROVIDER: ${OIDC_PROVIDER} OIDC_CLIENT: ${OIDC_CLIENT} OIDC_SECRET: ${OIDC_SECRET} DOCBEE_BASEURL: ${DOCBEE_BASEURL} DOCBEE_USER: ${DOCBEE_USER} DOCBEE_PASS: ${DOCBEE_PASS} DOCBEE_TIME: ${DOCBEE_TIME} GITLAB_HOST: ${GITLAB_HOST} GITLAB_PROJECT_ID: ${GITLAB_PROJECT_ID} GITLAB_REF: ${GITLAB_REF} GITLAB_PATH: ${GITLAB_PATH} GITLAB_TOKEN: ${GITLAB_TOKEN} volumes: - ${APP_HTDOCS_HOST:-/opt/qa-tool/htdocs}:/var/www/html - pdf_storage:/var/reports depends_on: mariadb: condition: service_healthy fix-pdf-perms: condition: service_completed_successfully restart: unless-stopped mariadb: image: mariadb:11 environment: MYSQL_DATABASE: ${DB_NAME} MYSQL_USER: ${DB_USER} MYSQL_PASSWORD: ${DB_PASS} MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS} volumes: - db_data:/var/lib/mysql healthcheck: test: ["CMD", "mariadb-admin", "ping", "-h", "127.0.0.1", "-p${DB_PASS}"] interval: 10s timeout: 5s retries: 30 start_period: 20s restart: unless-stopped schema-loader: image: mariadb:11 depends_on: mariadb: condition: service_healthy environment: DB_HOST: ${DB_HOST} DB_PORT: ${DB_PORT} DB_NAME: ${DB_NAME} DB_USER: ${DB_USER} DB_PASS: ${DB_PASS} command: > sh -lc " echo 'Waiting for DB…'; sleep 3; mysql -h $DB_HOST -P $DB_PORT -u$DB_USER -p$DB_PASS $DB_NAME </dev/null || true chown -R 0:0 /target 2>/dev/null || true exit 0 ' restart: "no" phpmyadmin: image: phpmyadmin:5 ports: - "${PHPMYADMIN_PORT:-8010}:80" environment: PMA_HOST: mariadb PMA_USER: ${DB_USER} PMA_PASSWORD: ${DB_PASS} depends_on: mariadb: condition: service_healthy restart: unless-stopped volumes: db_data: pdf_storage: ``` 4. **Deploy Stack** → öffnen: `http://:${APP_PORT}`. --- ## GitLab‑Vorlagen - Konfiguration via ENV (`GITLAB_HOST`, `GITLAB_PROJECT_ID`, `GITLAB_REF`, `GITLAB_PATH`, `GITLAB_TOKEN`). - UI lädt per GitLab API die Liste der YAML‑Dateien aus `GITLAB_PATH` (nur `.yaml`/`.yml`). - Parser akzeptiert **YAML** und **JSON** (Fallback). --- ## DocBee‑Integration - Beim Laden von `index.php` wird via `DOCBEE_BASEURL/restApi/login` ein Token geholt und **clientseitig** als `window.DOCBEE_TOKEN` bereitgestellt. - Exportablauf: 1. **postToDocBee** erstellt eine Notiz im angegebenen **Ticket** (aus `DocBee Ticket‑URL`). 2. Bei Erfolg wird die URL im Lauf aktualisiert. 3. Danach erfolgt Server‑Export (DB + optional PDF). **Erforderliche ENV:** `DOCBEE_BASEURL`, `DOCBEE_USER`, `DOCBEE_PASS`, `DOCBEE_TIME` (Minuten). --- ## PDF‑Export - Erzeugung **im Browser** via **jsPDF** + **AutoTable** (CDN‑Fallbacks vorhanden). - **Logo** `logo_light.png` wird proportional (max 26×12 mm) **rechtsbündig** im Kopf platziert. - Fallback: Falls Libraries fehlen, wird ein Text‑PDF erzeugt. - Server speichert PDFs in `PDF_STORAGE_DIR` (Default `/var/reports`). --- ## YAML‑Vorlage (Beispiel inkl. OLM) ```yaml name: "Modul XYZ – Basis‑Tests" module: "Modul XYZ" module_version: "1.2.3" pbx_version: "8.1" olm_nummer: "OLM-12345" steps: - type: "group" title: "Telefonie Basis" - type: "step" id: "s1" title: "Anruf initiieren" expected: "Ruf wird erfolgreich aufgebaut" required: true - type: "step" id: "s2" title: "Rufumleitung" expected: "Ruf wird korrekt umgeleitet" required: false ``` --- ## Troubleshooting - **Login‑Loop / 401:** OIDC‑Konfiguration prüfen (`OIDC_PROVIDER`, Redirect‑URL `/callback.php`). Lokal ggf. `AUTH_DISABLED=true`. - **DocBee 401/403:** `DOCBEE_USER/DOCBEE_PASS/DOCBEE_BASEURL/DOCBEE_TIME` prüfen. - **DB‑Fehler (PDO not loaded):** Image/Extension prüfen (`PHP_EXTENSION_PDO_MYSQL=1` gesetzt? Compose). - **Keine Schreibrechte PDF:** Volume/`fix-pdf-perms` prüfen; `PDF_STORAGE_DIR` existiert/schreibbar? `/api/health.php` ansehen. - **GitLab‑Liste leer:** Pfad/Ref/Token prüfen; nur `.yaml/.yml` werden angezeigt. - **Export blockiert:** Pflichtschritte haben keinen Status (📌). --- ## Sicherheitshinweise - **AUTH_DISABLED** ausschließlich in Dev/Stage verwenden. - DocBee‑Token wird **clientseitig** verwendet – nur in internen Netzen nutzen oder alternative Server‑Proxy‑Variante vorsehen. - Secrets per Portainer‑Secrets/ENV setzen, nicht im Repo. - DB‑Backups/Retention für `reports`/`steps` einplanen; PDF‑Ablage regelmäßig bereinigen/archivieren. --- ## Lizenz / Nutzung Interne Nutzung innerhalb o‑Byte / Kundenprojekten. Anpassungen willkommen.