# Protocol Proxy: Specifiche Implementative

## Requisiti Generali - controllare pagina standard e convenzioni&#x20;

* Ogni microservizio deve rispettare gli [standard della piattaforma](https://docs.opencityitalia.it/v/developers/standard-e-convenzioni/standard-della-piattaforma)&#x20;
* Ogni proxy deve soddisfare i requisiti suggeriti dal [12 factors manifest](https://12factor.net/it/)
* Esposizione di un endpoint`/status` per l'healthcheck: esso deve essere restituire 200 se il sistema è "healthy" e 503 in caso si presentino un problemi di connessione con kafka
* Esposizione delle metriche mediante l'endpoint `/metrics` con Prometheus utilizzando [la convenzione da loro suggerita](https://prometheus.io/docs/practices/naming/)
* Terminazione pulita del servizio (timeout di 15 secondi)&#x20;
* Esposizione di un endpoint `/docs` per la consultazione della documentazione delle API esposte dal servizio secondo lo standard OpenAPI
* Integrazione con [Sentry](https://https/.sentry.io) per l'error reporting
* Il sistema di logging deve rispettare il formato Apache e descrivere nei tre livelli debug, error e info. Ogni log, quando possibile, deve loggare il `remote_id` e l'`id` del documento processato&#x20;
* Il README deve seguire le [linee guida della pubblicazione del software open source](https://docs.italia.it/italia/developers-italia/lg-acquisizione-e-riuso-software-per-pa-docs/it/stabile/attachments/allegato-a-guida-alla-pubblicazione-open-source-di-software-realizzato-per-la-pa.html#file-readme)&#x20;
* il nome del progetto e del servizio devono essere nella seguente forma : "Protocol Proxy \<Nome del Protocollo Specifico>"
* Inserire il file `.gitlab-ci.yml` riportando in esso [questa](https://gitlab.com/opencity-labs/area-personale/pmpay-payment-proxy/-/blob/main/.gitlab-ci.yml?ref_type=heads) pipeline&#x20;

## Metriche in dettaglio

Il Protocol Proxy deve esporre le seguenti metriche:&#x20;

<table><thead><tr><th width="258">Metrica</th><th>Labels</th><th>Descrizione</th></tr></thead><tbody><tr><td><code>oc_document_validation_errors_total</code></td><td>cluster, env, app_name</td><td>la metrica deve misurare gli errori di validazione sull'evento letto (es. il <code>transmission_type</code> contiene un valore diverso da <code>Inbound</code> o <code>Outbound</code>)</td></tr><tr><td><code>oc_api_requests_total</code></td><td>cluster, env, method, app_name, status_code</td><td>la metrica deve monitorare le chiamate http indicandone lo status code</td></tr><tr><td><code>oc_document_success_events_total</code></td><td>cluster, env, app_name</td><td>la metrica deve misurare solo gli eventi per cui il proxy ha una configurazione e che sono stati processati con successo</td></tr><tr><td><code>oc_document_failed_events_total</code></td><td>cluster, env, app_name</td><td>la metrica deve misurare gli eventi validi di cui però è fallito il processing per qualsiasi motivo (escluso il caso in cui non esiste una configurazione per esso)</td></tr><tr><td><code>oc_document_provider_errors_total</code></td><td>cluster, env, app_name</td><td>la metrica deve misurare gli eventi validi di cui però è fallito il processing a causa di un errore sul provider</td></tr><tr><td><code>oc_document_internal_errors_total</code></td><td>cluster, env, app_name</td><td>la metrica deve misurare gli eventi validi di cui però è fallito il processing per errori interni al codice</td></tr><tr><td><code>oc_document_provider_latency_bucket</code></td><td>cluster, env, app_name</td><td>istogramma che mostra la distribuzione di latenza delle risposte del provider</td></tr></tbody></table>

## Requisiti normativi

* Avere una specifica in formato OpenAPI v3
* Rispettare la [Linee Guida di interoperabilità](https://docs.italia.it/italia/piano-triennale-ict/lg-modellointeroperabilita-docs): in particolare per quanto riguarda&#x20;
  * [il formato dei dati](https://docs.italia.it/italia/piano-triennale-ict/lg-modellointeroperabilita-docs/it/bozza/doc/04_Raccomandazioni%20di%20implementazione/04_raccomandazioni-tecniche-generali/02_formato-dei-dati.html) (4.2)
  * [raccomandazioni sul naming](https://docs.italia.it/italia/piano-triennale-ict/lg-modellointeroperabilita-docs/it/bozza/doc/04_Raccomandazioni%20di%20implementazione/04_raccomandazioni-tecniche-generali/03_progettazione-e-naming.html) (4.3) optando per la scelta di `snake_case` per i nomi degli attributi
  * logging (4.4)
  * risultare valido nel [validatore ufficiale OA3](https://github.com/italia/api-oas-checker)

## Documentazione API di Esempio - Swagger&#x20;

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/metrics" method="get" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/status" method="get" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/schema" method="get" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/tenants/" method="post" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/tenants/{id}" method="get" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/tenants/{id}" method="put" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/tenants/{id}" method="delete" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/services/" method="post" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/services/{id}" method="get" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/services/{id}" method="put" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>" path="/services/{id}" method="delete" %}
<https://api.qa.stanzadelcittadino.it/registry-proxy/agspr/v1/openapi.json>
{% endopenapi %}

## Specifiche funzionali

* Il servizio deve essere multi tentant e multi servizio: deve quindi essere in grado di gestire le confiugurazioni per più tenant a cui possono essere attribuiti più servizi con il corrente sistema di protocollazione.&#x20;
* Ogni richiesta sia essa appartenente alla fase 1 o alla fase 2 descritte nella sezione "[workflow sistema di protocollazione](https://docs.opencityitalia.it/sviluppatori-e-partner-tecnologici/integrazioni/integrazioni-con-il-flusso-delle-pratiche/webhooks)" devono  essere trattate in maniera atomica.
* Lo storage deve essere compatibile con Aws s3, Azure e local file system.

## Configurazione del microservizio (variabili d'ambiente)

Il servizio deve essere configurabile attraverso le seguenti variabili d'ambiente.&#x20;

Se le varibili senza valore di default non vengono settate, il servizio deve notificare la mancata impostazione attraverso un log di livello error e terminare in maniera pulita la propria esecuzione.&#x20;

<table><thead><tr><th width="348.3333333333333">Nome</th><th>Default</th><th>Descrizione</th></tr></thead><tbody><tr><td><code>ENVIRONMENT</code></td><td>local</td><td>Indica l'ambiente di sviluppo (locale, dev, prod, ecc.) utilizzato da Sentry.</td></tr><tr><td><code>DEBUG</code></td><td>true</td><td>...</td></tr><tr><td><code>SENTRY_ENABLED</code></td><td>false</td><td>...</td></tr><tr><td><code>SENTRY_DSN</code></td><td>nessun valore</td><td>Endpoint per il monitoraggio di Sentry.</td></tr><tr><td><code>KAFKA_SERVER</code></td><td>kafka:9092</td><td>Lista di lunghezza variabile i cui elementi devono essere separati da virgola.<br>lista degli Indirizzi dei broker Kafka per connettersi al cluster.</td></tr><tr><td><code>KAFKA_CONSUMER_GROUP</code></td><td>&#x3C;nome_del_servizio></td><td>Consumer group per Kafka.</td></tr><tr><td><code>KAFKA_CONSUMER_TOPIC</code></td><td>documents</td><td>Identifica il topic da cui consumare gli eventi Kafka.</td></tr><tr><td><code>KAFKA_PRODUCER_TOPIC</code></td><td>documents</td><td>Identifica il topic a cui inviare gli eventi Kafka.</td></tr><tr><td><code>KAFKA_RETRY_TOPIC</code></td><td>nessun valore</td><td>topic in cui produrre gli eventi consumati dal meccanismo di retry</td></tr><tr><td><code>SERVER_ADDRESS_PORT</code></td><td>0.0.0.0:8080</td><td>Indica l'indirizzo e la porta utilizzati per l'healthcheck.</td></tr><tr><td><code>CACHE_EXPIRATION</code></td><td>5m</td><td>...</td></tr><tr><td><code>CACHE_EVICTION</code></td><td>10m</td><td>...</td></tr><tr><td><code>STORAGE_TYPE</code></td><td>local </td><td>Tipo di storage dei pagamenti: s3, azure, local</td></tr><tr><td><code>STORAGE_ENDPOINT</code></td><td>nessun valore</td><td>Indirizzo di accesso allo storage.</td></tr><tr><td><code>STORAGE_ACCESS_S3_KEY</code></td><td>nessun valore</td><td>Chiave di accesso allo storage.</td></tr><tr><td><code>STORAGE_KEY_S3_ACCESS_SECRET</code></td><td>nessun valore</td><td>Chiave segreta di accesso allo storage.</td></tr><tr><td><code>STORAGE_S3_REGION</code></td><td>nessun valore</td><td>Location del cloud storage</td></tr><tr><td><code>STORAGE_BUCKET</code></td><td>nessun valore</td><td>Nome dello storage</td></tr><tr><td><code>STORAGE_BASE_PATH</code></td><td>"/data/"</td><td>Basepath dello storage</td></tr><tr><td><code>STORAGE_AZURE_ACCOUNT</code></td><td>nessun valore</td><td>Chiave dello storage AZURE</td></tr><tr><td><code>STORAGE_AZURE_KEY</code></td><td>nessun valore</td><td>Password dello storage AZURE</td></tr><tr><td><code>STORAGE_LOCAL_PATH</code></td><td>/data/</td><td></td></tr><tr><td><code>SDC_AUTH_TOKEN_USER</code></td><td>nessun valore</td><td>utente autenticazione per recuperare il token dalla piattaforma</td></tr><tr><td><code>SDC_AUTH_TOKEN_PASSWORD</code></td><td>nessun valore</td><td>password autenticazione per recuperare il token dalla piattaforma</td></tr></tbody></table>

## Test

### Protocol Proxy Tests Checklist

Se si sta facendo il deploy di un **nuovo** microservizio per la prima volta o si sta aggiungendo una nuova API o una nuova pagina a una interfaccia esistente, è necessario aggiungere alcuni controlli di qualità minima prima del rilascio.&#x20;

### Controlli <a href="#user-content-controlli" id="user-content-controlli"></a>

* Test automatici delle API nella CI (usare [hurl](https://hurl.dev/), [qui](https://gitlab.com/opencity-labs/area-personale/govpay-payment-proxy/-/tree/main/test?ref_type=heads) un esempio di utilizzo e [qui](https://gitlab.com/opencity-labs/area-personale/govpay-payment-proxy/-/blob/main/.gitlab-ci.yml?ref_type=heads#L52) un esempio di integrazione nelle CI)
* Test flusso standard
  * Inserire la configurazione del tenant
  * Inserire la configurazione del servizio
  * Inserire un esempio di documento non protocollato nel topic documents e verificare che venga correttamente protocollato
  * Inserire un esempio di documento protocollato nel topic documents e verificare che venga ignorato
  * Inserire un esempio di documento non protocollato nel topic documents per cui non esiste una configurazione di tenant e/o di servizio e verificare che venga ignorato
* Test flusso di errore
  * Modificare la configurazione del servizio in modo che sia errata (mettendo ad esempio credenziali errate)
  * Inserire un esempio di documento non protocollato nel topic documents e verificare che, a seguito del fallimento, venga prodotto un evento nel topic di retry
  * Correggere la configurazione del servizio
  * Inserire il documento prodotto nel topic di retry all'interno del topic documents e verificare che venga correttamente protocollato
