Salta al contenuto principale

GovStack Building Block: Implementare Moduli Government Digitale

Come implementare servizi di governo digitale con l'approccio modulare di GovStack: building block per identità, pagamenti, consent…

Cosa ne pensi di questo articolo?

GovStack Building Block: Implementare Moduli Government Digitale
GovTechFoto:Daniil KomovPexels

In Breve

Come implementare servizi di governo digitale con l'approccio modulare di GovStack: building block per identità, pagamenti, consent…

GovTech 24 min

GovStack Building Block: Implementare Moduli Government Digitale

Come implementare servizi di governo digitale con l'approccio modulare di GovStack: building block per identità, pagamenti, consent, registri digitali e messaging. GovSpecs 2.0 (2025-2027), adottato da oltre 20 paesi, come paradigma per DPI scalabili e interoperabili.

GovStack Building Blocks Digital Government DPI GovSpecs 2.0 ITU

GovStack: il Framework Modulare per il Governo Digitale

GovStack è un'iniziativa internazionale lanciata nel 2020 da Estonia, Germania, ITU (International Telecommunication Union) e DIAL (Digital Impact Alliance) con l'obiettivo di condividere gli strumenti, le conoscenze e le best practice necessarie per costruire servizi pubblici digitali su scala, senza dover ricominciare da zero ogni volta.

L'idea fondamentale è semplice ma potente: invece di sviluppare sistemi monolitici per-paese, ogni servizio digitale governativo viene decomposto in Building Block (moduli funzionali) che offrono una capacità specifica (identità, pagamenti, messaggistica, registri, etc.) e che possono essere combinati liberamente per costruire qualsiasi servizio. I Building Block sono interoperabili, riusabili e indipendenti dall'implementazione: GovStack definisce le specifiche, non il software.

Nel 2025, con il lancio di GovSpecs 2.0 (la strategia 2025-2027), GovStack ha raffinato il framework integrando nuovi building block, aggiornando le specifiche di interoperabilità e definendo un modello di maturità a più livelli per supportare paesi con capacità digitale molto diverse. Oltre 20 paesi stanno attivamente usando l'approccio GovStack.

Cosa Imparerai

  • I 9 Building Block fondamentali di GovStack e le loro specifiche tecniche
  • Come mappare i servizi PA italiani esistenti (SPID, CIE, pagoPA) sui Building Block GovStack
  • Architettura di riferimento GovStack: layered model e integration bus
  • GovSpecs 2.0: le novità della strategia 2025-2027
  • Implementazione pratica di un Building Block Identity con OpenID Connect
  • Building Block Payments: integrazione con sistemi di pagamento nazionali
  • Consent Building Block: gestione del consenso conforme GDPR
  • Come valutare se GovStack è adatto al tuo contesto

I 9 Building Block Fondamentali

GovStack definisce 9 building block fondamentali (pubblicati nella nuova specifica 2025) che coprono le funzionalità trasversali necessarie a qualsiasi servizio governativo digitale:

Building Block Funzione Protocolli / Standard Esempio Italiano
Identity Autenticazione e gestione identità OIDC, SAML, W3C DID SPID, CIE, EUDI Wallet
Payments Elaborazione pagamenti e trasferimenti ISO 20022, REST API pagoPA
Consent Raccolta e gestione dei consensi GDPR, DPIA, OAuth scopes CMP con GDPR-by-Design
Digital Registries Gestione di registri autorevoli (anagrafe, catasto) REST API, FHIR, CKAN ANPR, catasto, albo professionale
Messaging Comunicazioni sicure tra governo e cittadini SMTP, Push, WebSocket, MQTT IO App, PEC, notifiche pagoPA
Information Mediation Scambio dati sicuro tra sistemi X-Road, REST, GraphQL PDND, Interoperabilità AgID
Registration Iscrizione di persone/entità a servizi REST API, OAuth 2.0 Portale INPS, SUAP, portali comunali
Scheduler Gestione appuntamenti e prenotazioni iCalendar, REST API CUP sanitario, sportello digitale
Workflow Orchestrazione processi e procedimenti BPMN, SAGA pattern, REST Sistemi di gestione pratiche PA

Architettura di Riferimento GovStack

GovStack propone un'architettura a livelli (layered architecture) in cui i Building Block si collocano in strati distinti con responsabilità chiare:

  • Layer 0 - Infrastructure: cloud, network, security. I BB non dipendono da un cloud specifico; possono girare su AWS, Azure, GCP o infrastruttura on-premise.
  • Layer 1 - Core Building Blocks: i 9 BB fondamentali. Sono servizi autonomi che espongono API RESTful standardizzate. Ogni BB ha una specifica pubblica (OpenAPI + schemi JSON).
  • Layer 2 - Shared Services: servizi trasversali come logging centralizzato, service mesh, API gateway, service discovery. Questi servizi supportano tutti i BB.
  • Layer 3 - Applications: i servizi digitali veri e propri (iscrizione scolastica, richiesta certificato, pagamento bollo) che orchestrano i BB sottostanti.
# Architettura di un servizio PA con Building Block GovStack
# Esempio: Servizio di iscrizione scolastica online

# Il servizio orchestra 5 Building Block:
# 1. Identity BB - autenticazione genitore con SPID/CIE
# 2. Registration BB - raccolta dati del bambino
# 3. Digital Registries BB - verifica iscrizione anagrafica
# 4. Consent BB - consenso al trattamento dati minori
# 5. Messaging BB - conferma iscrizione via IO App/email
# 6. Payments BB - pagamento tassa iscrizione via pagoPA

from dataclasses import dataclass
from typing import Optional
import httpx

@dataclass
class SchoolEnrollmentRequest:
    parent_session_token: str   # Token da Identity BB (SPID/CIE)
    child_fiscal_code: str
    school_code: str
    year: int

class SchoolEnrollmentService:
    """
    Servizio iscrizione scolastica che orchestra i Building Block GovStack.
    Pattern: Saga orchestrator (gestione stati distribuiti con compensazioni).
    """

    def __init__(
        self,
        identity_bb_url: str,
        registry_bb_url: str,
        consent_bb_url: str,
        messaging_bb_url: str,
        payments_bb_url: str
    ):
        self.identity_url = identity_bb_url
        self.registry_url = registry_bb_url
        self.consent_url = consent_bb_url
        self.messaging_url = messaging_bb_url
        self.payments_url = payments_bb_url

    async def process_enrollment(self, request: SchoolEnrollmentRequest) -> dict:
        """
        Saga: processo iscrizione con compensazioni in caso di errore.
        Ogni step è idempotente e reversibile.
        """
        saga_log = []

        try:
            # Step 1: Verifica identità genitore tramite Identity BB
            parent_identity = await self._verify_parent_identity(
                request.parent_session_token
            )
            saga_log.append({"step": "identity_verified", "status": "ok"})

            # Step 2: Verifica residenza bambino tramite Digital Registries BB
            child_registry = await self._verify_child_in_registry(
                request.child_fiscal_code,
                parent_identity["fiscal_number"]
            )
            saga_log.append({"step": "registry_verified", "status": "ok"})

            # Step 3: Raccolta consenso GDPR tramite Consent BB
            consent_id = await self._collect_consent(
                parent_identity["fiscal_number"],
                purpose="school_enrollment_data_processing"
            )
            saga_log.append({"step": "consent_collected", "consent_id": consent_id})

            # Step 4: Registrazione iscrizione tramite Registration BB
            enrollment_id = await self._register_enrollment(
                child_fc=request.child_fiscal_code,
                school_code=request.school_code,
                year=request.year,
                parent_fc=parent_identity["fiscal_number"]
            )
            saga_log.append({"step": "enrollment_registered", "enrollment_id": enrollment_id})

            # Step 5: Pagamento tassa (se prevista) tramite Payments BB
            payment_url = await self._create_payment(
                parent_fc=parent_identity["fiscal_number"],
                enrollment_id=enrollment_id,
                amount_cents=1500  # 15 euro
            )
            saga_log.append({"step": "payment_created", "payment_url": payment_url})

            # Step 6: Notifica conferma tramite Messaging BB
            await self._send_confirmation(
                parent_fc=parent_identity["fiscal_number"],
                enrollment_id=enrollment_id,
                payment_url=payment_url
            )
            saga_log.append({"step": "notification_sent", "status": "ok"})

            return {
                "status": "success",
                "enrollment_id": enrollment_id,
                "payment_url": payment_url,
                "saga_log": saga_log
            }

        except Exception as e:
            # Compensazione: rollback degli step completati in ordine inverso
            await self._compensate(saga_log, e)
            raise

    async def _verify_parent_identity(self, session_token: str) -> dict:
        """Chiama il Building Block Identity per validare il token SPID/CIE."""
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{self.identity_url}/v1/tokens/validate",
                json={"token": session_token}
            )
            response.raise_for_status()
            return response.json()  # Returns: fiscal_number, name, surname, etc.

    async def _verify_child_in_registry(self, child_fc: str, parent_fc: str) -> dict:
        """Chiama il Building Block Digital Registries per verificare l'anagrafe."""
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{self.registry_url}/v1/citizens/{child_fc}/family-relations",
                params={"parent_fiscal_code": parent_fc}
            )
            response.raise_for_status()
            return response.json()

    async def _collect_consent(self, parent_fc: str, purpose: str) -> str:
        """Registra il consenso tramite il Building Block Consent."""
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{self.consent_url}/v1/consents",
                json={
                    "citizen_pseudonym": self._pseudonymize(parent_fc),
                    "purpose": purpose,
                    "legal_basis": "GDPR Art. 6(1)(e)",
                    "version": "2025-01"
                }
            )
            response.raise_for_status()
            return response.json()["consent_id"]

    async def _compensate(self, saga_log: list, error: Exception):
        """
        Compensazione Saga: rollback in ordine inverso degli step completati.
        Garantisce consistenza anche in caso di errori parziali.
        """
        for step in reversed(saga_log):
            try:
                if step["step"] == "consent_collected":
                    await self._revoke_consent(step["consent_id"])
                elif step["step"] == "enrollment_registered":
                    await self._cancel_enrollment(step["enrollment_id"])
            except Exception as compensation_error:
                # Logga l'errore di compensazione ma continua
                print(f"Compensation error for {step['step']}: {compensation_error}")

    def _pseudonymize(self, fiscal_code: str) -> str:
        import hashlib, hmac
        key = b"secret-vault-key"  # In produzione: usa un HSM
        return hmac.new(key, fiscal_code.encode(), hashlib.sha256).hexdigest()[:32]

GovSpecs 2.0: Le Novità della Strategia 2025-2027

GovSpecs 2.0, annunciato da GovStack nel 2025, introduce importanti aggiornamenti rispetto alla versione precedente delle specifiche:

  • Modello di maturità a 4 livelli: da "Fase iniziale" (solo formazione e architettura di alto livello) a "Integrazione avanzata" (multiple BB integrate in framework nazionali di interoperabilità). Questo permette ai paesi di adottare GovStack secondo le proprie priorità e capacità.
  • Supporto a Verifiable Credentials: il Building Block Identity ora include specifiche per W3C Verifiable Credentials, allineandosi con eIDAS 2.0 e il programma EUDI Wallet europeo.
  • AI BB: un nuovo Building Block per l'integrazione di componenti AI (modelli di language, predizione, classificazione) nei servizi governativi, con attenzione alla trasparenza e all'explainability.
  • Specifiche OpenAPI 3.1: tutte le API dei BB sono ora documentate con OpenAPI 3.1, con schemi JSON completi e esempi testabili tramite SwaggerUI.
  • Conformance testing: un framework automatizzato per verificare che un'implementazione di BB sia conforme alle specifiche GovStack.

Implementazione del Building Block Identity con OIDC

Il Building Block Identity è il più critico e il più complesso da implementare. GovStack specifica che deve esporre le seguenti API:

# Building Block Identity - Implementazione minima conforme GovStack
# OpenAPI 3.1 compatible - FastAPI implementation

from fastapi import FastAPI, HTTPException, Header, Depends
from fastapi.security import HTTPBearer
from pydantic import BaseModel
from typing import Optional
import jwt

app = FastAPI(
    title="Identity Building Block",
    description="GovStack Identity BB - Conforme a GovSpecs 2.0",
    version="2.0.0"
)

security = HTTPBearer()

# --- Modelli ---

class TokenValidationRequest(BaseModel):
    token: str
    expected_acr: Optional[str] = None  # Livello autenticazione richiesto

class IdentityResponse(BaseModel):
    sub: str                    # Identificativo presso l'IdP
    fiscal_number: Optional[str] = None  # Codice Fiscale (SPID/CIE)
    given_name: str
    family_name: str
    birthdate: Optional[str] = None
    acr: str                    # Livello autenticazione effettivo
    auth_time: int              # Timestamp autenticazione
    session_valid_until: int    # Scadenza sessione

class SessionCreationRequest(BaseModel):
    idp_id: str                 # Identity Provider scelto dall'utente
    redirect_uri: str
    acr_values: str = "https://www.spid.gov.it/SpidL2"
    scope: list = ["openid", "profile"]
    ui_locales: str = "it"

# --- Endpoints del Building Block Identity ---

@app.post("/v1/sessions",
    summary="Avvia sessione di autenticazione",
    tags=["Sessions"],
    response_model=dict)
async def create_authentication_session(request: SessionCreationRequest) -> dict:
    """
    GovStack Identity BB - Avvia il flusso di autenticazione.
    Restituisce l'URL di redirect verso l'IdP.
    """
    # Genera state e nonce per sicurezza
    import secrets
    session_id = secrets.token_urlsafe(32)
    state = secrets.token_urlsafe(32)
    nonce = secrets.token_urlsafe(32)

    # Recupera metadata dell'IdP dalla federazione OIDC
    idp_metadata = await get_idp_metadata(request.idp_id)

    # Costruisce URL autorizzazione (PKCE + Request Object)
    auth_url = build_oidc_auth_url(
        idp_auth_endpoint=idp_metadata["authorization_endpoint"],
        client_id=CLIENT_ID,
        redirect_uri=request.redirect_uri,
        scope=request.scope,
        state=state,
        nonce=nonce,
        acr_values=request.acr_values,
        private_key=SIGNING_KEY
    )

    # Salva sessione (Redis o DB)
    await session_store.save(session_id, {
        "state": state, "nonce": nonce, "idp_id": request.idp_id
    })

    return {"session_id": session_id, "authorization_url": auth_url}

@app.post("/v1/tokens/validate",
    summary="Valida un token di sessione",
    tags=["Tokens"],
    response_model=IdentityResponse)
async def validate_token(request: TokenValidationRequest) -> IdentityResponse:
    """
    GovStack Identity BB - Valida un token e restituisce l'identità.
    I servizi chiamanti usano questo endpoint per verificare l'autenticazione.
    """
    try:
        # Decodifica e valida il token (firma, scadenza, audience)
        claims = jwt.decode(
            request.token,
            JWKS,
            algorithms=["RS256"],
            audience=CLIENT_ID
        )

        # Verifica livello autenticazione se richiesto
        if request.expected_acr:
            actual_acr = claims.get("acr", "")
            if not _meets_acr_requirement(actual_acr, request.expected_acr):
                raise HTTPException(
                    status_code=403,
                    detail=f"Insufficient authentication level. Required: {request.expected_acr}"
                )

        return IdentityResponse(
            sub=claims["sub"],
            fiscal_number=claims.get("fiscal_number"),
            given_name=claims["given_name"],
            family_name=claims["family_name"],
            birthdate=claims.get("birthdate"),
            acr=claims.get("acr", ""),
            auth_time=claims.get("auth_time", 0),
            session_valid_until=claims.get("exp", 0)
        )
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired")
    except jwt.InvalidTokenError as e:
        raise HTTPException(status_code=401, detail=f"Invalid token: {str(e)}")

@app.delete("/v1/sessions/{session_id}",
    summary="Termina sessione (logout)",
    tags=["Sessions"])
async def end_session(session_id: str) -> dict:
    """
    GovStack Identity BB - Logout con propagazione verso l'IdP.
    Implementa OIDC Back-Channel Logout per notificare tutti i RP attivi.
    """
    session = await session_store.get(session_id)
    if not session:
        raise HTTPException(status_code=404, detail="Session not found")

    # Notifica logout all'IdP (OIDC Back-Channel Logout)
    idp_metadata = await get_idp_metadata(session["idp_id"])
    if "end_session_endpoint" in idp_metadata:
        await propagate_logout(idp_metadata["end_session_endpoint"], session)

    await session_store.delete(session_id)
    return {"status": "session_terminated"}

def _meets_acr_requirement(actual: str, required: str) -> bool:
    """Verifica che il livello di autenticazione effettivo soddisfi il requisito."""
    ACR_LEVELS = {
        "https://www.spid.gov.it/SpidL1": 1,
        "https://www.spid.gov.it/SpidL2": 2,
        "https://www.spid.gov.it/SpidL3": 3,
        "https://www.cie.gov.it/cie/aa": 2,
    }
    return ACR_LEVELS.get(actual, 0) >= ACR_LEVELS.get(required, 0)

Building Block Messaging: IO App e Notifiche Governative

Il Building Block Messaging gestisce le comunicazioni tra governo e cittadini. In Italia, il servizio più allineato con le specifiche GovStack Messaging è IO App (io.italia.it), l'app nazionale per la comunicazione con la PA gestita da PagoPA S.p.A.

# Building Block Messaging - Integrazione con IO App
# API REST di IO App per invio messaggi ai cittadini

import httpx
from pydantic import BaseModel
from typing import Optional

class IOMessage(BaseModel):
    fiscal_code: str           # Codice Fiscale del destinatario
    time_to_live: int = 3600  # Secondi di validità notifica push
    content: dict              # Contenuto del messaggio
    default_addresses: Optional[dict] = None  # Fallback email

class IOAppClient:
    """
    Client per le API di IO App.
    Le API IO App sono disponibili su https://developer.io.italia.it
    """

    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://api.io.italia.it/api/v1"

    async def send_message(self, message: IOMessage) -> dict:
        """
        Invia un messaggio a un cittadino tramite IO App.
        Il cittadino deve aver attivato il proprio profilo IO.
        """
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{self.base_url}/messages",
                headers={
                    "Ocp-Apim-Subscription-Key": self.api_key,
                    "Content-Type": "application/json"
                },
                json={
                    "fiscal_code": message.fiscal_code,
                    "time_to_live": message.time_to_live,
                    "content": message.content,
                    "default_addresses": message.default_addresses
                }
            )
            response.raise_for_status()
            return response.json()

    async def check_profile(self, fiscal_code: str) -> bool:
        """
        Verifica se un cittadino ha attivato il profilo IO e accetta messaggi dalla PA.
        """
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{self.base_url}/profiles/{fiscal_code}",
                headers={"Ocp-Apim-Subscription-Key": self.api_key}
            )
            if response.status_code == 404:
                return False
            response.raise_for_status()
            profile = response.json()
            return profile.get("sender_allowed", False)

# Utilizzo: notifica iscrizione scolastica
async def notify_enrollment(fiscal_code: str, enrollment_id: str, payment_url: str):
    io_client = IOAppClient(api_key="your-io-api-key")

    # Verifica se il cittadino usa IO App
    has_io = await io_client.check_profile(fiscal_code)

    if has_io:
        # Messaggio strutturato IO App con CTA pagamento
        message = IOMessage(
            fiscal_code=fiscal_code,
            content={
                "subject": f"Iscrizione Scolastica {enrollment_id} - Conferma",
                "markdown": f"""
## La tua iscrizione è stata registrata

L'iscrizione con codice **{enrollment_id}** è stata registrata con successo.

Per completare la procedura, effettua il pagamento della tassa di iscrizione tramite il
link qui sotto.

**Importo**: 15,00 €

[Paga ora]({payment_url})

Per assistenza: [Ufficio Scolastico](https://istruzione.comune.esempio.it)
""",
                "payment_data": {
                    "amount": 1500,
                    "notice_number": enrollment_id,
                    "payee": {
                        "fiscal_code": "COMUNE_FC",
                        "name": "Comune di Esempio"
                    }
                }
            },
            default_addresses={"email": None}  # No fallback email
        )
        await io_client.send_message(message)
    else:
        # Fallback: email tradizionale (da implementare)
        await send_email_notification(fiscal_code, enrollment_id, payment_url)

Mappa GovStack su Ecosistema Italiano

L'Italia ha un ecosistema DPI già avanzato che si mappa naturalmente sui Building Block GovStack. Per un developer italiano, adottare GovStack non significa ricominciare da zero: significa riorganizzare le integrazioni esistenti secondo un modello modulare standardizzato.

BB GovStack Implementazione Italiana Livello Maturità Gap da Colmare
Identity SPID, CIE, eIDAS Alto (livello 3-4) Unificazione OIDC completa, EUDI Wallet
Payments pagoPA Alto (livello 4) API GPD REST completa
Messaging IO App, PEC Alto (livello 3) Penetrazione IO App (ancora bassa in alcune aree)
Digital Registries ANPR, catasto, PDND Medio (livello 2-3) Interoperabilità tra registri ancora parziale
Information Mediation PDND Medio (livello 2) Adozione PDND ancora in crescita
Consent Vario (non standardizzato) Basso (livello 1) Serve piattaforma consensi centralizzata
Scheduler CUP sanitario regionale Basso-Medio (livello 1-2) Frammentazione regionale; no standard nazionale
Workflow Sistemi pratiche PA (eterogenei) Basso (livello 1) Grande eterogeneità; serve standardizzazione

Quando Adottare GovStack

GovStack è particolarmente adatto quando:

  • Stai costruendo un nuovo servizio digitale PA da zero e vuoi evitare dipendenze vendor
  • Devi integrare sistemi esistenti e vuoi un modello architetturale di riferimento condiviso
  • Operi in un contesto multi-paese (cooperazione internazionale, servizi transfrontalieri)
  • Vuoi contribuire all'ecosistema open source di GovStack e beneficiare delle implementazioni di altri paesi

GovStack è meno adatto quando hai servizi molto specifici per il contesto italiano, quando i sistemi esistenti (SPID, pagoPA) già soddisfano i tuoi requisiti senza il sovraccarico di astrazione aggiuntiva, o quando hai risorse limitate per gestire la complessità di una federazione distribuita.

Conclusioni: la Serie GovTech in Prospettiva

Questo articolo chiude la serie GovTech dedicata alla digitalizzazione della pubblica amministrazione. Abbiamo esplorato l'ecosistema completo: dalle infrastrutture digitali pubbliche (DPI) all'identità europea (eIDAS 2.0, EUDI Wallet), dall'implementazione concreta di SPID e CIE alla protezione dei dati (GDPR-by-Design), dall'accessibilità (WCAG 2.1 AA) agli open data (DCAT-AP_IT, CKAN) fino ai framework modulari internazionali (GovStack).

Il filo conduttore è sempre lo stesso: i servizi digitali pubblici devono essere inclusivi, sicuri, interoperabili e riutilizzabili. GovStack, con i suoi Building Block standardizzati, offre un vocabolario comune e un modello architetturale condiviso per raggiungere questi obiettivi su scala globale.

Tutta la Serie GovTech

  • #00: Digital Public Infrastructure - Architettura e Building Block
  • #01: eIDAS 2.0 e EUDI Wallet - Developer Guide
  • #02: OpenID Connect per Identità Governativa
  • #03: Open Data API Design - Pubblicare e Consumare Dati Pubblici
  • #04: GDPR-by-Design - Pattern Architetturali per Servizi Pubblici
  • #05: UI Accessibili per la PA - Implementazione WCAG 2.1 AA
  • #06: Integrazione API Governative - SPID, CIE e Servizi Digitali IT
  • #07: GovStack Building Block - (questo articolo)

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti