AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
翻译准备中
制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Piattaforma containerizzata (PHP/Apache + UI) per migliorare il flusso di lavoro degli enti che usano GovPay come soluzione PagoPA.
Include:
Repository: https://github.com/Comune-di-Montesilvano/GovPay-Interaction-Layer.git
License: European Union Public Licence v1.2 (EUPL-1.2)
Backoffice (Gestione operativa & Impostazioni)
Frontoffice (Portale pagamenti cittadino)
L'ambiente di deploy predefinito e consigliato è uno Stack Portainer.
Portainer semplifica la gestione del ciclo di vita dello stack (deploy, aggiornamenti, rollback, log, variabili d'ambiente) senza richiedere accesso SSH diretto al server.
| Scenario | Strumento | Note |
|---|---|---|
| Produzione | Portainer Stack (Podman rootless) | Raccomandato — vedi Setup produzione |
| Sviluppo locale | Docker Compose CLI | docker compose up -d --build |
| CI/CD | GitHub Actions | Build + test automatici — vedi .github/workflows/ |
[!NOTE] In Portainer le variabili d'ambiente dello stack si inseriscono direttamente nell'editor dello Stack (sezione Environment variables), senza necessità di copiare il file
.envsul server.
[!NOTE] Le immagini Docker sono già pubblicate su GHCR. Non è necessario clonare il repository né avere Git installato per un deploy di produzione.
docker compose (oppure Portainer con Podman rootless — ambiente consigliato)8443 (backoffice), 8444 (frontoffice)docker-compose.ymlcurl -O https://raw.githubusercontent.com/Comune-di-Montesilvano/GovPay-Interaction-Layer/main/docker-compose.yml
In Portainer: usa Stacks → Add stack → Repository puntando al repository — non serve scaricare nulla manualmente. Vedi Setup produzione.
Scarica il file d'esempio come riferimento:
curl -O https://raw.githubusercontent.com/Comune-di-Montesilvano/GovPay-Interaction-Layer/main/.env.example
cp .env.example .env
Il file contiene già tutti i valori di default preimpostati. Modifica solo le password e le chiavi crittografiche (indicate dai commenti). Tutto il resto — URL pubblici, integrazioni GovPay/pagoPA, branding — si configura dopo il primo avvio dal Backoffice → Impostazioni.
[!NOTE] In Portainer: non serve il file
.env. Inserisci le variabili direttamente in Stacks → Editor → Environment variables, usando.env.examplecome riferimento.
# scarica le immagini pubblicate su GHCR e avvia
docker compose pull && docker compose up -d
Vedi Rilasci e immagini Docker (GHCR) per i dettagli sulle immagini disponibili.
Sviluppo locale — per lavorare sulle sorgenti è necessario clonare il repository:
git clone https://github.com/Comune-di-Montesilvano/GovPay-Interaction-Layer.git cd GovPay-Interaction-Layer docker compose up -d --buildVedi Workflow di sviluppo per dettagli.
Se non hai certificati TLS personalizzati in ssl/, vengono generati self-signed automaticamente; il browser mostrerà un avviso (normale in locale). Vedi ssl/README.md.
Al primo accesso al backoffice viene avviata automaticamente la procedura di setup guidata per creare il primo superadmin e configurare le impostazioni di base.
In alternativa, è possibile pre-seeding il superadmin via variabili d'ambiente aggiungendo al .env (opzionale):
[email protected]
ADMIN_PASSWORD=password_sicura
Il seed è idempotente: viene eseguito solo se non esiste ancora un superadmin nel DB.
.envIl file .env contiene solo le variabili di bootstrap necessarie all'avvio dei container. Tutto il resto (GovPay, pagoPA, OIDC, branding, App IO, ecc.) si configura dall'interfaccia Backoffice → Impostazioni e viene salvato nel database.
cp .env.example .env
Le variabili obbligatorie prima del primo avvio:
| Variabile | Scopo |
|---|---|
DB_ROOT_PASSWORD, BACKOFFICE_DB_PASSWORD, FRONTOFFICE_DB_PASSWORD | Credenziali database |
APP_ENCRYPTION_KEY | Chiave cifratura segreti in DB — esattamente 32 caratteri (openssl rand -hex 16) |
MASTER_TOKEN | Token Bearer per comunicazione interna backoffice ↔ frontoffice (openssl rand -hex 24) |
FRONTOFFICE_LINK_SIGNING_KEY | Chiave firma link pubblici frontoffice (openssl rand -hex 32) |
Se una di queste variabili manca o è vuota, docker compose si rifiuta di avviare lo stack con un errore che la nomina (es. required variable MASTER_TOKEN is missing a value: MASTER_TOKEN obbligatoria: vedi .env.example).
Opzionale: VERIFY_IMAGES (default false) — vedi Verifica delle immagini prima del deploy.
GIL si integra con i seguenti servizi esterni. Le variabili infrastrutturali/bootstrap stanno nel .env; la configurazione operativa si imposta dal backoffice in tabella settings.
| Integrazione | Scopo | Variabili .env |
|---|---|---|
| GovPay | Gestione pendenze, pagamenti, flussi di rendicontazione, backoffice | GOVPAY_*_URL, AUTHENTICATION_GOVPAY |
| pagoPA Checkout | Avvio pagamenti online tramite redirect al portale pagoPA | PAGOPA_CHECKOUT_EC_BASE_URL, PAGOPA_CHECKOUT_SUBSCRIPTION_KEY |
| pagoPA Biz Events | Recupero on-demand delle ricevute di pagamento dal dettaglio flusso | BIZ_EVENTS_HOST, BIZ_EVENTS_API_KEY |
| App IO | Invio messaggi e avvisi di pagamento ai cittadini (con CTA e dati avviso pagoPA) | APP_IO_FEATURE_LEVEL_TYPE (opz.); chiave API configurabile per tipologia |
| OIDC Esterno | Autenticazione cittadini nel frontoffice tramite proxy OIDC esterno | Backoffice → Impostazioni → Frontoffice — vedi sezione Autenticazione OIDC |
Se AUTHENTICATION_GOVPAY=ssl o sslheader, GIL autentica le chiamate verso GovPay tramite certificato X.509 client.
Il flusso operativo corrente e' UI first:
gil_certs/var/www/certificate/govpay-cert.pem e /var/www/certificate/govpay-key.pemI path runtime attesi sono:
GOVPAY_TLS_CERT=/var/www/certificate/govpay-cert.pem
GOVPAY_TLS_KEY=/var/www/certificate/govpay-key.pem
[!WARNING] In deploy normali i certificati GovPay non vanno gestiti copiando file nel repository: vengono mantenuti nel volume
gil_certse aggiornati dalla UI. La cartellacertificate/nella root ha senso solo come supporto locale/storico, non come flusso operativo principale.
Se la chiave privata e' protetta da password, valorizza anche GOVPAY_TLS_KEY_PASSWORD. In assenza dei file o con certificato scaduto le chiamate a GovPay falliscono a runtime.
Vedi certificate/README.md per dettagli su nomi file accettati e provenienza dei certificati.
Il frontoffice supporta l'autenticazione dei cittadini tramite un proxy OIDC esterno (ad es. pa-sso-proxy o qualsiasi IdP compatibile OpenID Connect).
[!NOTE] L'autenticazione è completamente opzionale. Con tipo impostato su "Nessuno" il frontoffice è ad accesso libero e non richiede login.
Esterno (OIDC Proxy)| Campo | Descrizione |
|---|---|
| OIDC Issuer (Base URL) | URL pubblico del proxy OIDC (es. https://sso.ente.gov.it) |
| Client ID | Client ID registrato sul proxy |
| Client Secret | Client Secret (se richiesto dal proxy) |
| OIDC Logout URL | URL di logout remoto (es. https://sso.ente.gov.it/logout) |
Il frontoffice implementa il flusso Authorization Code + PKCE (standard OAuth 2.0/OIDC):
Cittadino → GET /login
→ redirect a {OIDC_ISSUER}/OIDC/authorization?...
→ login sul proxy
→ redirect a {FRONTOFFICE_URL}/oidc/callback?code=...
→ scambio codice per token (POST /OIDC/token)
→ recupero claims da /OIDC/userinfo
→ sessione frontoffice creata
Nel pannello di amministrazione del tuo proxy OIDC registra il client con:
| Parametro | Valore |
|---|---|
| Redirect URI | {FRONTOFFICE_PUBLIC_BASE_URL}/oidc/callback |
| Allowed Scopes | openid profile email |
| Grant Type | authorization_code |
| PKCE | Richiesto (S256) |
L'URL esatto della Redirect URI è visibile nella card informativa del tab Frontoffice in Impostazioni.
[!IMPORTANT] L'ambiente di produzione ufficiale è Podman rootless gestito tramite Portainer. Podman rootless garantisce isolamento dei container senza privilegi root sul sistema host, riducendo la superficie d'attacco.
Requisiti sul server:
# Podman + plugin docker-compose compatibile
podman --version # >= 4.x
podman-compose --version # oppure docker-compose con DOCKER_HOST=unix:///run/user/<uid>/podman/podman.sock
# Portainer Agent (o Portainer CE/BE già installato)
Deploy tramite Portainer:
https://github.com/Comune-di-Montesilvano/GovPay-Interaction-Layer.gitdocker-compose.ymldocker-compose.override.yml — vedi sotto).env.example come riferimento)Per aggiornare lo stack a una nuova versione: modifica APP_VERSION nelle Environment variables → Update the stack.
[!NOTE] In Podman rootless il DNS resolver della rete interna differisce da Docker. Se necessario imposta la variabile
NGINX_DNS_RESOLVERcon l'IP corretto (podman network inspect <network-name>→ campo gateway).
[!WARNING] In produzione usare esclusivamente named volumes. I bind mount sono vietati.
Il
docker-compose.override.ymlpresente nella root del repository aggiunge bind mount locali (./debug:/var/www/html/public/debug) pensati esclusivamente per il debug in sviluppo locale. In produzione questo file non deve mai essere incluso nello stack.
Il docker-compose.yml ufficiale usa già solo named volumes per tutti i dati persistenti:
| Volume | Contenuto | Persistenza |
|---|---|---|
gil_db_data | Dati MariaDB | ⚠️ Critico — mai eliminare |
gil_ssl_certs | Certificati TLS server | Da popolare prima del primo avvio |
gil_certs | Certificati mTLS GovPay | Da popolare prima del primo avvio |
gil_images | Immagini/loghi personalizzati | Caricati via Backoffice UI |
gil_backups | Backup DB | Prodotti da script di backup |
Backup dei volumi: prima di qualsiasi aggiornamento dello stack esegui un backup dei volumi critici, in particolare gil_db_data.
# Esempio backup volume DB (da adattare all'ambiente Podman)
podman run --rm -v gil_db_data:/data -v $(pwd):/backup alpine \
tar czf /backup/gil_db_data_$(date +%Y%m%d).tar.gz -C /data .
[!CAUTION] Non usare
docker-compose.override.ymlin produzione. In Portainer, assicurati che il campo Compose path punti solo adocker-compose.yml. Se viene accidentalmente incluso l'override, i bind mount montano percorsi inesistenti sul server e causano errori di avvio.
In produzione evita localhost/127.0.0.1.
Imposta nel .env (o nelle Environment variables di Portainer):
BACKOFFICE_PUBLIC_BASE_URL=https://backoffice.ente.gov.it
FRONTOFFICE_PUBLIC_BASE_URL=https://pagamenti.ente.gov.it
Per HTTPS server (browser → applicazione), i certificati validi vanno nel volume gil_ssl_certs:
server.crtserver.keyIn Portainer puoi popolare il volume prima del deploy tramite un container helper o podman volume import. Vedi ssl/README.md per dettagli e troubleshooting permessi.
I certificati in gil_certs sono distinti: servono per l'autenticazione client verso GovPay (mTLS app → GovPay). Vedi certificate/README.md.
Pattern consigliato: reverse proxy pubblico (porta 443) → container interno.
Header da preservare:
Host: <hostname pubblico>
X-Forwarded-Proto: https
X-Forwarded-For: <IP client>
Imposta SSL=off nel .env se il reverse proxy termina TLS e il container riceve HTTP interno.
In produzione non è necessario clonare il repository completo né avere un ambiente Node.js o Composer installato. Usa direttamente le immagini pubblicate su GHCR:
docker compose pull
docker compose up -d
Le immagini sono pubblicate automaticamente a ogni tag vX.Y.Z (tag immagine X.Y.Z, X.Y, latest), firmate e verificabili con scripts/verify-images.sh (vedi Rilasci e immagini Docker), su:
ghcr.io/comune-di-montesilvano/govpay-interaction-layer-backofficeghcr.io/comune-di-montesilvano/govpay-interaction-layer-frontofficeghcr.io/comune-di-montesilvano/govpay-interaction-layer-dbPer un server di produzione sono sufficienti: il docker-compose.yml e le variabili d'ambiente (tramite .env o Portainer).
Ogni release è associata a un tag Git vX.Y.Z, creato su un commit già presente su main (altrimenti il workflow rifiuta il rilascio). Al push del tag, il workflow GitHub Actions .github/workflows/docker-publish.yml:
docker-compose.yml) con i 3 digest ed esegue lo smoke test (scripts/smoke-stack.sh);:X.Y.Z (senza v, es. 1.6.8), :X.Y e :latest.Il rebuild automatico giornaliero di latest (solo con una causa reale: commit su main, patch di sistema, CVE con fix) segue la stessa pipeline e pubblica :latest + :latest-YYYYMMDD. Un'immagine che fallisce un passo resta un digest senza tag (rimosso da ghcr-cleanup.yml) e i tag esistenti non si spostano.
# Avanzare di versione (dal commit di main da rilasciare)
git tag vX.Y.Z
git push origin vX.Y.Z
Il workflow parte automaticamente. Puoi seguire l'avanzamento su GitHub → Actions → "Docker Publish".
Prima di aggiornare uno stack verifica che le immagini del tag da installare siano state prodotte e firmate da docker-publish.yml di questo repository:
scripts/verify-images.sh 1.6.9 # stesso valore di APP_VERSION
scripts/verify-images.sh latest
CONTAINER_CLI=podman scripts/verify-images.sh 1.6.9
Lo script non richiede cosign installato (usa l'immagine ufficiale ghcr.io/sigstore/cosign/cosign fissata per digest) e verifica la firma di backoffice, frontoffice e db con l'identità https://github.com/Comune-di-Montesilvano/GovPay-Interaction-Layer/.github/workflows/docker-publish.yml@refs/(tags/v*|heads/main). Se la CLI gh è presente verifica anche le attestazioni (provenance SLSA e SBOM CycloneDX). Stampa i digest verificati; exit ≠ 0 = non aggiornare lo stack. Le immagini pubblicate prima dell'introduzione della firma non passano la verifica.
Verifica automatica all'avvio (VERIFY_IMAGES). Il compose include il servizio one-shot verify-images (cosign, stessa identità): con VERIFY_IMAGES=true verifica la firma delle 3 immagini di APP_VERSION prima di avviarle; firma assente/non valida o tag inesistente → backoffice, frontoffice e db restano creati ma non partono e il deploy (anche da Portainer) va in errore: rimettere il tag precedente. Default false (il servizio esce subito con successo). Per attivarla:
scripts/verify-images.sh <APP_VERSION>;VERIFY_IMAGES=true nel .env o nelle Environment variables di Portainer, poi docker compose up -d;ghcr.io, tuf-repo-cdn.sigstore.dev e rekor.sigstore.dev.La verifica controlla il tag nel registry: esegui docker compose pull prima di docker compose up -d (oppure fissa APP_VERSION a un rilascio), altrimenti un latest locale obsoleto può non coincidere con quanto verificato.
La verifica avviene solo quando compose (ri)crea/avvia lo stack: i riavvii dei container già creati (riavvio host, restart policy) non ripassano da verify-images.
[!WARNING] Da questa versione i segreti di bootstrap sono obbligatori:
DB_ROOT_PASSWORD,BACKOFFICE_DB_PASSWORD,FRONTOFFICE_DB_PASSWORD,APP_ENCRYPTION_KEY,MASTER_TOKEN,FRONTOFFICE_LINK_SIGNING_KEY. Un'istanza con una di queste variabili vuota o assente non riparte dopo l'upgrade (docker composetermina conrequired variable ... is missing a value). Prima dell'upgrade controllare il.env(o le Environment variables di Portainer) e compilarle con i valori già in uso — non generarne di nuovi per un'istanza esistente:APP_ENCRYPTION_KEYdiversa rende illeggibili i segreti cifrati nel DB, password DB diverse non corrispondono a quelle già nel volume. Solo seMASTER_TOKENoFRONTOFFICE_LINK_SIGNING_KEYerano davvero vuote se ne può generare una nuova (openssl rand -hex 24/-hex 32): con chiave vuota nessun link firmato era stato emesso.
Altre modifiche del compose, senza azioni richieste: no-new-privileges e cap_drop: ALL su tutti i servizi con le sole capability necessarie (backoffice/frontoffice: CHOWN, SETUID, SETGID, DAC_OVERRIDE, FOWNER, KILL; db: CHOWN, SETUID, SETGID, DAC_OVERRIDE, FOWNER); servizio verify-images (spento di default, vedi sopra). Chi usa un compose personalizzato con processi aggiuntivi nei container deve verificare che non servano altre capability.
[!WARNING] Altri cambi incompatibili.
composernon è più nell'immagine runtime: le istanze che montanocomposer.json/vendoro contano sulcomposer updateall'avvio devono usare ilvendordell'immagine; convendorassente il container si ferma con un errore esplicito. L'immagine cosignghcr.io/sigstore/cosign/cosignviene scaricata sempre, anche conVERIFY_IMAGES=false: i registry mirror/offline devono includerla. È richiesto Docker Compose v2 (service_completed_successfully, liste con merge YAML): un Portainer datato con compose v1 non funziona.
[!WARNING] Prima di ogni upgrade (cambio di
APP_VERSIONo pull di un nuovolatest) esegui un backup del database. Le migrazioni dello schema sono irreversibili: una volta avviata la nuova versione, il DB non torna allo stato precedente senza un restore.
# Dump logico (stack attivo)
docker exec gil-db sh -c 'mariadb-dump -uroot -p"$MARIADB_ROOT_PASSWORD" --single-transaction --routines --all-databases' \
> gil_db_$(date +%Y%m%d_%H%M).sql
In alternativa (o in aggiunta) il backup a freddo del volume descritto in Volumi: regola aurea in produzione.
[!NOTE] Il servizio
dbha un healthcheck (healthcheck.sh --connect) e backoffice/frontoffice partono solo con il DB healthy, cioè quando MariaDB accetta connessioni (init completato). Il check non usa credenziali: funziona anche su volumi creati da immagini vecchie o ripristinati da un dump.MARIADB_AUTO_UPGRADE=1resta disponibile come opzione (eseguemariadb-upgradeall'avvio, dopo il backup) ma non è necessario per l'healthcheck.
APP_VERSION=<tag precedente> (es. 1.6.8) nel .env o nelle Environment variables di Portainer, poi docker compose pull && docker compose up -d. I tag latest-YYYYMMDD esistono solo per i rebuild automatici giornalieri: utili per tornare a un latest precedente, non sostituiscono i tag di versione.APP_VERSION seleziona tutte e 3 le immagini, quindi il rollback cambia anche l'immagine db. Il downgrade di db (nuova versione di MariaDB) o di uno schema già migrato è possibile solo insieme al restore del backup fatto prima dell'upgrade: fermare lo stack, ripristinare dump/volume, poi avviare con la APP_VERSION precedente. Mai avviare una versione vecchia su un DB già migrato.scripts/verify-images.sh.| Immagine | Scopo |
|---|---|
govpay-interaction-layer-backoffice | Applicazione backoffice (PHP/Apache) |
govpay-interaction-layer-frontoffice | Applicazione frontoffice (PHP/Apache) |
govpay-interaction-layer-db | Database MariaDB con schema iniziale |
Registry: ghcr.io/comune-di-montesilvano/
| Sviluppo | Produzione | |
|---|---|---|
| Avvio | docker compose up -d --build | docker compose pull && docker compose up -d |
| Immagini | Build locali da Dockerfile | Pre-buildate da GHCR |
| Debug mount | docker-compose.override.yml caricato automaticamente | Non presente (o da rimuovere) |
| Certificati TLS | Self-signed (auto-generati) | Validi in ssl/ |
I daemon principali (cron_ragioneria.php, cron_tefa_scanner.php, cron_pendenze_massive.php) si gestiscono da Impostazioni → Cron nel backoffice (start/stop/log/autostart). Possono anche essere avviati manualmente:
# Daemon ragioneria (sincronizza flussi GovPay → DB)
docker exec -d gil-backoffice php /var/www/html/scripts/cron_ragioneria.php
# Daemon TEFA scanner (elabora IUR via Biz Events)
docker exec -d gil-backoffice php /var/www/html/scripts/cron_tefa_scanner.php
# Pendenze massive (one-shot o in loop)
docker exec gil-backoffice php /var/www/html/scripts/cron_pendenze_massive.php
Lo script elabora i lotti caricati via interfaccia web (stato PENDING) e li invia a GovPay.
# Esecuzione manuale
docker exec gil-backoffice php /var/www/html/scripts/cron_pendenze_massive.php
Schedulazione crontab (ogni 5 minuti):
*/5 * * * * docker exec gil-backoffice php /var/www/html/scripts/cron_pendenze_massive.php >> /var/log/gil_cron.log 2>&1
Schedulazione systemd timer (consigliato in produzione):
/etc/systemd/system/gil-pendenze.service:
[Unit]
Description=GIL Inserimento Massivo Pendenze
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/docker exec gil-backoffice php /var/www/html/scripts/cron_pendenze_massive.php
/etc/systemd/system/gil-pendenze.timer:
[Unit]
Description=GIL Pendenze ogni 5 minuti
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
[Install]
WantedBy=timers.target
datiAllegati; origine e operatore tracciati.iuv_prefix): per tipologia si può configurare un prefisso (max 10 cifre) che forza idPendenza e numeroAvviso a essere avvisi pagoPA a 18 cifre con quel prefisso. Si imposta da Impostazioni → Configurazione tipologie.flussi_rendicontazioni dal daemon ragioneria — i report leggono da cache locale anziché interrogare GovPay in real-time.ragioneria, biz, tefa, pendenze-massive), con pulsanti AJAX dedicati per avviare/arrestare i processi direttamente dalla home page (riservato ai superadmin)./pagamenti/report-ragioneria)Aggiorna.Rigenera cache.id_pendenza disponibile) o la ricerca per IUV./pagamenti/report-tefa)cron_tefa_scanner.php che arricchisce le IUR via Biz Events./pagamenti/incassi-tassonomia)tassonomia_label) in luogo del valore tecnico raw.Il tab Impostazioni → Cron gestisce i daemon di background:
| Daemon | Scopo |
|---|---|
cron_biz_scanner.php | Scansiona i Biz Events e popola biz_ricevute |
cron_ragioneria.php | Sincronizza flussi GovPay nella tabella flussi_rendicontazioni; ciclo ogni 30 min |
cron_tefa_scanner.php | Processa IUR dalla cache, arricchisce via Biz Events per TEFA |
cron_pendenze_massive.php | Elabora lotti pendenze massive in stato PENDING |
docker-setup.sh lo riavvia automaticamente a ogni rebuild del container.ragioneria_scan_da).# Rebuild dopo modifiche a PHP/composer/asset
docker compose up -d --build
# Log in tempo reale
docker compose logs -f
# Shell nel container backoffice
docker compose exec backoffice bash
Il file docker-compose.override.yml viene caricato automaticamente da docker compose se presente nella stessa directory. Aggiunge bind mount locali (./debug:/var/www/html/public/debug) su backoffice e frontoffice per utility di test live.
[!WARNING]
docker-compose.override.ymlè esclusivamente per sviluppo locale. Non copiarlo né includerlo in produzione. Per avviare esplicitamente senza override:docker compose -f docker-compose.yml up -dIn Portainer, il campo Compose path deve puntare solo a
docker-compose.yml.
Struttura codice:
backoffice/ — applicazione backofficefrontoffice/ — applicazione frontofficeapp/ — librerie PHP condivisebackoffice/templates/ e frontoffice/templates/ — template TwigDocker Compose non espande variabili del tipo FOO="${BAR}" negli env_file. Usa valori espliciti.
.sh e line endingGli script devono usare LF (non CRLF). Questo repository forza i line ending via .gitattributes.
Controlla i log: docker compose logs backoffice oppure docker logs gil-backoffice
Cause comuni:
.env mancante o con variabili obbligatorie vuotessl/ non leggibili dal container (vedi ssl/README.md)GovPay-Interaction-Layer/
├── docker-compose.yml
├── docker-compose.override.yml # override sviluppo (debug mount — non usare in prod)
├── Dockerfile
├── .env # da creare (non versionato)
├── .env.example # template per .env
├── .github/workflows/
│ ├── ci.yml # CI: test PHP su push/PR
│ └── docker-publish.yml # CD: build e push immagini GHCR su tag vX.Y.Z
├── backoffice/ # applicazione backoffice (Slim 4 + Twig)
├── frontoffice/ # applicazione frontoffice
├── app/ # codice PHP condiviso
├── docker/
│ └── db/Dockerfile # immagine govpay-db
├── ssl/ # certificati TLS server (browser → app) — vedi ssl/README.md
├── certificate/ # certificati client GovPay (app → GovPay) — vedi certificate/README.md
├── img/ # immagini/loghi — vedi img/README.md
├── scripts/ # script di utilità runtime (cron)
├── migrations/ # migrazioni DB
├── govpay-clients/ # client API GovPay generati
├── pagopa-clients/ # client API pagoPA generati
└── debug/ # tool debug (montati solo in sviluppo via override)
git checkout -b feature/nuova-funzionalitagit commit -m "feat: descrizione"git push origin feature/nuova-funzionalita