A collection is a typed table — backed by MongoDB under the hood, but exposed through AppEngine's CRUD layer rather than directly. AppEngine ships ~150 built-in collections (contacts, products, orders, pages, leads, …) and lets you define your own without redeploying.
Built-in collections (selected)
The full set lives in @jaclight/dbsdk's DataType enum and is loaded at boot. The ones you'll touch most:
- Storefront —
product,productvariant,category,cart,order,lineitem,discount,giftcard,inventory,shipping,tax,invoice,subscription,rental,return - CRM —
contact,lead,audience,campaign,crm-message,crm-ticket,crm-reservation,task,opportunity,note,activity,crm-customer - Site / CMS —
page,site,domain,theme,category,tag,image,video,file - Auth —
user,customer,userrole,apikey,device,organization - Automation —
automation,flow,step,trigger,action,ruleset,rule - Banking —
account,transfer,card,kyc,loan,journal-entry - Community —
community-page,post,story,follow,bookmark,badge
Built-in collections come with hand-tuned JSON schemas, validation rules, indexes, and event hooks. Custom collections share the same CRUD endpoints but you supply the schema.
Schema shape
A collection record is itself a BaseModel<CollectionModel>. The interesting bit is data:
{
name: 'product', // matches datatype
title: 'Products',
description: 'Catalogue of items for sale',
schema: {
type: 'object',
properties: {
sku: { type: 'string' },
title: { type: 'string' },
price: { type: 'number' },
// ...JSON Schema with x- extensions for UI/validation
},
required: ['sku', 'title'],
},
indexes: [{ fields: ['sku'], unique: true }],
enableWorkflow: false, // toggles the approval pipeline
enableHistory: true,
requiredRole: { read: [...], create: [...], update: [...], delete: [...] },
events: { onCreate: '...', onUpdate: '...' },
}
The schema is JSON Schema with AppMint extensions:
x-control/x-control-variant— which form control to renderx-render— output renderer (e.g.file,html,markdown)dataSource— populate selects from another collection or functionhidden,hideIn,readOnly— UI behavior
The same schema is used to validate API writes, generate admin forms, and drive the Vibe Studio low-code builder.
Defining a custom collection
Create the collection record itself with a POST /repository/create, with datatype: 'collection'.
/repository/createJWTcurl -X POST https://appengine.appmint.io/repository/create \
-H "orgid: my-org" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"datatype": "collection",
"data": {
"name": "vehicle",
"title": "Vehicles",
"schema": {
"type": "object",
"properties": {
"vin": { "type": "string" },
"make": { "type": "string" },
"model": { "type": "string" },
"year": { "type": "integer" }
},
"required": ["vin", "make", "model"]
},
"indexes": [{ "fields": ["vin"], "unique": true }]
}
}'
Once created, the new collection is immediately usable through the same CRUD surface as any built-in:
# write a vehicle
curl -X POST https://appengine.appmint.io/repository/create \
-H "orgid: my-org" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{ "datatype": "vehicle", "data": { "vin": "1HGBH...", "make": "Honda", "model": "Civic", "year": 2024 } }'
# query vehicles
curl https://appengine.appmint.io/repository/find/vehicle \
-H "orgid: my-org" \
-H "Authorization: Bearer $JWT"
/repository/collections/{name?}/{subName?}JWT/repository/find/{datatype}/{dataId?}JWT/repository/find/{datatype}JWTValidation hooks
RepositoryService runs the JSON Schema validator on every write. Failures throw a 400 with the validation errors. Beyond schema validation, collections can declare:
- Indexes — created in MongoDB on first write, enforced thereafter (unique, sparse, compound).
- Required role overrides — per-record
requiredRoleplus collection-level defaults override the global RBAC matrix. - Workflow — when
enableWorkflow: true, writes start indraftand require approval to publish. See State and workflow. - History — when
enableHistory: true, every change is appended to a versioned history collection. Restore viaPOST /repository/trash-restore.
Querying
AppEngine wraps Mongo's query language under /repository/find/{datatype} and /repository/search/{datatype}. Pass a Mongo-style filter:
curl -X POST https://appengine.appmint.io/repository/find/contact \
-H "orgid: my-org" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{ "filter": { "data.tags": "vip" }, "page": 1, "pageSize": 50 }'
The Dynamic Query module exposes the same engine to no-code rule builders — see the Automation pages for how rules and audiences use this.
For complex filtering across multiple collections, the platform's audience engine (CRM) and the rule engine both build on the same query layer. You don't have to roll aggregations by hand.
Listing collections
To see what's installed in your tenant:
/repository/collectionsJWTThe response includes both built-ins and any custom collections you've registered. The Discovery API (/discover) exposes the same data in a format meant for AI agents and integrators.