Référence
Données : collections, fichiers, réglages
Mis à jour le 4 septembre 2026Plateforme v1 Markdown brut
Le principe
Une app Capibara ne possède pas de base de données : ses données vivent dans
l’organisation qui l’a installée, cloisonnées par app. Trois familles, toutes
servies par ctx (code hébergé) :
| Famille | ctx |
Capability | Pour quoi |
|---|---|---|---|
| Collections | ctx.data.<nom> |
data.collections |
des enregistrements typés, déclarés au manifeste (scores, favoris, tickets…) |
| Clé/valeur | ctx.kv |
storage.tenant.ro / .rw |
curseurs, caches, petits réglages (32 Ko / 200 clés) |
| Fichiers privés | ctx.files |
files.private |
pièces jointes, exports, images générées (≤ 5 Mo) |
Et une quatrième, saisie par un administrateur de l’organisation, jamais par
votre code : les réglages (settings du manifeste → ctx.install.config),
avec des champs secret chiffrés au repos.
Conséquences, toutes voulues : la donnée est supprimée avec l’organisation,
incluse dans son export RGPD, conservée 30 jours après une
désinstallation (réinstaller la retrouve) puis purgée par la plateforme —
l’admin peut aussi purger tout de suite depuis la fiche de l’app. Vous ne
gérez ni migration, ni sauvegarde, ni DDL : le manifeste est le contrat.
Déclarer des collections
{
"capabilities": ["data.collections"],
"collections": {
"favorites": { "fields": { "city": "string", "addedAt": "date" } },
"scores": { "fields": { "partyId": "string", "value": "number", "label": "string", "meta": "json" }, "indexes": ["partyId"] }
}
}
- Types de champ :
string(≤ 20 000 caractères),number,boolean,
date(ISO 8601, normalisée à l’écriture),json(valeur libre ≤ 16 Ko). - Au plus 10 collections et 30 champs par collection ; noms =
identifiants simples (a-zpuis lettres/chiffres/_). Le nom$files
est réservé. indexesest documentaire : les égalités sont déjà indexées (GIN).- Requiert
main: seules les apps hébergées y accèdent — un backend
externe n’a ni collections, ni KV, ni fichiers
(le manifeste les refuse sansmain).
Toute écriture est validée contre la déclaration : un champ non déclaré,
un type faux ou un enregistrement > 64 Ko sont refusés avec un message qui
nomme le champ. Un null est accepté partout (champ vide).
Lire et écrire — ctx.data
// Créer ou remplacer (clé fournie) — la clé est générée (« rec_… ») si absente.
const fav = await ctx.data.favorites.set({ city: 'Lyon', addedAt: new Date().toISOString() }, 'lyon');
// Lire une ligne par sa clé.
const row = await ctx.data.favorites.get('lyon'); // { id, key, data, createdAt, updatedAt } | null
// Interroger : where + orderBy + curseur, ≤ 100 lignes par page.
const page = await ctx.data.scores.query({
where: { partyId: 'p_123', value: { gte: 10 } },
orderBy: { field: 'createdAt', dir: 'desc' },
limit: 20,
});
const next = page.nextCursor ? await ctx.data.scores.query({ where: { partyId: 'p_123' }, cursor: page.nextCursor }) : null;
// Compter, supprimer.
const { count } = await ctx.data.scores.count({ partyId: 'p_123' });
await ctx.data.favorites.delete('lyon');
Opérateurs de where par type (au plus 5 conditions, in ≤ 20 valeurs) :
| Type | Opérateurs |
|---|---|
string |
eq, ne, in, contains |
number |
eq, ne, in, gt, gte, lt, lte |
date |
eq, ne, gt, gte, lt, lte |
boolean |
eq, ne |
json |
aucun (stockage seulement) |
{ champ: valeur } vaut { champ: { eq: valeur } }. Le tri porte sur
updatedAt (défaut, décroissant), createdAt ou key — le tri par champ
de données viendra plus tard ; en attendant, triez la page côté code ou
utilisez la clé.
Quota de lignes par app installée (toutes collections) : 5 000 (Gratuit),
100 000 (Pro), 1 000 000 (Business). Au-delà, set d’une NOUVELLE clé
échoue avec un message clair — remplacer une ligne existante passe toujours.
Fichiers privés — ctx.files
{ "capabilities": ["files.private"] }
const f = await ctx.files.put('rapport.pdf', pdfBytes); // Uint8Array, ArrayBuffer ou base64
// f = { id, name, contentType, size, url, createdAt }
return ui.link({ label: 'Télécharger le rapport', href: f.url }); // ou ui.image({ src: f.url, alt: '…' })
const { dataBase64 } = await ctx.files.get(f.id);
const { files } = await ctx.files.list();
await ctx.files.delete(f.id);
- Types acceptés :
png,jpg,webp,gif(vérifiés par leurs octets de
signature),pdf,csv,txt,md,json— ≤ 5 Mo par fichier,
500 fichiers par installation ; l’espace compte dans le quota de
stockage de la formule de l’organisation (comme sa médiathèque). urlest un chemin relatif vers une route gardée : seule une personne
connectée à l’organisation ET autorisée à « utiliser l’app » peut l’ouvrir.
Jamais d’URL publique, jamais de lien devinable.
Réglages — settings
{
"settings": {
"fields": [
{ "key": "defaultCity", "label": "Ville par défaut", "type": "text", "placeholder": "Paris" },
{ "key": "mode", "label": "Mode", "type": "select", "options": [{ "value": "simple", "label": "Simple" }, { "value": "expert", "label": "Expert" }] },
{ "key": "apiKey", "label": "Clé API du service tiers", "type": "secret", "required": true, "help": "Trouvez-la dans votre compte du service." }
]
}
}
- Types :
text,textarea,number,boolean,select(avec
options),secret. Au plus 20 champs. - Un administrateur remplit ces réglages sur la fiche de l’app
(« Réglages de l’app ») ; votre code les lit dansctx.install.config
(ctx.install.config.defaultCity). - Un champ
secretest chiffré au repos (contexte imposé par la
plateforme) et jamais renvoyé à l’écran : l’admin voit « défini » et
peut le remplacer ; seul votre code hébergé reçoit la valeur en clair.
Ne le journalisez pas (ctx.logest visible de l’admin). - Les champs
configdes widgets continuent d’arriver dans le même
ctx.install.config; en cas de clé identique, le réglage déclaré prime.
Cycle de vie, export, test
- Désinstallation : tout est conservé 30 jours (l’organisation voit
« Données conservées » sur la fiche, avec « Effacer maintenant ») ; passé ce
délai, la plateforme purge lignes, fichiers, KV et réglages. - Export : l’admin exporte les données de votre app en JSON depuis la
fiche ; elles font aussi partie de l’export RGPD de l’organisation
(collections + métadonnées des fichiers + KV). - Pendant le développement : la section Données de votre app
(portail) montre les collections, le KV et les fichiers de vos
installations de test, avec suppression ligne à ligne — jamais ceux
d’une installation réelle. Retirer une install de test efface ses données.