Il tuo primo import, da un capo all'altro
La panoramica ti lascia un motore sano. Questa pagina è il resto delle prime due ore: entra un file, qualcuno lo rivede, e righe firmate arrivano sul tuo backend.
Non scrivi una UI di mapping e non dichiari lo schema nel codice host. Lo schema è un catalogo pubblicato. Il widget lo carica. Apply è un webhook firmato — è il default.
your page Mildport engine your backend ───────── ─────────────── ──────────── <mildport-import ingest → match → review catalog-key="crm"> ─────────► ─────────► POST /apply HMAC-signed rows1. Chiavi dal tuo account
Sezione intitolata “1. Chiavi dal tuo account”Servono due valori, entrambi dal tuo account Mildport:
| Cosa | Dove | Dove va |
|---|---|---|
| Chiave di licenza | Licenze — una volta all’emissione | license-key del widget |
| Chiave pubblica | Self-hosting (IMPORT_LICENSE_PUBLIC_KEY) |
il motore, già, se il preflight della panoramica è passato |
Conferma che il motore accetti la chiave:
curl -H "Authorization: Bearer $LICENSE" \ https://imports.your-infra.example/api/import/v1/license/verifyUna buona risposta è "verified": true. Qualsiasi altra cosa — vedi
Risoluzione dei problemi di deployment.
2. Pubblica un catalogo, poi incorporalo
Sezione intitolata “2. Pubblica un catalogo, poi incorporalo”Lo schema vive nell’editor dei cataloghi — /admin/catalogs
sul motore, o <mildport-catalog-editor> nel tuo admin. Bozza i campi da una spec OpenAPI o
un record di esempio, marca required quelli che la tua API rifiuterebbe vuoti, e
pubblica. Dai al catalogo una chiave stabile (crm, contacts, …).
Fissa quella chiave sul widget. I cambi di schema dopo sono un publish nell’editor, non un release dell’host:
<mildport-import api-base-url="https://imports.your-infra.example" license-key="SIGNED_TENANT_KEY" catalog-key="crm"></mildport-import>Un catalogo pubblicato e niente catalog-key va bene lo stesso — il widget lo adotta da
solo. Fissa la chiave quando una pagina deve sempre importare in uno schema specifico.
Schema calcolato per utente a runtime, o versionato con l’app? È il percorso schema-come-codice. Saltalo finché non hai un motivo.
3. Registrare il webhook di apply
Sezione intitolata “3. Registrare il webhook di apply”Apply è di default un POST firmato al tuo backend. Registra l’URL una volta; la risposta porta il segreto di firma esattamente una volta — conservalo.
curl -X POST https://imports.your-infra.example/api/import/v1/webhooks \ -H "Authorization: Bearer $LICENSE" \ -H "Content-Type: application/json" \ -d '{ "url": "https://api.your-app.example/mildport/apply" }'Una prima occhiata senza backend? el.applyMode = 'browser' e leggi le righe da
onResults. La produzione è il webhook. Dettagli: Eventi e apply e il
riferimento webhook.
4. Eseguire un import
Sezione intitolata “4. Eseguire un import”Apri la pagina, lascia un CSV (o un foglio disordinato, o un PDF con una tabella), conferma il mapping suggerito, sistema ciò che la griglia di review segnala, e apply.
Il widget parla con il motore per ingest e mapping. Non chiami ingest tu stesso, salvo costruire un flusso headless, senza widget.
5. Verificare la firma, poi scrivere
Sezione intitolata “5. Verificare la firma, poi scrivere”Ogni consegna è firmata HMAC. Verifica il body grezzo prima di fidarti, rifiuta i
timestamp stantii, e deduplica su x-import-delivery-id — i retry sono normali.
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(rawBody: string, header: string, secret: string): boolean { const parts = Object.fromEntries(header.split(',').map(kv => kv.split('='))); const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex'); const got = Buffer.from(parts.v1 ?? '', 'hex'); const exp = Buffer.from(expected, 'hex'); return got.length === exp.length && timingSafeEqual(got, exp);}Il body sono righe nella forma del catalogo (contact.email, …) più un mapping. Restituisci
2xx quando le hai persistite. Un 4xx è terminale; un 5xx viene ritentato. Payload e
header: Webhook di apply.
6. Confermare che ha funzionato
Sezione intitolata “6. Confermare che ha funzionato”- Il widget ha emesso
import-appliedcon unrowCount. - Il tuo handler ha loggato un
deliveryIde scritto altrettante righe. - Una seconda consegna con lo stesso id è un no-op dal tuo lato.
Bloccato? Risoluzione dei problemi di deployment copre immagini che non fanno pull, 401 di licenza, CORS, e un pod che non diventa mai Ready.
Avanti: Configurazione · Licenze · Cataloghi