GovStack: modułowe ramy dla administracji cyfrowej

GovStack to międzynarodowa inicjatywa zapoczątkowana w 2020 roku przez Estonia, Niemcy, ITU (Międzynarodowy Związek Telekomunikacyjny) e DIAL (Sojusz na rzecz Digital Impact) z celem jest dzielenie się narzędziami, wiedzą i najlepszymi praktykami potrzebnymi do budowania usług odbiorców cyfrowych na dużą skalę, bez konieczności zaczynania za każdym razem od zera.

Podstawowa idea jest prosta, ale potężna: zamiast opracowywać monolityczne systemy dla każdego kraju rządowa usługa cyfrowa jest podzielona na Blok konstrukcyjny (moduły funkcjonalne), które oferują określone możliwości (tożsamość, płatności, przesyłanie wiadomości, rejestry itp.) i to można je dowolnie łączyć, budując dowolną usługę. Bloki konstrukcyjne są interoperacyjne, nadające się do ponownego użycia i niezależne od wdrożenia: GovStack definiuje specyfikacje, a nie oprogramowanie.

W 2025 r., wraz z uruchomieniem Specyfikacje Gov 2.0 (strategia na lata 2025-2027), GovStack udoskonalił ramy poprzez integrację nowych elementów składowych, aktualizację specyfikacji interoperacyjności i zdefiniowanie wielopoziomowy model dojrzałości wspierający kraje o dużym potencjale cyfrowym inny. Ponad 20 krajów aktywnie korzysta z podejścia GovStack.

Czego się nauczysz

  • 9 podstawowych elementów składowych GovStack i ich specyfikacje techniczne
  • Jak zmapować istniejące włoskie usługi PA (SPID, CIE, pagoPA) na GovStack Building Blocks
  • Architektura referencyjna GovStack: model warstwowy i szyna integracyjna
  • GovSpecs 2.0: co nowego w strategii na lata 2025-2027
  • Praktyczna implementacja tożsamości blokowej za pomocą OpenID Connect
  • Building Block Payments: integracja z krajowymi systemami płatności
  • Element konstrukcyjny zgody: zarządzanie zgodami zgodnymi z RODO
  • Jak ocenić, czy GovStack jest odpowiedni dla Twojego kontekstu

9 podstawowych elementów składowych

GovStack definiuje 9 podstawowych elementów (opublikowanych w nowej specyfikacji 2025), które obejmują wielofunkcyjności niezbędne dla każdej cyfrowej usługi rządowej:

Blok konstrukcyjny Funkcjonować Protokoły/Standardy Przykład włoski
Tożsamość Uwierzytelnianie i zarządzanie tożsamością OIDC, SAML, W3C DID Portfel SPID, CIE, EUDI
Płatności Przetwarzanie płatności i przelewów ISO 20022, API REST payPA
Zgoda Gromadzenie i zarządzanie zgodami Zakresy RODO, DPIA, OAuth CMP z RODO na etapie projektowania
Rejestry cyfrowe Zarządzanie miarodajnymi rejestrami (urząd stanu cywilnego, księga wieczysta) REST API, FHIR, CKAN ANPR, rejestr gruntów, rejestr zawodowy
Wiadomości Bezpieczna komunikacja między rządem a obywatelami SMTP, Push, WebSocket, MQTT Aplikacja IO, powiadomienia PEC, pagoPA
Mediacja Informacyjna Bezpieczna wymiana danych pomiędzy systemami X-Road, REST, GraphQL Interoperacyjność PDND, AgID
Rejestracja Rejestracja osób/podmiotów na usługi REST API, OAuth 2.0 Portal INPS, SUAP, portale miejskie
Harmonogram Zarządzanie terminami i rezerwacjami iCalendar, API REST Kubek zdrowia, licznik cyfrowy
Przepływ pracy Orkiestracja procesów i procedur BPMN, wzór SAGA, REST Systemy zarządzania praktyką PA

Architektura referencyjna GovStack

GovStack proponuje architekturę warstwową, w której bloki konstrukcyjne są umieszczane w warstwach wyróżnia się jasnymi obowiązkami:

  • Warstwa 0 – Infrastruktura: chmura, sieć, bezpieczeństwo. Kulki nie są zależne od konkretnej chmury; mogą działać na infrastrukturze AWS, Azure, GCP lub lokalnie.
  • Warstwa 1 – Podstawowe bloki konstrukcyjne: 9 podstawowych kulek. Są to autonomiczne usługi, które ujawniają Standaryzowane interfejsy API RESTful. Każdy BB ma publiczną specyfikację (schematy OpenAPI + JSON).
  • Warstwa 2 — usługi wspólne: usługi przekrojowe, takie jak scentralizowane logowanie, siatka usług, Brama API, wykrywanie usług. Usługi te obsługują wszystkie BB.
  • Warstwa 3 – Aplikacje: rzeczywiste usługi cyfrowe (zapisy do szkół, wniosek o wydanie certyfikatu, opłata skarbowa), które koordynują bazowe BB.
# 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: Co nowego w Strategii na lata 2025-2027

Specyfikacje Gov 2.0, ogłoszony przez GovStack w 2025 r., wprowadza ważne aktualizacje w porównaniu do poprzedniej wersji specyfikacji:

  • Czterostopniowy model dojrzałości: z „Fazy początkowej” (tylko szkolenia i architektura wysoki poziom) do „zaawansowanej integracji” (wiele BB zintegrowanych z krajowymi ramami interoperacyjności). Umożliwia to krajom przyjęcie GovStack zgodnie z ich własnymi priorytetami i możliwościami.
  • Wsparcie dla weryfikowalnych poświadczeń: Building Block Identity zawiera teraz specyfikacje dla Weryfikowalne poświadczenia W3C, zgodne z eIDAS 2.0 i europejskim programem portfela EUDI.
  • DO BB: nowy moduł konstrukcyjny do integracji komponentów AI (modele językowe, przewidywanie, klasyfikacja) w służbach rządowych, zwracając uwagę na przejrzystość i wyjaśnialność.
  • Specyfikacje OpenAPI 3.1: Wszystkie interfejsy API BB są teraz udokumentowane w OpenAPI 3.1, z Kompletne schematy JSON i testowalne przykłady za pośrednictwem SwaggerUI.
  • Testowanie zgodności: Zautomatyzowana platforma do sprawdzania, czy implementacja BB jest zgodny ze specyfikacjami GovStack.

Implementacja tożsamości blokowej za pomocą OIDC

Tożsamość bloku konstrukcyjnego jest najbardziej krytyczna i najbardziej złożona do wdrożenia. GovStack określa, że ​​musi udostępniać następujące interfejsy 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)

Wiadomości blokowe: aplikacja IO i powiadomienia rządowe

Building Block Messaging zarządza komunikacją między rządem a obywatelami. We Włoszech usługa bardziej zgodny ze specyfikacją GovStack Messaging I aplikacja (io.italia.it), ogólnokrajowa aplikacja do komunikacji z PA zarządzana przez 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)

Mapa GovStack we włoskim ekosystemie

Włochy mają już zaawansowany ekosystem ŚOI, który w naturalny sposób odwzorowuje się na blokach konstrukcyjnych GovStack. Dla włoskiego programisty przyjęcie GovStack nie oznacza zaczynania od zera: oznacza to zreorganizować istniejące integracje według ustandaryzowanego modelu modułowego.

BB GovStack Realizacja włoska Poziom dojrzałości Luka do wypełnienia
Tożsamość SPID, CIE, eIDAS Wysoki (poziom 3-4) Pełna unifikacja OIDC, portfel EUDI
Płatności payPA Wysoki (poziom 4) Kompletne API REST GPD
Wiadomości Aplikacja IO, PEC Wysoki (poziom 3) Penetracja aplikacji IO (w niektórych obszarach wciąż niska)
Rejestry cyfrowe ANPR, rejestr gruntów, PDND Średni (poziom 2-3) Interoperacyjność między rejestrami jest nadal częściowa
Mediacja Informacyjna PDND Średni (poziom 2) Popularność PDND wciąż rośnie
Zgoda Różne (niestandaryzowane) Niski (poziom 1) Potrzebujemy scentralizowanej platformy konsensusu
Harmonogram Regionalny Puchar Zdrowia Niski-Średni (poziom 1-2) fragmentacja regionalna; brak normy krajowej
Przepływ pracy Systemy ćwiczeń PA (heterogeniczne) Niski (poziom 1) Duża różnorodność; potrzebna jest standaryzacja

Kiedy zastosować GovStack

GovStack jest szczególnie odpowiedni, gdy:

  • Budujesz nowa usługa cyfrowa PA od zera i chcą uniknąć zależności od dostawców
  • Musisz zintegrować istniejące systemy i potrzebujesz wspólnego referencyjnego modelu architektonicznego
  • Działasz w kontekście wielokrajowy (współpraca międzynarodowa, usługi transgraniczne)
  • Chcesz wnieść swój wkład w ekosystem open source GovStack i korzystać z wdrożeń w innych krajach

GovStack jest mniej odpowiedni, gdy masz bardzo specyficzne usługi dla kontekstu włoskiego, gdy są to systemy istniejące (SPID, pagoPA) już spełniają Twoje wymagania bez narzutu dodatkowej abstrakcji, lub gdy masz ograniczone zasoby do zarządzania złożonością rozproszonej federacji.

Wniosek: Seria GovTech z perspektywy

Artykuł ten zamyka cykl GovTech poświęcony cyfryzacji administracji publicznej. Zbadaliśmy cały ekosystem: od publicznej infrastruktury cyfrowej (DPI) po tożsamość Unia Europejska (eIDAS 2.0, EUDI Wallet), od konkretnego wdrożenia SPID i CIE po ochronę danych (RODO-by-Design), od dostępności (WCAG 2.1 AA) po otwarte dane (DCAT-AP_IT, CKAN) aż do międzynarodowe ramy modułowe (GovStack).

Wspólny wątek jest zawsze ten sam: publiczne usługi cyfrowe muszą takie być włącznie, bezpieczne, interoperacyjne i nadające się do ponownego użycia. GovStack ze swoimi ustandaryzowanymi blokami konstrukcyjnymi zapewnia wspólne słownictwo i wspólny model architektoniczny, aby osiągnąć te cele w skali globalnej.

Cała seria GovTech

  • #00: Cyfrowa infrastruktura publiczna - architektura i elementy konstrukcyjne
  • #01: eIDAS 2.0 i portfel EUDI - Przewodnik programisty
  • #02: OpenID Connect dla tożsamości rządowej
  • #03: Projektowanie API otwartych danych - publikuj i korzystaj z danych publicznych
  • #04: RODO-by-Design - Wzorce architektoniczne dla usług publicznych
  • #05: Dostępny interfejs użytkownika dla implementacji PA - WCAG 2.1 AA
  • #06: Integracja rządowych interfejsów API - usługi cyfrowe SPID, CIE i IT
  • #07: Blok konstrukcyjny GovStack — (ten artykuł)