Ga naar inhoud

Het manifest

Alles wat Tabbr over je module moet weten, staat in één bestand: tabbr.config.json in de root van je workspace. De CLI leest het bij het bouwen en publiceren, en de club ziet een deel ervan bij het installeren (de rechten die je module vraagt).

Dit is — licht ingekort — het manifest van de module Bevoegdheden & competenties:

tabbr.config.json
{
"club": "",
"apiHost": "https://api.tabbr.be",
"moduleId": "qualifications",
"package": "tabbr/qualifications",
"version": "1.0.0",
"title": "Bevoegdheden & competenties",
"summary": "Bevoegdheden (wie mag wat, van wanneer tot wanneer) en competenties (wat kan iemand al).",
"icon": "workspace_premium",
"exposedModule": "./Module",
"exportName": "Module",
"engines": { "tabbr": "^1.3" },
"uses": { "sys.access": "^1" },
"optionalUses": { "tabbr.consent": "^1" },
"optionalDependencies": { "sys.messaging": "*" },
"permissions": {
"entities": { "read": ["person"], "write": [] },
"personalData": ["identity"]
},
"entities": [
{
"name": "programme",
"label": "Opleiding",
"display": ["name"],
"fields": [
{ "key": "name", "label": "Naam", "type": "tabbr.text", "includeInSearch": true },
{ "key": "archived", "label": "Gearchiveerd", "type": "tabbr.bool" }
]
}
],
"backend": {
"entry": "backend/src/index.ts",
"allowedHosts": [],
"secretFieldNames": [],
"triggers": [
{ "type": "CRON", "name": "refreshAll", "cronExpression": "10 2 * * *", "handler": "refreshAll" },
{ "type": "ENTITY_HOOK", "name": "programmeUpdated", "entity": "programme", "event": "onUpdated", "handler": "onProgrammeSaved" }
]
}
}
Veld Betekenis
moduleId Unieke id in de hele store. Kan nooit veranderen — de server weigert een versie met een ander id.
package <uitgever>/<naam>, bv. tabbr/groups. De uitgever bepaalt ook de naam van contracten die je aanbiedt.
version Semver. Elke nieuwe versie moet hoger zijn dan alle vorige.
title Reservetitel. De getoonde titel komt uit je vertalingen (module.title).
summary De korte beschrijving in de Module Store.
icon Een Material-icoon, bv. groups of verified_user.
exposedModule, exportName Waar Tabbr je moduleklasse vindt: normaal ./Module en Module.
visibility PUBLIC of UNLISTED in de store.
club, apiHost, localApiHost Alleen voor de ontwikkelaar (dev preview, publiceren). Commit club niet.

engines.tabbr is het bereik van de module-API waartegen je bouwt, bv. ^1.3. De huidige module-API is 1.3.0. Een club op een Tabbr die buiten dat bereik valt, krijgt je module niet; de app laadt dan gewoon zonder.

API Wat er bijkwam
1.0 De eerste gepubliceerde modules
1.1 Contracten: uses, MODULE_CONTRACTS, tabbr.uses
1.2 Toegangsregels op modulevelden, {entity.key}, gerelateerde filters één stap ver en via meerwaardige verwijzingen
1.3 userPrompts, provides, optionalUses
Veld Betekenis
uses Contracten die je module nodig heeft, met een semver-bereik: { "sys.access": "^1" }. Je module kan dan alleen geïnstalleerd worden in een club die het contract heeft.
optionalUses Contracten die je gebruikt als ze er zijn (API 1.3).
provides Contracten die je module zelf aanbiedt — zie Contracten.
dependencies / optionalDependencies Andere pakketten, of ingebouwde modules zoals sys.messaging.

Wat je hier vraagt, toont de Module Store in gewone taal aan de beheerder die je module installeert (“leest personen”, “verwerkt persoonsgegevens: contactgegevens”, “verstuurt mails”…). Vraag niet meer dan je nodig hebt.

"permissions": {
"entities": { "read": ["person", "membership"], "write": ["flight"] },
"personalData": ["contact"],
"messaging": true
}

Een module brengt haar eigen gegevens mee. Per entiteit:

Veld Betekenis
name [a-z][a-zA-Z0-9]{1,39}, uniek in de club, bv. groupMember.
label De naam die de club ziet, bv. Groepslid.
display De velden die een record voorstellen (in een keuzelijst, een verwijzing).
sort De standaardsortering.
fields[] De velden: key, label, type en opties.
access De toegangsregels bij de eerste installatie (viewAccess, createAccess, updateAccess, deleteAccess). Daarna beslist de club.

Veldtypes: tabbr.text, tabbr.paragraph, tabbr.int, tabbr.decimal, tabbr.bool, tabbr.date, tabbr.email, tabbr.phone, tabbr.national-id, tabbr.entity (met target, multi, freeTextAllowed), tabbr.single-select (met choices, multi), sys.file en tabbr.person.address. Per veld kan je ook description, category, includeInSearch, personalDataCategory en een eigen access meegeven.

Een entiteit met een verwijzing en een keuzelijst
{
"name": "groupMember",
"label": "Groepslid",
"display": ["person"],
"fields": [
{ "key": "group", "label": "Groep", "type": "tabbr.entity", "target": "group" },
{ "key": "person", "label": "Persoon", "type": "tabbr.entity", "target": "person" },
{ "key": "role", "label": "Functie", "type": "tabbr.single-select",
"choices": [ { "value": "member", "name": "Lid" }, { "value": "trainer", "name": "Trainer" } ] },
{ "key": "from", "label": "Vanaf", "type": "tabbr.date" },
{ "key": "until", "label": "Tot en met", "type": "tabbr.date" }
],
"access": {
"viewAccess": [
{ "andFilterValues": [ { "filterId": "currentUser:roles", "operator": "HAS_ANY", "value": ["ADMIN"] } ] },
{ "andFilterValues": [ { "filterId": "root.{person}:currentUser" } ] },
{ "andFilterValues": [ {
"filterId": "root.{group}:reverse.groupMember.{group}",
"value": [ { "andFilterValues": [
{ "filterId": "root.{person}:currentUser" },
{ "filterId": "root:{role}", "operator": "EQ", "value": "trainer" },
{ "filterId": "root:{until}", "operator": "IS_EMPTY" }
] } ]
} ] }
]
}
}

De drie regels (één ervan volstaat) lezen als: een ADMIN ziet alles, je ziet je eigen lidmaatschappen, en je ziet de leden van een groep waarvan jij een lopend lidmaatschap als trainer hebt.

In filter-id’s verwijs je naar je eigen velden met {fieldKey}, bv. root.{person}:currentUser (“de persoon van dit record is de ingelogde gebruiker”). De volledige filtertaal staat in Filters en toegangsregels.

Zonder dat jij er iets voor bouwt, krijgt de club voor elke entiteit van je module:

  • een plek in Instellingen › jouw module, met de gewone schermen voor velden, lijsten, toegang, hooks, acties en layout (zie Clubbeheer);
  • eigen velden bovenop de jouwe, en lijsten in het menu;
  • de omgekeerde filter “heeft een gerelateerde …” op elke entiteit waarnaar je entiteit verwijst;
  • hooks en audit.

De velden die jij declareert, zijn beheerd: de club kan ze hernoemen, keuzes aanpassen en bepalen wie ze ziet, maar niet verwijderen of van type veranderen.

Veld Betekenis
entry Het TypeScript-bestand met je functies, bv. backend/src/index.ts.
triggers[] Wanneer Tabbr je functies oproept: CRON of ENTITY_HOOK.
allowedHosts De enige externe hosts die je backend mag aanspreken, bv. ["admin.gliding.app"].
localAllowedHosts Idem, voor een lokale Tabbr.
secretFieldNames Instellingen die geheim zijn (een API-key): ze komen nooit terug naar de browser.
manageRoles true als je via sys.access rollen toekent (zoals de groepenmodule).

Meer daarover in De backend.