Manifest
Décrire publiquement une app tierce : identité, URL, permissions, collections, documents et fichiers.
Le manifest est le contrat public entre votre app, le client et Superfasttt. Il decrit ce que votre app demande et quelles ressources elle utilisera.
Vous le fournissez au format JSON. Une fois importe puis installe, il determine les permissions et ressources disponibles pour votre app dans l'espace client.
Exemple complet
{
"manifest_version": "2.0",
"id": "audit-pro",
"name": "Audit Pro",
"version": "1.0.0",
"description": "Audits qualité et conformité multi-site.",
"author": {
"name": "Acme Solutions",
"email": "contact@acme.example.com",
"url": "https://acme.example.com"
},
"runtime": {
"type": "external",
"entry_url": "https://audit-pro.example.com",
"allowed_origins": [
"https://audit-pro.example.com",
"https://staging-audit-pro.example.com"
]
},
"permissions": [
"app_data:read",
"app_data:write",
"rich_documents:read",
"rich_documents:write",
"assets:read",
"assets:write"
],
"collections": {
"inspections": {
"schema": {
"type": "object",
"properties": {
"title": { "type": "string", "maxLength": 200 },
"site_id": { "type": "string" },
"status": {
"type": "string",
"enum": ["draft", "in_review", "validated", "archived"]
},
"score": { "type": "number", "minimum": 0, "maximum": 100 },
"inspector_email": { "type": "string", "format": "email" }
},
"required": ["title", "site_id", "status"],
"additionalProperties": false
},
"indexes": ["status", "site_id", "inspector_email"]
}
},
"rich_documents": {
"audit_report": {
"editor": "prosemirror",
"schema_version": "audit-report-v1",
"is_indexable": false
}
},
"assets": {
"allowed_mime_types": ["image/png", "image/jpeg", "application/pdf"],
"max_file_size_mb": 25,
"max_total_size_mb": 1024
}
}Champs racine
| Champ | Requis | Description |
|---|---|---|
manifest_version | oui | Version du format de manifest. Utilisez "2.0". |
id | oui | Identifiant stable de l'app. Utilisez un slug court, en minuscules, sans espace. |
name | oui | Nom affiché au client. |
version | oui | Version SemVer, par exemple 1.0.0. |
description | non | Description courte de l'app. |
author | non | Informations publiques de l'éditeur : name, email, url. |
runtime | oui | URL de lancement et origins autorisées. |
permissions | oui | Permissions demandées par l'app. |
collections | non | Données métier JSON gérées par l'app. |
rich_documents | non | Types de documents riches utilisés par l'app. |
assets | non | Règles de fichiers et médias. |
runtime
"runtime": {
"type": "external",
"entry_url": "https://audit-pro.example.com",
"allowed_origins": ["https://audit-pro.example.com"]
}| Champ | Requis | Description |
|---|---|---|
type | oui | Utilisez "external" pour une app hébergée par vous. |
entry_url | oui | URL de lancement de votre app. En production, utilisez HTTPS. |
allowed_origins | oui | Origins exactes autorisées à appeler l'API depuis le navigateur. |
Règles importantes :
- Une origin a la forme
scheme://host[:port], sans chemin ni query string. - Les wildcards ne sont pas acceptées.
- En production, utilisez
https://. - En développement,
http://localhost:<port>est accepté. - L'origin de
entry_urldoit être présente dansallowed_origins.
Exemples valides :
[
"https://audit-pro.example.com",
"https://staging-audit-pro.example.com",
"http://localhost:3000"
]Exemples invalides :
[
"*",
"https://*.example.com",
"https://audit-pro.example.com/app",
"http://audit-pro.example.com"
]permissions
Demandez uniquement les permissions nécessaires.
| Permission | Utilisation |
|---|---|
app_data:read | Lire les records de vos collections. |
app_data:write | Créer, modifier et supprimer les records de vos collections. |
rich_documents:read | Lire vos documents riches et leurs versions. |
rich_documents:write | Créer, modifier, restaurer et supprimer vos documents riches. |
assets:read | Lister, consulter et obtenir une URL de téléchargement de vos fichiers. |
assets:write | Uploader, compléter, rattacher et supprimer vos fichiers. |
Si vous ajoutez une permission après installation, réimportez le manifest puis réinstallez l'app pour que le client accorde la nouvelle permission.
collections
Une collection représente un type d'objet métier de votre app.
"collections": {
"inspections": {
"schema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"status": { "type": "string", "enum": ["draft", "done"] }
},
"required": ["title"],
"additionalProperties": false
},
"indexes": ["status"]
}
}| Champ | Description |
|---|---|
| Clé de collection | Identifiant utilisé dans l'URL, par exemple /api/v1/app-data/inspections. |
schema | JSON Schema de type object appliqué au champ data de chaque record. |
indexes | Champs autorisés pour les filtres de /query. |
Bonnes pratiques :
- Gardez des noms de collections simples :
inspections,sites,contracts,cases. - Utilisez
additionalProperties: falsepour éviter les données non prévues. - Ajoutez dans
indexesuniquement les champs que vous devez filtrer souvent. - Pour faire evoluer un schema, ajoutez d'abord des champs optionnels. Un nouveau champ requis doit être traité comme une évolution incompatible.
rich_documents
Les documents riches servent aux rapports, comptes-rendus et contenus editables associes a votre app.
"rich_documents": {
"audit_report": {
"editor": "prosemirror",
"schema_version": "audit-report-v1",
"is_indexable": false
}
}| Champ | Description |
|---|---|
| Clé du document | Type de document utilisé dans les appels API. |
editor | Format éditeur utilisé par votre app. |
schema_version | Version du format de contenu que votre app produit. |
is_indexable | Indique si ce type de document peut être considéré comme indexable. |
Le contenu du document est un objet JSON produit par votre éditeur. Votre app reste responsable de savoir l'afficher et le modifier.
À l'usage, votre app envoie collection, editor, schema_version, title
et content à POST /api/v1/rich-documents. Le serveur extrait
automatiquement plain_text et incrémente la version à chaque PATCH.
Exemple complet dans le
Quickstart §7.
assets
"assets": {
"allowed_mime_types": ["image/png", "image/jpeg", "application/pdf"],
"max_file_size_mb": 25,
"max_total_size_mb": 1024
}| Champ | Description |
|---|---|
allowed_mime_types | Liste des types MIME acceptes. Si absent, aucun filtre MIME specifique n'est demande. |
max_file_size_mb | Taille maximale d'un fichier individuel. |
max_total_size_mb | Taille maximale cumulee pour les fichiers de l'installation. |
Evitez les types trop larges. Declarez explicitement les formats necessaires a votre cas d'usage.
L'upload se fait en 3 appels : POST /api/v1/app-assets/upload-url (réponse :
asset_id, upload_url, required_headers), PUT direct vers le stockage,
puis POST /api/v1/app-assets/complete qui revérifie la taille et le content
type via HEAD. Le téléchargement passe ensuite par
POST /api/v1/app-assets/{asset_id}/download-url. Exemple complet dans le
Quickstart §7.
Valider et importer
Les endpoints de manifest attendent toujours une enveloppe :
{
"manifest": {
"manifest_version": "2.0",
"id": "audit-pro",
"name": "Audit Pro",
"version": "1.0.0",
"runtime": {
"type": "external",
"entry_url": "https://audit-pro.example.com",
"allowed_origins": ["https://audit-pro.example.com"]
},
"permissions": ["app_data:read"]
}
}Valider sans effet de bord :
curl -X POST https://api.superfasttt.ai/api/v1/app-platform/manifests/validate \
-H "Authorization: Bearer <user_access_token>" \
-H "X-Tenant-ID: <espace_client>" \
-H "Content-Type: application/json" \
-d @manifest-request.jsonImporter :
curl -X POST https://api.superfasttt.ai/api/v1/app-platform/manifests/import \
-H "Authorization: Bearer <user_access_token>" \
-H "X-Tenant-ID: <espace_client>" \
-H "Content-Type: application/json" \
-d @manifest-request.jsonErreurs de validation courantes
| Code | Cause |
|---|---|
required | Un champ obligatoire est absent. |
invalid_type | Un champ n'a pas le type attendu. |
invalid_semver | version n'est pas au format SemVer complet. |
https_required | Une URL de production n'utilise pas HTTPS. |
wildcard_forbidden | Une origin contient *. |
origin_not_allowed | L'origin de entry_url n'est pas dans allowed_origins. |
unknown_permission | Une permission demandee n'est pas disponible. |
must_be_object | Le JSON Schema d'une collection n'est pas un objet. |
index_field_unknown | Un champ indexe n'existe pas dans schema.properties. |
reserved_field | Le champ schema utilise un nom de champ réservé. |
Versioning
- Incrementez
versionpour chaque changement publie a un client. - Les changements compatibles ajoutent des champs optionnels ou des collections nouvelles.
- Les changements incompatibles modifient le type d'un champ, rendent un champ obligatoire ou changent la signification d'une valeur existante.
- Apres un changement de manifest, reimportez puis reinstallez l'app pour que l'espace client utilise la nouvelle version.

