Configure app settings and permissions
Let an installer choose the objects and fields your app uses, and declare the permissions those choices require. Start with a scaffolded app and use a sandbox installation when testing permission changes.
Scopes, macros, and settings
Section titled “Scopes, macros, and settings”The installation token is only half of API access. Every call the function
makes as that token is checked against the scopes granted on the install.
You declare what the app needs in requiredScopes. The installer can still
uncheck items on the consent / install screen.
Macro scopes
Section titled “Macro scopes”Write macros, not every leaf scope. Caraer expands them against the tenant catalog at install time (and again when settings change).
| Macro | Expands to |
|---|---|
tools.forms.all |
Every tools.forms.* scope |
records.candidate.all |
Record-level scopes for candidate (create / read / update / delete). Does not include property or relation scopes |
records.candidate.properties_all |
Every records.candidate.property.* scope |
records.candidate.relations_all |
Every records.candidate.relation.* scope |
records.*.all |
Record-level scopes for every object. Use sparingly |
global.all |
Every global.* scope |
A typical “this app fully owns one object” pack is the three records.<object>.* macros together. The CLI wizard can add that pack in one step.
Concrete scopes (tools.apps.read) are fine when you need one permission only.
tools.objects_schemas.write is the usual extra if install creates objects.
Bind scopes to settings
Section titled “Bind scopes to settings”Do not hard-code records.candidate.all when the installer chooses the object.
Put the setting name in angle brackets. Caraer substitutes the selected
object when settings are saved:
settingsSchema: - name: attendee_object label: Attendee object type: OBJECT_SINGLE_SELECT required: true - name: candidate_mapping label: Candidate type: MAPPING required: true
requiredScopes: - tools.objects_schemas.write - records.<attendee_object>.all - records.<attendee_object>.properties_all - records.<attendee_object>.relations_all - records.<candidate_mapping>.all - records.<candidate_mapping>.properties_all - records.<candidate_mapping>.relations_allHow substitution works:
<fieldName>must match asettingsSchemaname.OBJECT_SINGLE_SELECT/OBJECT_MULTI_SELECTuse the selected object name (multi-select expands to one scope set per object).MAPPINGusesmappingValue.objectName, not the mapping items.- An empty or unset field grants no extra record scopes.
- Changing the setting updates the install: scopes for the old object are removed, scopes for the new object are added.
The function still sees the setting value on body.settingsSchema. Use that
value as the object name in API calls; the token is already scoped to it.
Settings UX
Section titled “Settings UX”- Settings are for admins installing the app, not for you. Keep required fields to the minimum that makes the app work.
- Prefer
SWITCH,OBJECT_SINGLE_SELECT,SINGLE_SELECT, andMAPPINGover free-text object or property names. - Group related fields with
settingsSections(orsrc/app/settings-sections/*.json). Caraer lays cards left-to-right, max three across. Unassigned fields land in Other settings. - Hide advanced fields behind a switch:
- name: custom_mapping type: SWITCH defaultValue: false- name: field_mapping type: MAPPING visibleWhen: - field: custom_mapping operator: EQUALS value: trueHidden fields are not required and their values are dropped.
valueScope: USERstores the value per Caraer user (calendar picks). Default isCOMPANY(one value for the install).FILE/MULTI_FILEbelong on app-bar action dialogs, not as everyday install settings.
Function habits
Section titled “Function habits”- Return quickly from webhooks and inbound handlers. Enqueue
POST {caraerApiBase}/v2/apps/{appUuid}/installation/jobsfor work that can exceed the 60s function timeout. - Set
waitUntilComplete: trueonlifecycle/install.json(andupdate.jsonif settings save must show hook-written mappings) so the install request waits for the function. - Put shared helpers in
src/app/shared/and importrequire("../../shared")from a function folder. Do not copy files. - Read third-party tokens from
body.secrets/body.connections. Root.envis for your deploy-time keys (GOOGLE_CLIENT_SECRET), not installer secrets. See External OAuth and secrets.