ADS-B aéronefs militaires — exemple de source de données
Installez une source de données déclarative via un Scrydon extension, synchronisez-la et exploitez-la depuis Analytics → Sources de données — historique de synchronisation, rétention en direct, table sous-jacente et suppression. Exemple ADS-B complet avec les parcours UI et développeur.
Téléchargements
Les deux fichiers sont générés par le script de build de la documentation (apps/docs/scripts/build-extension-examples.ts) à partir d'un manifeste source unique situé à apps/docs/examples/scrydon-extension-adsb-aircraft/manifest.ts. Ils sont régénérés à chaque bun run dev / bun run build de l'application de documentation — ce sont les mêmes octets, simplement deux formes de distribution pour la même source de données.
| Fichier | Utilisation |
|---|---|
| 📦 scrydon-extension-adsb-aircraft.scrydon-extension.tar.gz | Recommandé — installation via l'interface. Deux étapes : un administrateur d'organisation admet l'extension dans Paramètres → Plateforme → Extensions (catalogue uniquement — rien n'est encore matérialisé) ; un utilisateur de l'espace de travail le sélectionne dans Analytics → Marketplace pour instancier la source de données dans son environnement. |
| 📥 adsb-lol-military-declarative.json | Appliquez directement le manifeste déclaratif brut via curl vers POST /api/table/data-sources/apply — le parcours développeur qui contourne l'enveloppe extension. Utile pour les tests scriptés. |
Chemin A — installation via l'interface (recommandé)
L'installation d'une extension se déroule en deux étapes par conception — voir ADR 2026-05-30 pour la justification. L'étape 1 catalogue l'extension au niveau de l'organisation ; l'étape 2 instancie la source de données dans un environnement d'espace de travail.
Étape 1 — L'administrateur d'organisation télécharge l'extension
- En tant qu'administrateur d'organisation, ouvrez Paramètres → Plateforme → Extensions → Sources et cliquez sur Téléverser une extension (ponctuel).
- Déposez le fichier
scrydon-extension-adsb-aircraft.scrydon-extension.tar.gztéléchargé sur la zone de dépôt (ou cliquez pour le sélectionner). La boîte de dialogue affiche l'id de l'extensionscrydon-extension-adsb-aircraft, la version1.0.0et un résumé de contribution en une ligne : 1 source de données. - Cochez Je comprends que cette extension n'est pas signé… et cliquez sur Télécharger. L'extension est admis dans le catalogue de l'organisation. Aucune ligne
data_sourcen'est encore créée — les extensions contenant uniquement des sources de données reportent la matérialisation à l'étape 2 (le téléversement se termine silencieusement et l'extension apparaît dans Analytics → Marketplace).
Étape 2 — L'utilisateur de l'espace de travail instancie la source de données
- En tant qu'utilisateur de l'espace de travail, ouvrez
apps/analyticset confirmez qu'un espace de travail et un environnement sont sélectionnés (sélecteur en haut à droite). - Ouvrez Extensions dans la barre latérale. La carte
scrydon-extension-adsb-aircraftapparaît avec un unique bouton Installer (l'extension contient exactement une source de données qui n'est pas encore présente dans cet environnement). - Cliquez sur Installer. La plateforme planifie cette unique version de source de données, l'autorise, puis l'applique → api-table enregistre une ligne dans
data_sourcelimitée à votre environnement. - Ouvrez Sources de données dans la barre latérale — la nouvelle ligne apparaît avec Source :
adsb-lol-military-declarative, Fournisseur :adsb-lol, Intervalle : 60s, Statut :En attente. - Ouvrez le menu d'actions de la ligne et cliquez sur Synchroniser maintenant. Attendez-vous à une notification verte avec le nombre de lignes écrites ; le Statut passe à
Sainet la Dernière synchronisation s'affiche après l'actualisation automatique.
Le parcours d'installation via la extensions atteint le même endpoint d'application api-table via le domaine propriétaire des sources de données, de sorte que les installations ultérieures du même extension dans des environnements différents produisent des lignes identiques.
Chemin B — appliquer le JSON directement (développeur)
Ignorez l'outillage de création de extension et appliquez directement le manifeste brut à l'endpoint interne /data-sources/apply d'api-table. Cela emprunte le même chemin de code que le hook installDataSource du chemin A — les deux convergent vers POST /api/table/data-sources/apply.
Il s'agit de l'exercice de bout en bout le plus rapide pour :
- le domaine des sources de données api-table (ligne dans
data_source, colonnes d'état de synchronisation mises à jour à chaque tick), - le runtime de sondage générique derrière l'opération de fournisseur de données Base Platform (HTTP fetch → sélection
itemsPath→ mapping de champs → validation des lignes), - la vue Analytics → Sources de données (badge de statut, heure de dernière synchronisation, compteur de lignes écrites, action « Synchroniser maintenant »).
Le manifeste ci-dessous est la source canonique adsb-lol-military-declarative de @scrydon/sdk-authoring, sérialisée en JSON simple. Le test de parité golden dans le monorepo affirme que cela produit des lignes identiques octet par octet à la source de code équivalente sur la même fixture — donc une fois que « Synchroniser maintenant » réussit, vous exercez le runtime de sondage en production contre une vraie API publique.
L'endpoint est protégé par authentification interne (x-scrydon-internal-dev: 1 en développement, Dapr SPIFFE en production) et accepte les appelants détenant la capacité data-source:apply — platform (réconciliateur/tick), agentic (import de extension) et api-platform (le délégué extensions Better Auth). L'appel curl ci-dessous utilise l'en-tête de développement ; en production, l'appel parvient via l'un de ces trois appelants attestés par Dapr.
Prérequis
Vous disposez d'une stack Scrydon locale en cours d'exécution. Le service api-table doit répondre :
curl -fsS http://localhost:7500/api/table/healthVous avez besoin d'un identifiant d'organisation pour délimiter la source de données. Récupérez-le depuis la table organization de votre base de données auth, ou depuis l'URL de n'importe quelle page limitée à une organisation dans l'interface de la plateforme.
export ORG="<your-org-uuid>"Le manifeste
Voici le manifeste déclaratif complet. Il s'agit de JSON pur — sans fonctions, sans code. Le bundler de extension émet exactement cette forme à partir de defineDataSource({...}).
{
"kind": "table",
"id": "adsb-lol-military-declarative",
"vendor": "adsb-lol",
"displayName": "ADS-B Lol — Military Aircraft (declarative)",
"scope": "global",
"table": {
"name": "aircraft_position",
"primaryKey": ["icao24", "seenAt"],
"timestampColumn": "seenAt",
"columns": [
{ "name": "icao24", "dataType": "string", "isPrimaryKey": true },
{ "name": "callsign", "dataType": "string", "nullable": true },
{ "name": "registration", "dataType": "string", "nullable": true },
{ "name": "aircraftType", "dataType": "string", "nullable": true },
{ "name": "category", "dataType": "string", "nullable": true },
{ "name": "latitude", "dataType": "decimal" },
{ "name": "longitude", "dataType": "decimal" },
{ "name": "altitudeFeet", "dataType": "int", "nullable": true },
{ "name": "groundSpeedKnots", "dataType": "double", "nullable": true },
{ "name": "heading", "dataType": "double", "nullable": true },
{ "name": "seenAt", "dataType": "timestamp", "isPrimaryKey": true }
]
},
"ingest": {
"mode": "poll",
"intervalSec": 60,
"minIntervalSec": 30,
"request": {
"url": "https://api.adsb.lol/v2/mil",
"method": "GET",
"headers": { "accept": "application/json" }
},
"response": { "itemsPath": "$.ac" },
"filter": {
"requireNonNull": ["hex", "lat", "lon"]
},
"mapping": {
"icao24": { "path": "hex" },
"callsign": { "path": "flight", "transform": "trim_to_null" },
"registration": { "path": "r" },
"aircraftType": { "path": "t" },
"category": { "path": "category" },
"latitude": { "path": "lat" },
"longitude": { "path": "lon" },
"altitudeFeet": {
"path": "alt_baro",
"transform": "value_map",
"args": { "map": { "ground": 0 }, "passthrough": "number", "default": null }
},
"groundSpeedKnots": { "path": "gs", "transform": "number_or_null" },
"heading": { "path": "track", "transform": "number_or_null" },
"seenAt": {
"path": "seen",
"transform": "iso_from_epoch_offset",
"args": {
"basePath": "$.now",
"baseUnit": "ms",
"offsetUnit": "s",
"direction": "subtract"
}
}
}
}
}Ce que fait chaque bloc
| Bloc | Objectif |
|---|---|
kind: "table" | Le seul type de source supporté aujourd'hui — déclare une destination en forme de lignes. |
id | Identité stable. api-table effectue un upsert sur (organization_id, id) — ré-appliquer le même manifeste met à jour la ligne en place. |
vendor | Slug du fournisseur en forme libre affiché dans la liste des sources de données. |
scope: "global" | Une source pour toute l'organisation. (Le périmètre par espace de travail est prévu dans la feuille de route.) |
table.primaryKey | Clé primaire composite utilisée pour dédupliquer les résultats du sondage dans la table silver. |
table.columns[] | La liste exacte des colonnes — dataType + nullable + isPrimaryKey correspondent directement au DDL de la table silver. |
ingest.intervalSec / minIntervalSec | Cadence du tick (60s ici) et plancher appliqué par le planificateur. |
ingest.request | Spécification de la requête HTTP simple. Sans code, sans signature — headers et query sont des chaînes statiques. |
ingest.response.itemsPath | Sélecteur de type JSONPath atteignant le tableau de lignes dans l'enveloppe de réponse. |
ingest.filter.requireNonNull | Filtre au niveau de la ligne : ignore les éléments dont les chemins listés sont null/undefined. |
ingest.mapping[<column>] | Une entrée par nom dans table.columns[]. path lit le champ source ; transform + args optionnels le reformatent. Les transformations supportées sont documentées dans data-sources/index.mdx#field-mappings. |
Appliquer le manifeste
Téléchargez le fichier JSON lié ci-dessus, puis assemblez le corps de la requête d'application. Le chemin le plus propre utilise jq pour que le JSON soit composé de façon sûre (sans problèmes d'échappement shell) :
# 1) Téléchargez le manifeste une fois.
curl -fsS -o adsb-lol-military-declarative.json \
http://localhost:4001/static/scrydon-pack-adsb-aircraft/adsb-lol-military-declarative.json
# 2) Composez le corps de la requête d'application et envoyez-le en POST.
jq -n \
--arg org "$ORG" \
--slurpfile manifest adsb-lol-military-declarative.json \
'{ organizationId: $org, extensionId: "scrydon-extension-adsb-aircraft", extensionVersion: "1.0.0", manifest: $manifest[0] }' \
| curl -fsS -X POST http://localhost:7500/api/table/data-sources/apply \
-H 'content-type: application/json' \
-H 'x-scrydon-internal-dev: 1' \
-d @-Réponse attendue :
{ "sourceId": "adsb-lol-military-declarative" }Si vous préférez ne pas dépendre de jq, enregistrez le corps complet de la requête sur disque une fois et envoyez-le directement en POST :
ORG="<your-org-uuid>"
jq -n --arg org "$ORG" \
--slurpfile manifest adsb-lol-military-declarative.json \
'{ organizationId: $org, extensionId: "scrydon-extension-adsb-aircraft", extensionVersion: "1.0.0", manifest: $manifest[0] }' \
> apply-body.json
curl -fsS -X POST http://localhost:7500/api/table/data-sources/apply \
-H 'content-type: application/json' \
-H 'x-scrydon-internal-dev: 1' \
-d @apply-body.jsonExploiter et observer (Analytics → Sources de données)
Une fois la source instanciée dans votre environnement, tout ce qui suit est accessible en quelques clics — sans SDK, sans appels API. Voici l'expérience complète de l'opérateur pour n'importe quelle source de données, en utilisant l'exemple ADS-B comme sujet concret.
En tant qu'utilisateur de l'espace de travail, allez dans apps/analytics → Sources de données. Chaque source installée dans l'environnement courant est une ligne affichant Source, Fournisseur, Intervalle, Statut, Dernière synchronisation, Lignes et Dernière erreur. Une source fraîchement installée affiche Statut : En attente jusqu'à sa première synchronisation. La vue est limitée à l'environnement d'espace de travail sélectionné dans le sélecteur en haut à droite.
Ouvrez le menu d'actions ⋯ de la ligne et choisissez Synchroniser maintenant. Le badge passe à Synchronisation… pendant l'exécution du sondage — une récupération externe peut prendre quelques secondes à une minute — puis la ligne se rafraîchit automatiquement : Statut → Sain, Dernière synchronisation se met à jour et Lignes indique combien ont été écrites. Vous n'avez pas à attendre l'intervalle planifié ; cela exécute le même tick à la demande.
Cliquez sur la ligne pour ouvrir son panneau de détail, qui affiche :
- Mode d'écriture — comment les nouvelles lignes arrivent (
upsert,changed-only,appendoureplace). En lecture seule : il est fixé lors de l'installation de la source (voir Modes d'écriture). - Rétention — un contrôle modifiable (traité ci-après).
- Historique de synchronisation — les ticks les plus récents : quand chacun an eu lieu, l'événement (ex. lignes en upsert), le nombre de lignes concernées et tout message d'erreur.
- Ouvrir la table — un raccourci direct vers la table sous-jacente, où vous pouvez parcourir et interroger les lignes ingérées. (Apparaît une fois que la première synchronisation a provisionné la table.)
Dans le panneau de détail, définissez la Rétention sur la fenêtre que vous souhaitez conserver — pour l'exemple ADS-B, par exemple 7 jours — et enregistrez. La plateforme conserve uniquement les partitions journalières les plus récentes de la table et supprime les anciennes automatiquement ; la modification prend effet immédiatement, sans reconstruction de la table ni rechargement des données. Effacez le champ pour revenir à la valeur par défaut de la source. Voir Rétention pour la façon dont la valeur par défaut est définie.
En bas du panneau de détail, la Zone de danger contient Supprimer la source de données. La suppression est irréversible : après confirmation, la plateforme supprime la table sous-jacente et toutes ses lignes, supprime la source et arrête son planification. Si l'extension qui a contribué cette source n'a contribué rien d'autre, l'extension d'origine est également supprimé — ainsi, pour une extension à source unique comme cet exemple ADS-B, « Supprimer la source de données » nettoie à la fois la source et l'extension en une seule étape.
Si l'extension contient également d'autres contenus (une ontologie, des workflows ou d'autres sources de données), la source est quand même supprimée mais l'extension est conservé — une notification vous en informe — et vous désinstallez l'extension lui-même depuis Paramètres → Plateforme → Extensions → Installées quand vous êtes prêt. Cette action est irréversible ; réinstaller l'extension est le moyen de récupérer la source.
Si une synchronisation échoue
Si le Statut passe à Erreur, survolez la cellule Dernière erreur (ou lisez-la dans le panneau de détail). Les causes les plus courantes :
| Erreur | Signification | Que faire |
|---|---|---|
data_source_connection_required | La source nécessite un identifiant (son request référence un authRef), mais aucune connexion activée n'existe pour votre organisation. | Connectez le compte dans les paramètres de l'organisation sous le nom attendu par l'extension, puis synchronisez à nouveau. Cet exemple ADS-B n'utilise aucun identifiant, vous ne devriez donc pas voir cette erreur. |
invalid_installed_manifest | Le manifeste stocké a échoué à la revalidation complète au moment du tick — ex. un type de colonne ou un nom de transformation incorrect. | Réinstallez l'extension avec un manifeste corrigé. |
egress_denied | La garde de sortie a bloqué l'URL de la requête (elle doit être https:// et résoudre vers un hôte public). | Confirmez que l'hôte de la source est accessible et autorisé dans votre environnement. |
5xx en amont | L'API externe était momentanément indisponible ou limitée en débit (api.adsb.lol l'est parfois). | Cliquez à nouveau sur Synchroniser maintenant — les ticks sont idempotents. |
Aparté développeur — vérifier la ligne et l'état de synchronisation en base de données
L'interface opérateur ci-dessus est la surface supportée. Si vous développez localement et souhaitez confirmer la ligne sous-jacente directement :
SELECT source_id, status, last_sync_at, last_rows_written, last_error, consecutive_failures
FROM data_source
WHERE organization_id = :ORG;Après une Synchronisation maintenant réussie :
source_id | status | last_sync_at | last_rows_written | last_error | consecutive_failures
-----------------------------+--------+---------------------+-------------------+------------+----------------------
adsb-lol-military-declarative | ok | 2026-05-28 14:02:11 | 37 | | 0D'où vient ce manifeste
La source TypeScript se trouve à packages/sdk-authoring/src/extensions/authoring/data-source/adsb-lol-military-declarative.ts — elle appelle defineDataSource({...}) avec la même forme. Le bundler de extension sérialise l'argument de l'appel en JSON et l'émet dans un sous-répertoire data-source/ à l'intérieur d'un .scrydon-extension.tar.gz. L'endpoint /data-sources/apply accepte ce JSON directement, ce que démontre cette page : le même manifeste, simplement sans l'enveloppe extension.
Si vous souhaitez livrer la source dans une extension plutôt que de l'appliquer manuellement, suivez le parcours Auteur dans sdks/authoring/data-sources.