Votre premier import, de bout en bout
La vue d’ensemble vous laisse un moteur sain. Cette page est le reste des deux premières heures : un fichier entre, quelqu’un le relit, et des lignes signées arrivent sur votre backend.
Vous n’écrivez pas d’UI de mapping et vous ne déclarez pas le schéma dans le code hôte. Le schéma est un catalogue publié. Le widget le charge. Apply est un webhook signé — c’est le défaut.
your page Mildport engine your backend ───────── ─────────────── ──────────── <mildport-import ingest → match → review catalog-key="crm"> ─────────► ─────────► POST /apply HMAC-signed rows1. Clés depuis votre compte
Section intitulée « 1. Clés depuis votre compte »Deux valeurs, toutes deux depuis votre compte Mildport :
| Quoi | Où | Où ça va |
|---|---|---|
| Clé de licence | Licences — une fois à l’émission | license-key du widget |
| Clé publique | Self-hosting (IMPORT_LICENSE_PUBLIC_KEY) |
le moteur, déjà, si le preflight de la vue d’ensemble a passé |
Confirmez que le moteur accepte la clé :
curl -H "Authorization: Bearer $LICENSE" \ https://imports.your-infra.example/api/import/v1/license/verifyUne bonne réponse est "verified": true. Tout le reste — voir
Dépannage de déploiement.
2. Publier un catalogue, puis l’embarquer
Section intitulée « 2. Publier un catalogue, puis l’embarquer »Le schéma vit dans l’éditeur de catalogues — /admin/catalogs
sur votre moteur, ou <mildport-catalog-editor> dans votre propre admin. Rédigez les champs
depuis une spec OpenAPI ou un enregistrement d’exemple, marquez required ceux que votre
API rejetterait vides, et publiez. Donnez au catalogue une clé stable (crm,
contacts, …).
Épinglez cette clé sur le widget. Les changements de schéma après ça sont un publish dans l’éditeur, pas un release hôte :
<mildport-import api-base-url="https://imports.your-infra.example" license-key="SIGNED_TENANT_KEY" catalog-key="crm"></mildport-import>Un catalogue publié et pas de catalog-key, ça va aussi — le widget l’adopte tout seul.
Épinglez la clé quand une page doit toujours importer dans un schéma précis.
Schéma calculé par utilisateur à l’exécution, ou versionné avec votre app ? C’est le chemin schéma-en-code. Passez-le tant que vous n’avez pas une raison.
3. Enregistrer le webhook d’apply
Section intitulée « 3. Enregistrer le webhook d’apply »Apply est par défaut un POST signé vers votre backend. Enregistrez l’URL une fois ; la réponse porte le secret de signature exactement une fois — stockez-le.
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" }'Un premier regard sans backend ? el.applyMode = 'browser' et lisez les lignes depuis
onResults. La production, c’est le webhook. Détails : Événements et apply
et la référence webhook.
4. Lancer un import
Section intitulée « 4. Lancer un import »Ouvrez la page, déposez un CSV (ou un tableur brouillon, ou un PDF avec un tableau), confirmez le mapping proposé, corrigez ce que la grille de revue signale, et apply.
Le widget parle à votre moteur pour l’ingest et le mapping. Vous n’appelez pas l’ingest vous-même, sauf à construire un flux headless, sans widget.
5. Vérifier la signature, puis écrire
Section intitulée « 5. Vérifier la signature, puis écrire »Chaque livraison est signée HMAC. Vérifiez le corps brut avant de lui faire confiance,
rejetez les horodatages trop vieux, et dédupliquez sur x-import-delivery-id — les retries
sont normaux.
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);}Le corps, ce sont des lignes à la forme de votre catalogue (contact.email, …) plus un
mapping. Renvoyez 2xx quand vous les avez persistées. Un 4xx est terminal ; un 5xx
est retenté. Payload et en-têtes : Webhooks d’apply.
6. Confirmer que ça a marché
Section intitulée « 6. Confirmer que ça a marché »- Le widget a émis
import-appliedavec unrowCount. - Votre handler a journalisé un
deliveryIdet écrit autant de lignes. - Une deuxième livraison avec le même id est un no-op de votre côté.
Bloqué ? Dépannage de déploiement couvre les images qui ne pullent pas, les 401 de licence, le CORS, et un pod qui ne devient jamais Ready.
Suite : Configuration · Licences · Catalogues