#!/usr/bin/env php true, CURLOPT_HTTPHEADER => $headers, CURLOPT_TIMEOUT => 20, ]); if ($method === 'PATCH') { curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH'); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); } elseif ($method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); } $raw = curl_exec($ch); $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return ['http_code' => $code, 'body' => json_decode($raw ?: '{}', true) ?: []]; } function commentIssue(string $token, string $repo, int $num, string $body, bool $dryRun): bool { if ($dryRun) { echo "[dry-run] comment #$num\n"; return true; } $r = ghApi($token, 'POST', "https://api.github.com/repos/$repo/issues/$num/comments", ['body' => $body]); if ($r['http_code'] >= 200 && $r['http_code'] < 300) { echo "OK comment #$num\n"; return true; } fwrite(STDERR, "FAIL comment #$num HTTP {$r['http_code']}: " . json_encode($r['body']) . "\n"); return false; } function closeIssue(string $token, string $repo, int $num, bool $dryRun): bool { if ($dryRun) { echo "[dry-run] close #$num\n"; return true; } $r = ghApi($token, 'PATCH', "https://api.github.com/repos/$repo/issues/$num", ['state' => 'closed']); if ($r['http_code'] >= 200 && $r['http_code'] < 300) { echo "OK close #$num\n"; return true; } fwrite(STDERR, "FAIL close #$num HTTP {$r['http_code']}: " . json_encode($r['body']) . "\n"); return false; } // ── #200: reply only, keep OPEN ───────────────────────────────────────────── $body200 = <<<'MD' Ciao Marco, grazie per la segnalazione dettagliata. Il messaggio **«Impossibile contattare il server»** compare quando il browser **non riesce a completare** la richiesta a `api/index.php?action=health_check`. Quindi phpinfo funziona, ma **l'endpoint API no** (404, redirect, TLS, path sbagliato, ecc.). ### Check rapidi (dalla macchina dove apri il browser) ```bash curl -sv "https://TUO-DOMINIO/api/index.php?action=ping" curl -sv "https://TUO-DOMINIO/api/index.php?action=health_check" ``` Se uno dei due fallisce: DevTools → **Network** → URL esatto e **status code** della richiesta `health_check`. ### Cause frequenti con Traefik + Docker Swarm 1. **Routing incompleto** — Traefik deve inoltrare `/` **e** `/api/*`, non solo la homepage. 2. **Redirect HTTPS** — dietro Traefik serve `X-Forwarded-Proto: https`, oppure disabilitare il redirect in `.htaccess`. Nelle immagini recenti il Dockerfile imposta `SetEnvIf X-Forwarded-Proto "https" HTTPS=on`. 3. **Sottopath** — EverShelf usa URL relativi (`api/index.php`); se l'app è su `/sottocartella/`, l'URL pubblico deve essere coerente. 4. **Volume `data/`** — al primo avvio può essere quasi vuoto; assicurati permessi scrivibili: ```bash docker exec -it CONTAINER chown -R www-data:www-data /var/www/html/data docker exec -it CONTAINER chmod -R 775 /var/www/html/data ``` 5. **`API_TOKEN` in `.env`** — se impostato, compare un prompt token (non «server non raggiungibile»). ### Per il passo successivo Puoi condividere: - URL pubblico esatto (con path) - Output dei due `curl` sopra - Screenshot Network tab su `health_check` - Labels Traefik del servizio (router + middlewares) Resta aperta finché non confermi che `ping`/`health_check` rispondono — poi chiudiamo insieme. MD; commentIssue($token, $repo, 200, $body200, $dryRun); // ── Resolved auto-report bugs ─────────────────────────────────────────────── $bugs = [ 198 => "Risolto in develop: `PRAGMA busy_timeout` portato a 10s e `dbWithRetry()` su `updateInventory` per ritentare su SQLITE_BUSY quando cron smart-shopping e PWA scrivono in parallelo.", 199 => "Duplicato di #198 — stesso evento (`inventory_update` → database locked). Fix: retry + busy_timeout aumentato.", 196 => "Risolto in v1.7.38+: `saveProduct` intercetta `UNIQUE constraint failed: products.barcode`, fa merge sul prodotto esistente o risponde 409 JSON (`barcode_already_used`) invece di HTTP 500.", 197 => "Conseguenza lato PWA del crash PHP #196 — risolto con gestione barcode duplicato in `saveProduct`.", 195 => "Risolto: `EverLog::request()` ora riceve sempre stringhe — `\$method = (string)(\$_SERVER['REQUEST_METHOD'] ?? 'GET')` (fix CLI/cron che passavano null).", 193 => "Stesso root cause di #195 (fatal TypeError su `EverLog::request` con method null da CLI). Fix già in develop.", 194 => "Risolto: `_applySpesaScanUI` usava `currentPage` (inesistente) → corretto in `_currentPageId`.", 192 => "Risolto: in `renderShoppingItems` la variabile `enriched` veniva referenziata prima della dichiarazione (TDZ). Ora `enrichedRaw` → `_dedupeShoppingByGeneric` → `enriched`.", 191 => "Risolto: in `_runStartupCheck` `setProgress` è dichiarata prima delle chiamate e `barEl` inizializzato prima dell'uso (niente più TDZ).", 134 => "Segnalazione auto-report su volume Docker non scrivibile. Mitigazioni: `_ensureDataDir()`, `_ensureDbWritable()`, Dockerfile `chown www-data`. Su Swarm: `chown -R www-data:www-data data` al primo boot.", 184 => "Correlato a #134: SQLite readonly quando `data/` o `evershelf.db` non sono scrivibili. Fix operativo + chmod WAL/SHM sidecar in `_ensureDbWritable()`.", ]; foreach ($bugs as $num => $msg) { commentIssue($token, $repo, $num, $msg . "\n\n_Chiuso dopo triage — fix in develop._", $dryRun); closeIssue($token, $repo, $num, $dryRun); } // ── Feature / enhancement backlog (close with acknowledgment) ─────────────── $features = [122, 121, 120, 119, 116, 115, 114, 106, 105, 104, 103, 102, 101, 97, 93, 81, 80, 79, 69, 67, 65]; $featMsg = <<<'MD' Grazie per la proposta — è nel **backlog** del progetto. Chiudiamo questa issue per tenere il tracker focalizzato sui bug attivi; la funzionalità resta nel radar per release future. **Riapri pure** quando vuoi lavorarci o seguirne lo sviluppo. MD; foreach ($features as $num) { commentIssue($token, $repo, $num, $featMsg, $dryRun); closeIssue($token, $repo, $num, $dryRun); } echo "Done.\n";