Files
PecHub/docs/aeterna-api.md
T
2026-06-18 11:24:05 +02:00

15 KiB
Raw Blame History

Integrazione Aeterna Archiviazione Sostitutiva PecHub

Documento tecnico sull'integrazione di PecHub con Aeterna, piattaforma di conservazione digitale conforme E-ARK gestita da Idra Informatica.


Indice

  1. Panoramica del provider
  2. Architettura Aeterna
  3. Autenticazione JWT
  4. Ingest Upload SIP
  5. Formato SIP BagIt (RFC 8493)
  6. Polling stato ingest
  7. Disseminazione (DIP)
  8. Mapping stati Aeterna → PecHub
  9. Configurazione in PecHub
  10. Esempi curl completi
  11. Note operative

1. Panoramica del provider

Campo Valore
Provider Idra Informatica srl
Piattaforma Aeterna v0.1.0
URL applicazione https://aeterna.idrainformatica.it
Endpoint API https://api.aeterna.idrainformatica.it
Documentazione https://api.aeterna.idrainformatica.it/docs
OpenAPI JSON https://api.aeterna.idrainformatica.it/openapi.json
Standard E-ARK CSIP 2.1.0, BagIt RFC 8493, PREMIS 3.0, METS 1.12

Credenziali tenant PecHub

Campo Valore
Org. name pechub
Tenant slug pechub
Username matteo@idrainformatica.it
Password (cifrata nel DB PecHub)
Tenant ID 366d3d51-b25d-46fc-8f9c-9bc28d902620

2. Architettura Aeterna

Aeterna e' una piattaforma multi-tenant FastAPI (Python). Ogni organizzazione (tenant) ha:

  • Container MinIO dedicato per lo storage isolato
  • Collection Apache Solr dedicata per la ricerca full-text
  • RBAC (Role-Based Access Control) per-tenant

Il ciclo di vita di un documento archiviale in Aeterna:

SIP (upload)  →  AIP (ingest pipeline)  →  DIP (disseminazione)
     |                    |                        |
  BagIt ZIP         PREMIS events           ZIP scaricabile
  multipart      METS 1.12 generato
  form-data      validazione E-ARK

3. Autenticazione JWT

Aeterna usa JWT Bearer token, NON HTTP Basic. Il token ha durata 3600 secondi (1 ora). Esiste un refresh token.

Login

POST /api/v1/auth/login
Content-Type: application/json

Body:

{
  "email": "matteo@idrainformatica.it",
  "password": "...",
  "tenant_slug": "pechub"
}

Risposta 200:

{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 3600,
  "user": {
    "id": "e3cac60b-d942-4590-94fe-932c0e14e836",
    "email": "matteo@idrainformatica.it",
    "full_name": "Matteo Giustini",
    "is_platform_admin": false,
    "tenant_id": "366d3d51-b25d-46fc-8f9c-9bc28d902620",
    "permissions": [
      "ingest:submit", "ingest:manage", "packages:read",
      "packages:create", "dissemination:read", "dissemination:download",
      "preservation:manage", "audit:read", "settings:manage", ...
    ]
  }
}

Utilizzo del token nelle richieste successive:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Refresh token

POST /api/v1/auth/refresh
Content-Type: application/json

{"refresh_token": "eyJhbGciOiJIUzI1NiIs..."}

Verifica identita'

GET /api/v1/auth/me
Authorization: Bearer <token>

4. Ingest Upload SIP

L'endpoint di ingest accetta pacchetti SIP in due formati:

  • E-ARK CSIP v2.2.0 (ZIP con METS.xml in root)
  • BagIt RFC 8493 (ZIP con bagit.txt + data/) — formato scelto per PecHub

Endpoint

POST /api/v1/ingest/upload
Authorization: Bearer <token>
Content-Type: multipart/form-data

Campi form-data

Campo Tipo Obbligatorio Descrizione
file file si ZIP SIP (E-ARK CSIP o BagIt)
title string si Titolo del pacchetto
description string no Descrizione
creator string no Nome del produttore
submission_agreement string no ID o URL dell'accordo di versamento
ead3_file file no EAD3 finding aid XML (GAP-09)
eac_cpf_file file no EAC-CPF authority record XML

Risposta 202 Accepted

{
  "package_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "pid": "urn:pechub:aip:a1b2c3d4",
  "status": "UPLOADED",
  "task_id": "celery-task-uuid",
  "message": "SIP uploaded successfully. Processing started.",
  "submitted_at": "2026-06-18T09:00:00Z"
}

Il package_id e' l'identificatore da usare per polling e DIP.


5. Formato SIP BagIt (RFC 8493)

PecHub costruisce pacchetti BagIt in memoria (build_bagit_sip in conservatore_client.py).

Struttura ZIP generata

pechub-pec-{message_id}/
    bagit.txt               # Dichiarazione BagIt (obbligatorio)
    bag-info.txt            # Metadati descrittivi (opzionale)
    manifest-sha256.txt     # Checksum SHA-256 dei file in data/
    data/
        {message_id}.eml    # Messaggio PEC grezzo

Contenuto bagit.txt

BagIt-Version: 1.0
Tag-File-Character-Encoding: UTF-8

Contenuto bag-info.txt (esempio)

Bag-Software-Agent: PecHub Archival Module
Bagging-Date: 2026-06-18
External-Identifier: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Source-Organization: PecHub
Description: PEC oggetto del messaggio (max 500 char)
Contact-Email: mittente@pec.it
External-Description: PEC a destinatario@pec.it
Bag-Group-Identifier: 2026-06-18

Contenuto manifest-sha256.txt

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  data/a1b2c3d4-e5f6.eml

Rilevamento automatico BagIt da Aeterna

Aeterna rileva automaticamente il formato BagIt dalla presenza di bagit.txt nella root del bag all'interno dello ZIP. Non e' necessario specificare il formato. La pipeline verifica i checksum del manifest prima dell'ingest.


6. Polling stato ingest

Dopo l'upload, la pipeline di Aeterna processa il pacchetto in modo asincrono.

Endpoint status

GET /api/v1/ingest/{package_id}/status
Authorization: Bearer <token>

Risposta

{
  "package_id": "a1b2c3d4-...",
  "pid": "urn:pechub:aip:a1b2c3d4",
  "status": "PROCESSING",
  "task_id": "celery-task-uuid",
  "pipeline_stage": "format_identification",
  "progress_pct": 40,
  "steps": [
    {"name": "validation", "status": "completed", ...},
    {"name": "format_identification", "status": "running", ...},
    {"name": "virus_scan", "status": "pending", ...}
  ],
  "is_valid": null,
  "validation_errors": 0,
  "error_message": null,
  "submitted_at": "2026-06-18T09:00:00Z",
  "completed_at": null
}

Stati possibili

Status Aeterna Significato Stato PecHub
UPLOADED SIP ricevuto, elaborazione non iniziata uploading
VALIDATING Validazione E-ARK/BagIt in corso uploading
PROCESSING Pipeline ingest in corso uploading
INGESTING AIP in fase di creazione uploading
ACTIVE AIP attivo, conservazione completata confirmed
FAILED Pipeline fallita con errori failed
REJECTED Pacchetto non conforme agli standard rejected
DELETED Soft-delete rejected

Report completo

GET /api/v1/ingest/{package_id}/report
Authorization: Bearer <token>

7. Disseminazione (DIP)

Richiesta generazione DIP

POST /api/v1/packages/{package_id}/disseminate
Authorization: Bearer <token>
Content-Type: application/json

{"note": "Richiesto da PecHub Archival Module"}

Risposta 202:

{
  "id": "dip-uuid",
  "pid": "urn:pechub:dip:...",
  "status": "PROCESSING",
  "size_bytes": null,
  "is_available": false
}

Verifica stato DIP

GET /api/v1/packages/{package_id}/dip
Authorization: Bearer <token>

Quando is_available: true, il DIP e' scaricabile.

Download DIP

GET /api/v1/packages/{package_id}/dip/download
Authorization: Bearer <token>

Risposta: stream ZIP del DIP.


8. Mapping stati Aeterna → PecHub

_STATUS_MAP = {
    "UPLOADED":   "uploading",
    "VALIDATING": "uploading",
    "PROCESSING": "uploading",
    "INGESTING":  "uploading",
    "ACTIVE":     "confirmed",   # conservazione completata
    "FAILED":     "failed",
    "REJECTED":   "rejected",
    "DELETED":    "rejected",
}

Il versamento_id in PecHub corrisponde al package_id di Aeterna (UUID v4).


9. Configurazione in PecHub

Impostazioni tenant

Dalla pagina Impostazioni → Archiviazione Sostitutiva:

Campo Valore per Aeterna
Modalita' Produzione
Identificativo conservatore aeterna
URL endpoint API https://api.aeterna.idrainformatica.it
Tenant Slug pechub
Username matteo@idrainformatica.it
Password (da fornire, viene cifrata AES-256-GCM)

Riconoscimento automatico del provider

Il factory ConservatoreClient.from_tenant_credentials() rileva Aeterna se:

  • conservatore_id == "aeterna" (case-insensitive), OPPURE
  • "aeterna" e' presente nell'URL endpoint, OPPURE
  • "idrainformatica" e' presente nell'URL endpoint

Se rilevato come Aeterna, usa AeternaConservatoreClient (JWT + BagIt). Altrimenti usa ProductionConservatoreClient (HTTP Basic, standard AgID legacy).

Test connessione

Dopo aver configurato e salvato le impostazioni, usare il pulsante "Testa connessione" in Impostazioni → Archiviazione Sostitutiva.

Oppure via API:

POST /api/v1/settings/test-conservatore
Authorization: Bearer <pechub-token>

Risposta:

{
  "success": true,
  "message": "Connessione ad Aeterna riuscita (utente: matteo@idrainformatica.it)",
  "latency_ms": 342,
  "provider_info": {
    "platform": "Aeterna",
    "tenant_slug": "pechub",
    "user_email": "matteo@idrainformatica.it",
    "permissions_count": 20
  }
}

10. Esempi curl completi

Login

TOKEN=$(curl -s -X POST https://api.aeterna.idrainformatica.it/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"matteo@idrainformatica.it","password":"...","tenant_slug":"pechub"}' \
  | jq -r .access_token)
echo "Token: $TOKEN"

Upload SIP BagIt

# Crea un BagIt minimo di test
mkdir -p /tmp/testbag/data
echo "Hello PEC" > /tmp/testbag/data/test.eml
SHA=$(sha256sum /tmp/testbag/data/test.eml | awk '{print $1}')

cat > /tmp/testbag/bagit.txt <<EOF
BagIt-Version: 1.0
Tag-File-Character-Encoding: UTF-8
EOF

cat > /tmp/testbag/manifest-sha256.txt <<EOF
$SHA  data/test.eml
EOF

# ZIP del bag
cd /tmp && zip -r testbag.zip testbag/

# Upload
curl -s -X POST https://api.aeterna.idrainformatica.it/api/v1/ingest/upload \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@/tmp/testbag.zip;type=application/zip" \
  -F "title=Test PEC da PecHub" \
  -F "description=Messaggio di test" \
  -F "creator=PecHub" \
  | jq .

Polling status

PACKAGE_ID="a1b2c3d4-e5f6-7890-abcd-ef1234567890"

curl -s https://api.aeterna.idrainformatica.it/api/v1/ingest/$PACKAGE_ID/status \
  -H "Authorization: Bearer $TOKEN" \
  | jq '{status:.status, stage:.pipeline_stage, pct:.progress_pct}'

Lista pacchetti

curl -s "https://api.aeterna.idrainformatica.it/api/v1/packages?limit=10" \
  -H "Authorization: Bearer $TOKEN" \
  | jq '.items[] | {id:.id, title:.title, status:.status}'

Report ingest

curl -s https://api.aeterna.idrainformatica.it/api/v1/ingest/$PACKAGE_ID/report \
  -H "Authorization: Bearer $TOKEN" \
  | jq .

Richiesta DIP

curl -s -X POST \
  "https://api.aeterna.idrainformatica.it/api/v1/packages/$PACKAGE_ID/disseminate" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"note":"Richiesto da PecHub"}' \
  | jq .

Download DIP

curl -L -o /tmp/dip.zip \
  "https://api.aeterna.idrainformatica.it/api/v1/packages/$PACKAGE_ID/dip/download" \
  -H "Authorization: Bearer $TOKEN"

11. Note operative

Dimensione pacchetti

Non ci sono limiti documentati. I file EML di PEC sono tipicamente 10-500 KB. Il timeout HTTP nel client e' impostato a 120 secondi per l'upload.

Concorrenza

Ogni AeternaConservatoreClient gestisce il token JWT in memoria. Se il worker usa piu' istanze concorrenti, ogni istanza effettua il suo login. Il token dura 3600s, il rinnovo automatico avviene 60s prima della scadenza.

Retry policy

In caso di fallimento dell'upload, il batch ArchivalBatch in PecHub ha max_attempts=3 e un next_retry_at con back-off esponenziale.

Standard di riferimento

  • E-ARK CSIP v2.1.0 — Common Specification for Information Packages
  • E-ARK SIP/AIP/DIP — Submission/Archival/Dissemination Information Package
  • BagIt RFC 8493 — formato file standard per trasferimento dati
  • PREMIS 3.0 — metadati di preservazione
  • METS 1.12 — Metadata Encoding and Transmission Standard
  • Dublin Core / EAD — metadati descrittivi

Codice sorgente rilevante

File Descrizione
worker/app/archival/conservatore_client.py Client completo con AeternaConservatoreClient, BagIt builder, factory
worker/scripts/test_aeterna_transmission.py Script di test standalone
backend/app/api/v1/settings.py Endpoint test-conservatore
backend/app/models/tenant_settings.py Modello DB con conservatore_tenant_slug
backend/app/services/tenant_settings_service.py Servizio credenziali
backend/alembic/versions/0020_add_conservatore_tenant_slug.py Migrazione DB
frontend/src/pages/Settings/SettingsPage.tsx UI configurazione conservatore
frontend/src/api/settings.api.ts Client API frontend

Esecuzione script di test

# Dal server, dentro il container worker
docker exec -it pechub-worker-1 \
  python /app/scripts/test_aeterna_transmission.py

# I risultati vengono salvati in /tmp/aeterna_test_results.json

Documento generato il 2026-06-18. Versione Aeterna: 0.1.0.