# Architettura

## Architettura generale

In questo e nei diagrammi che seguono è stato seguito il [Modello C4](https://c4model.com/) per la rappresentazione dei diagrammi architetturali.

```mermaid
C4Context
      title System Context diagram for Opencity Italia



Enterprise_Boundary(b0, "DatacenterBoundary") {

  System_Boundary(b1, "CmsBoundary"){
    System(EzSystem, "CMS Core", "Permette ai redattori di gestire i contenuti e di pubblicarli secondo il modello prescelto.")
    System(SolrService, "CMS Search Engine", "Permette la ricerca rapida dei contenuti del sito.")
  }

  System_Boundary(b2, "ServicesBoundary"){
    SystemQueue_Ext(KafkaService, "Kafka", "Gestione asincrona di messaggi")

    System(ServicesCore, "Servizi Digitali Core", "Gestione pratiche a istanza e appuntamenti")
    System(AnalyticsSubsystem, "Analytics", "Gestione statistiche e rapporti")
    System(PaymentsIntegrations, "Sistemi di pagamento", "Integrazioni con gli intermediari di pagamento PagoPA")
    System(DocumentsIntegrations, "Sistemi di protocollazione", "Integrazioni con i sistemi di protocollazione")

  }

  System_Ext(MailServer, "E-mail system", "Un servizio di invio e-mail.")
  SystemDb_Ext(PostgreSql, "PostgreSQL Database", "Main data persistence")
  SystemDb_Ext(MongoDb, "MongoDB Document Database", "Forms data persistence")

}

BiRel(ServicesCore, KafkaService, "Send messages")
Rel(AnalyticsSubsystem, KafkaService, "Read messages")
BiRel(PaymentsIntegrations, KafkaService, "Send & Read messages")
BiRel(DocumentsIntegrations, KafkaService, "Send & Read messages")

Person_Ext(Citizen, "Visitatore del sito")
Person(RedattoreSito, "Redattore", "Gestisce i contenuti")
Person(AmministratoreSito, "Amministratore", "Gestisce utenti e impostazioni")
Person(ServicesOperator, "Operatore Servizi Digitali", "Gestisce pratiche e appuntamenti")
 
BiRel(Citizen, EzSystem, "Visits")
BiRel(RedattoreSito, EzSystem, "Uses")

Rel(EzSystem, MailServer, "Sends e-mails", "SMTP")
Rel(EzSystem, RedattoreSito, "Sends e-mails to")
Rel(ServicesCore, MailServer, "Sends e-mails", "SMTP")
Rel(ServicesCore, MongoDb, "Store forms")

Rel(EzSystem, PostgreSql, "Read&Write data")
Rel(ServicesCore, PostgreSql, "Read&Write data")

UpdateElementStyle(Citizen, $fontColor="white", $bgColor="grey", $borderColor="grey")
UpdateRelStyle(Citizen, EzSystem, $textColor="blue", $lineColor="blue", $offsetX="5")
UpdateRelStyle(EzSystem, MailServer, $textColor="blue", $lineColor="blue", $offsetY="-10")

UpdateRelStyle(SystemAA, SystemC, $textColor="blue", $lineColor="blue", $offsetY="-40", $offsetX="-50")
UpdateRelStyle(SystemC, customerA, $textColor="red", $lineColor="red", $offsetX="-50", $offsetY="20")

UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")


```

## Sito istituazionale

L'architettura del CMS è una classica architettura monolitica con un core in PHP e una persistenza principale (PostgreSQL) a cui si affiancano un motore di ricerca (Solr) e un layer di cache http (Varnish)

### Container diagram

```mermaid
    C4Container
    title Container diagram per il sito istituzionale

    System_Ext(email_system, "E-Mail System", "An external e-mail delivery", $tags="v1.0")

    Container_Boundary(c1, "CMS") {
        Container(cms-core, "CMS Core", "PHP, Docker container", "Core del CMS")        
        ContainerDb(solr, "SOLR", "Java, Docker container", "Motore di ricerca")
        ContainerDb_Ext(redis, "Redis", "Key-value store", "Persistenza temporanea per le sessioni utente")
        ContainerDb_Ext(postgresql, "PostgreSQL", "Database-as-a-service", "Persistenza princiapale dell'applicativo")
    }

    Rel(cms-core, solr, "indexes", "HTTP")
    Rel(cms-core, postgresql, "store", "SQL")
    Rel(cms-core, redis, "store", "custom")
    UpdateRelStyle(cms-core, solr, $offsetY="20")
    Rel(cms-core, email_system, "send", "SMTP")

UpdateLayoutConfig($c4ShapeInRow="2", $c4BoundaryInRow="1")
```

## Motore di ricerca (Solr)

Il CMS usa **Apache Solr** tramite l'estensione ezfind per indicizzare i contenuti e servirli alla ricerca e ai blocchi filtrabili. Ogni istanza ha il proprio core dedicato. L'indicizzazione avviene automaticamente alla pubblicazione, ma in alcuni scenari (primo avvio, modifiche al modello dei contenuti, migrazione) è necessario un reindice manuale.

Per i dettagli sul funzionamento e su quando eseguire il reindice, vedi [Motore di ricerca (Solr)](/installazione-e-manutenzione/solr-indicizzazione.md).

## Servizi digitali e area personale

L'architettura ha subito varie trasformazioni nel tempo e non può dirsi ancora definitiva, ma alcune caratteristiche sono ormai consolidate:

* la decomposizione in microservizi con storage indipendenti e API ReST
* il sistema di scambio di messaggi basato su Kafka per rendere asincrone le interazioni tra i microservizi

```mermaid
    C4Container
    title Container diagram per i servizi digitali

    Container_Boundary(c1, "Core") {
        Container(app-core, "", "", "")        
    }

    Container_Boundary(c2, "Analytics") {
        Container(analytics, "", "", "")        
    }

    Container_Boundary(c3, "Pagamenti") {
        Container(pagamenti, "", "", "")        
    }
    Container_Boundary(c4, "Protocolli") {
        Container(protocolli, "", "", "")        
    }

    SystemQueue_Ext(kafka, "Kafka", "Gestione asincrona di messaggi")

    BiRel(app-core, kafka, "R/W Messages")
    BiRel(analytics, kafka, "Read Messages")
    BiRel(protocolli, kafka, "R/W Messages")
    BiRel(pagamenti, kafka, "R/W Messages")

UpdateLayoutConfig($c4ShapeInRow="2", $c4BoundaryInRow="2")


```

### Vista dettagliata di Services Core

Questa parte del sistema ha la maggior parte delle responsabilità relative alle pratiche al sistema di appuntamenti. E' costitutito da un core in symfony e da alcuni servizi al contorno che svolgono funzioni specifiche.

* **Kafka API**, è una istanza del server open-source Vector fornisce una interfaccia HTTP per Kafka
* **Gotenberg** è un tool opensource che la piattaforma utilizza per la creazione dei PDF
* **Form Server** è la nostra implementazione del server open-source Form.io, di cui usiamo nel core le librerie Javascript per il rendering delle form.
* **Form Builder** è una Single-Page-App in angular che include la libreria di Form.io per la creazione delle form. E' un servizio dedicato agli amministratori della piattaforma per la gestione di una libreria di componenti condivisi e riusabili dagli Enti nella creazione dei loro moduli: anagrafiche, definizione di immobili, autoveicoli etc...

```mermaid
    C4Container
    title Container diagram per il Core dei servizi digitali

    Container_Boundary(c1, "Core") {
        Container(vector, "Kafka API", "Vector instance", "")
        Container(payment-updater, "Payments Updater", "Legge msg su Pagamenti e aggiorna le pratiche", "")
        Container(document-updater, "Documents Updater", "Legge msg su Documenti e aggiorna le pratiche", "")
        Container(app-core, "Services Core", "", "")
        Container(form-server, "Form Server", "", "")        
        Container(gotenberg, "PDF Generator", "Gotenberg Instance", "")
        Container(form-builder, "Form UI", "Angular SPA", "")
        Container(pdnd-connector, "PDND Connector", "Interagisce per conto dell'Ente con la piattaforma PDND", "")
    }

    SystemQueue_Ext(kafka, "Kafka", "Distributed message system")
    SystemDb_Ext("postgresql", "PostgreSQL", "Main relational db")
    SystemDb_Ext("redis", "Redis", "Key-value store")
    SystemDb_Ext("mongo", "MongoDB", "Document database")

    Rel(app-core, gotenberg, "Creates PDF from modules")
    Rel(app-core, form-server, "Saves modules definitions")
    Rel(app-core, pdnd-connector, "PDND e-services management")

    Rel(app-core, vector, "Emit applications messages", "HTTP")
    Rel(vector, kafka, "")

    Rel(app-core, redis, "Sessions data", "")
    UpdateRelStyle(app-core, redis, $offsetY="0", $offsetX="0")

    Rel(app-core, postgresql, "", "")
    UpdateRelStyle(app-core, postgresql, $offsetY="0", $offsetX="0")

    Rel(form-server, mongo, "modules definition")
    Rel(form-builder, form-server, "")


    Rel(kafka, payment-updater, "Read topic payments")
    Rel(payment-updater, app-core, "Update applications")

    Rel(kafka, document-updater, "")
    Rel(document-updater, app-core, "")

    
UpdateLayoutConfig($c4ShapeInRow="2", $c4BoundaryInRow="2")


```

### Vista di dettaglio del sotto-sistema dei Pagamenti

TBD

### Vista di dettaglio del sotto-sistema dei Documenti

TBD

### Vista di dettaglio del sotto-sistema degli Analytics

```mermaid
C4Container
    title Container diagram per sistema di Analytics

    Container_Boundary(c1, "Analytics") {
        
        Container(services-aggregator, "Services aggregator", "", "")
        Container(bookings-aggregator, "Bookings Aggregator", "", "")   
        Container(first-avail-aggregator, "First-Availability Aggregator", "", "")   
        Container(charts-exporter, "ChartJs Exporter", "API", "HTTP")   
        Container(grafana, "Grafana", "Internal data-visualization tool", "")   
    }

    SystemQueue_Ext(kafka, "Kafka", "Distributed message system")
    SystemDb_Ext("clickhouse", "ClickHouse", "OLAP Database")

    Rel(kafka, services-aggregator, "")
    Rel(kafka, bookings-aggregator, "")
    Rel(kafka, first-avail-aggregator, "")

    Rel(services-aggregator, clickhouse, "")
    Rel(bookings-aggregator, clickhouse, "")
    Rel(first-avail-aggregator, clickhouse, "")

    Rel(clickhouse, grafana, "")
    Rel(clickhouse, charts-exporter, "")

UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="2")

```


---

# Agent Instructions: 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/installazione-e-manutenzione/architettura.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.
