> For the complete documentation index, see [llms.txt](https://docs.opencityitalia.it/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.opencityitalia.it/sviluppatori-e-partner-tecnologici/standard-e-convenzioni/standard-della-piattaforma.md).

# Standard della piattaforma

## **Struttura Eventi**

### **Producers**

Nella piattaforma si fa ampio uso del **pattern** [**Event Sourcing**](https://martinfowler.com/eaaDev/EventSourcing.html), perciò è fondamentale che il **formato degli eventi** sia **stabile**, **versionato** e **documentato**.

Tutti i producer DEVONO includere **obbligatoriamente** i seguenti campi in ogni evento:

| Campo              | Valore                                                    | Formato                 | Annotazioni                                                                                 |
| ------------------ | --------------------------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------- |
| `id`               | identificativo unico dell'entità oggetto dell'evento      | UUID                    | Es: in un pagamento è l'ID del pagamento, in una pratica è l'application\_id etc...         |
| `event_id`         | identificativo unico dell'evento                          | UUID                    | Non deve esserci per nessun motivo due volte lo stesso ID                                   |
| `event_version`    | versione dell'evento                                      | Integer or Float        | E' un intero (Es: 1, 2, etc..) cambia ad ogni cambiamento NON retrocompatibile.             |
| `event_created_at` | data dell'evento                                          | ISO8601                 | Ricordarsi di usare il formato della timezone Europe/Rome (Es: `2022-06-22T15:11:20+02:00`) |
| `app_id`           | Nome e versione dell'applicativo che ha generato l'evento | `$application:$version` | Utile per motivi di debug (Es: payment-dispatcher:1.0.15).                                  |

> **Nota importante:** Se si genera un nuovo evento **a partire da uno esistente**, **NON** vanno ricopiati i campi `event_id`, `event_created_at`, `event_version`, `app_id`. Si tratta di una **nuova entità**, quindi deve avere **nuovi valori**.

### **Consumers**

Chi consuma eventi deve:

* **Gestire esplicitamente** le versioni supportate.
* **Scartare** eventi con versioni non supportate.
* **Non** generare errori per versioni non gestite:
  * È corretto **loggare in DEBUG** la ricezione di una versione non supportata.
  * In condizioni normali, un consumer **emette un log a livello INFO solo se**:
    * ha processato con successo l’evento.
    * ha eseguito un'azione concreta.

> Questo approccio evita rumore nei log e rende evidenti solo le operazioni significative.

## Sistema di Retry

### **Obiettivo**

La piattaforma è dotata di un componente, detto RetryOrchestrator, responsabile della gestione automatica dei **retry** per eventi temporaneamente non processabili. In caso di errore temporaneo, consente di riprogrammare la consegna dell’evento al consumer in base a una **politica configurabile**, evitando la perdita di messaggi e riducendo l'intervento manuale.

### **Funzionamento**

1. Quando un **servizio X** fallisce nel processare un messaggio, questo viene inviato nel **Failed Message Topic (FMT)**.
2. Il **RetryOrchestrator** legge i messaggi dal FMT e, sulla base della politica di retry, li **ripropone al servizio X**.
3. Se il messaggio esaurisce i tentativi previsti, viene inviato in una **Dead Letter Queue (DLQ)**.

### **Politica di Retry**

La politica di retry viene definita tramite due variabili d’ambiente principali:

| Variabile                  | Descrizione                                                                                                                                        |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `KAFKA_DISPATCHER_POLICY`  | Specifica la sequenza dei retry come array di coppie `NxTm`, dove `N` è il numero di tentativi e `Tm` è il tempo di attesa (es. `2x1m,1x2m,3x3m`). |
| `KAFKA_RETRY_QUEUE_PREFIX` | Prefisso dei topic di attesa su Kafka (es. `retryQueue_`).                                                                                         |

#### **Esempio**

Con la configurazione:

* `KAFKA_DISPATCHER_POLICY=2x1m,1x2m,3x3m`
* `KAFKA_RETRY_QUEUE_PREFIX=retryQueue_`

Il servizio si aspetta i seguenti topic di retry:

* `retryQueue_1m`
* `retryQueue_2m`
* `retryQueue_3m`

Un messaggio attraverserà quindi una sequenza di 6 tentativi: 2 tentativi a distanza di 1 minuto, 1 tentativo dopo 2 minuti, 3 tentativi dopo 3 minuti ciascuno.

## Standard Date

### Formato delle date

Tutte le date all’interno della piattaforma devono essere rappresentate nel **formato ISO 8601**, con la seguente struttura:

```
YYYY-MM-DDTHH:MM:SS+HH:MM
```

Esempio:

```
2025-03-12T00:00:00+01:00
```

> Questo formato garantisce coerenza, leggibilità e interoperabilità tra i diversi sistemi e microservizi, soprattutto in contesti distribuiti.

### Fuso orario

Tutte le date devono essere espresse nel **fuso orario `Europe/Rome`**, che gestisce automaticamente l’**ora solare** (`+01:00`) e l’**ora legale** (`+02:00`).

> Non utilizzare `UTC` o altri fusi orari, salvo esplicita eccezione documentata.

### Linee guida

* Le date devono **includere l’offset del fuso orario** (`+01:00` o `+02:00`) come parte della stringa.
* Le librerie utilizzate per serializzazione/deserializzazione devono essere configurate per usare **`Europe/Rome`** come timezone di default.
* Il formato deve essere rispettato sia in **input** che in **output** per tutte le API e gli eventi.

#### Applicazioni

| Contesto          | Applicazione dello standard                      |
| ----------------- | ------------------------------------------------ |
| API REST          | Tutte le date nei payload (richieste e risposte) |
| Messaggi su Kafka | Timestamp negli eventi pubblicati                |

#### Validazioni e test

* Ogni data deve essere validata secondo il pattern ISO8601 con timezone `Europe/Rome`.
* I test automatici devono includere:
  * Verifica del formato in fase di creazione e lettura degli eventi.
  * Verifica dell’offset corretto (`+01:00` o `+02:00`) in base alla data.
  * Gestione corretta dell’ora legale.

## API Standards

### **Principi di riferimento**

Le API della piattaforma seguono i principi di:

* [Zalando RESTful API Guidelines](https://opensource.zalando.com/restful-api-guidelines/)
* [Linee guida di interoperabilità della PA (AgID)](https://docs.italia.it/AgID/documenti-in-corso/lg-interoperabilita-docs/)

### **Comportamento dei servizi**

* I servizi DEVONO **esporre solo i verbi HTTP previsti** e restituire **errore per metodi non supportati**.
* I metodi seguenti devono essere **idempotenti**, come da [RFC 7231](https://datatracker.ietf.org/doc/html/rfc7231):
  * `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PUT`, `TRACE`
* I percorsi (path) delle risorse devono:
  * Essere **al plurale** per rappresentare collezioni
  * Usare **kebab-case** (es. `user-preferences`)

### **Esempi di endpoint**

```http
POST    /tenants
GET     /tenants/{tenant_id}
PUT     /tenants/{tenant_id}
PATCH   /tenants/{tenant_id}
DELETE  /tenants/{tenant_id}
```

> Le URL nelle risposte devono essere sempre espresse in forma **assoluta**.

### GET e Navigazione

Per le risorse collezione, le risposte devono includere una struttura di **meta-informazioni** e **link di navigazione**:

```json
{
  "meta": {
    "page": {
      "offset": 5000,
      "limit": 20,
      "sort": "creationTime"
    },
    "total": 46561
  },
  "links": {
    "self": "https://api.example.it/items?offset=5000&limit=20&sort=creationTime",
    "prev": "https://api.example.it/items?offset=4980&limit=20&sort=creationTime",
    "next": "https://api.example.it/items?offset=5020&limit=20&sort=creationTime"
  },
  "data": [
    { "id": "..." },
    { "id": "..." },
    { "id": "..." }
  ]
}
```

### **Paginazione**

I parametri di paginazione da usare nei `GET`, ove applicabile, sono:

| Parametro | Descrizione                                     |
| --------- | ----------------------------------------------- |
| `offset`  | Offset dell’elemento iniziale                   |
| `limit`   | Numero massimo di elementi da restituire        |
| `sort`    | Ordinamento (campo o criterio)                  |
| `cursor`  | Puntatore per navigazione cursor-based          |
| `embed`   | Specifica risorse correlate da includere        |
| `q`       | Query full-text o filtro libero                 |
| `fields`  | Specifica dei campi da includere nella risposta |

Per endpoint con elevata numerosità di dati, si può usare la **cursor-based pagination**, ad esempio:

```http
GET /payments?created_since=2024-12-01T00:00:00+01:00
```

### Gestione degli errori

Tutti gli errori devono seguire lo standard [RFC 7807 - Problem Details for HTTP APIs](https://datatracker.ietf.org/doc/html/rfc7807):

```json
{
  "type": "/errors/incorrect-user-pass",
  "title": "Incorrect username or password.",
  "status": 401,
  "detail": "Authentication failed due to incorrect username or password.",
  "instance": "/login/log/abc123"
}
```

> Ogni errore può includere:
>
> * `type`: URL che identifica il tipo di errore
> * `title`: breve descrizione dell’errore
> * `status`: HTTP status code (opzionale)
> * `detail`: descrizione dettagliata (opzionale)
> * `instance`: identificatore specifico dell’occorrenza (opzionale)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.opencityitalia.it/sviluppatori-e-partner-tecnologici/standard-e-convenzioni/standard-della-piattaforma.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
