@inwink-mcp/backoffice-extension-helpers 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -1
- package/dist/cli.js +133 -34
- package/package.json +1 -1
- package/templates/vite-extension/AGENTS.md.tpl +13 -5
- package/templates/vite-extension/docs/inwink-api/README.md +65 -24
- package/templates/vite-extension/docs/inwink-api/aggregate.md +238 -0
- package/templates/vite-extension/docs/inwink-api/assets.md +107 -107
- package/templates/vite-extension/docs/inwink-api/create.md +3 -3
- package/templates/vite-extension/docs/inwink-api/delete.md +4 -2
- package/templates/vite-extension/docs/inwink-api/entities.md +24 -60
- package/templates/vite-extension/docs/inwink-api/entity-template.md +201 -0
- package/templates/vite-extension/docs/inwink-api/files.md +136 -135
- package/templates/vite-extension/docs/inwink-api/history.md +68 -0
- package/templates/vite-extension/docs/inwink-api/import.md +4 -4
- package/templates/vite-extension/docs/inwink-api/query-language.md +127 -38
- package/templates/vite-extension/docs/inwink-api/query.md +12 -10
- package/templates/vite-extension/docs/inwink-api/update.md +7 -5
|
@@ -1,68 +1,32 @@
|
|
|
1
|
-
◂
|
|
1
|
+
◂ Back to [README](./README.md)
|
|
2
2
|
|
|
3
|
-
# Entity
|
|
3
|
+
# Entity contracts & other endpoints
|
|
4
4
|
|
|
5
|
-
>
|
|
5
|
+
> The exact fields of an entity are discovered with `inwink_mcp_get_entity_description`: this page lists no schema.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Entity contracts
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
| File | Upload files (voir [files.md](./files.md)) | |
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## Entity Contracts
|
|
21
|
-
|
|
22
|
-
### Event Entity
|
|
23
|
-
|
|
24
|
-
Scoped to EventAPI. Always has an `eventId` property. URL uses `{eventId}` as shardId.
|
|
25
|
-
|
|
26
|
-
### Customer Entity
|
|
27
|
-
|
|
28
|
-
Scoped to CustomerAPI. Always has a `customerId` property. URL uses `{customerId}` as shardId.
|
|
29
|
-
|
|
30
|
-
### Dynamic Entity
|
|
31
|
-
|
|
32
|
-
Can have custom properties added via backoffice or template API. Custom properties behave identically to built-in properties in all endpoints.
|
|
33
|
-
|
|
34
|
-
### With Publication Status
|
|
35
|
-
|
|
36
|
-
Has a `status` property (string, case-insensitive): `Draft`, `Preview`, `Published`, `Canceled`, `Rejected`.
|
|
37
|
-
|
|
38
|
-
### With History
|
|
39
|
-
|
|
40
|
-
Tracked modifications. Read-only properties: `validFrom` (last modification date, UTC), `modifiedById` (UUID), `modifiedByDisplayName` (string).
|
|
9
|
+
- **Event Entity** — scoped to EventAPI. Always has an `eventId` property. The URL uses `{eventId}` as shardId.
|
|
10
|
+
- **Community Entity** — scoped to CommunityAPI. Always has a `communityId` property. The URL uses `{communityId}` as shardId. Community entities (members, forums, discussion subjects…) are **not** reachable through EventAPI: an event and a community are two separate containers.
|
|
11
|
+
- **Customer Entity** — scoped to CustomerAPI. Always has a `customerId` property. The URL uses `{customerId}` as shardId.
|
|
12
|
+
- **Auth Tenant Entity** — scoped to an **audience** (tenant) of a customer, on CustomerAPI. Its name starts with `authtenant` (`authtenantcommunity`, `authtenantcontact`, `authtenantcompany`, `authtenantmailtemplate`…). The URL takes two segments: `{customerId}/audience/{tenantId}` — see [README.md](./README.md#audience-scoped-entities-customerapi).
|
|
13
|
+
- **Dynamic Entity** — can have custom properties added through the backoffice or the template API. Custom properties declared on the entity's own template (the one `inwink_mcp_get_entity_description` returns) behave exactly like native properties on every endpoint. Some fields are declared by a parent record instead: they resolve only on the routes scoped to that parent record, and fail elsewhere with `400 … property resolution error`, like an unknown name. To declare a custom property from the extension, see [entity-template.md](./entity-template.md).
|
|
14
|
+
- **With Publication Status** — has a `status` property (string, case-insensitive): `Draft`, `Preview`, `Published`, `Canceled`, `Rejected`.
|
|
15
|
+
- **With History** — modifications are tracked in a history table (see [history.md](./history.md)). Read-only properties: `validFrom` (start of validity of the current version = last modification date, UTC), `validTo` (end of validity; on the current table, an "infinity" sentinel value), `modifiedById` (UUID), `modifiedByDisplayName` (string).
|
|
41
16
|
|
|
42
17
|
---
|
|
43
18
|
|
|
44
|
-
##
|
|
45
|
-
|
|
46
|
-
### Person (EventAPI)
|
|
47
|
-
|
|
48
|
-
Contracts: Event entity, Dynamic, With Publication Status, With History.
|
|
49
|
-
|
|
50
|
-
Key properties: `id` (uuid), `mail`, `firstname`, `lastname`, `company`, `jobTitle`, `preferredLanguage`, `isRegistered` (bool), `hasAttended` (bool), `status`, `registrationDate`, `registrationMode` (enum: BackOffice, Website, OnSite, Order, Invitation, ExhibitorAccount), `checkinDate`, `kinds` (string[]), `badgeRef`, `userId`, `contactId`, `description` (localizable), `photo` (file ref).
|
|
51
|
-
|
|
52
|
-
Expandable relations: `exhibitor`, `infos`, `roomingInfos`, `exhibitorAccounts`, `orders`, `hotelRoomNights`, `sessions`, `favoriteExhibitors`, `animatedSessions`, `orderItems`, `personScans`, `tasks`, `meetingPersons`, `availabilities`, `agenda`, `activityView`.
|
|
53
|
-
|
|
54
|
-
### EventDetail (EventAPI)
|
|
55
|
-
|
|
56
|
-
Contracts: Event entity, With History.
|
|
19
|
+
## Other endpoints
|
|
57
20
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
21
|
+
| Endpoint | Pattern | Purpose |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| Worktemplate | `GET {api}/{shardId}/{entity}/worktemplate` | Returns the entity template (properties, types, required flags, localization) — see [entity-template.md](./entity-template.md) |
|
|
24
|
+
| Template (patch) | `PATCH {api}/{shardId}/{entity}/template` | Adds/edits/removes **one** custom field without touching the others — see [entity-template.md](./entity-template.md) |
|
|
25
|
+
| Template (replace) | `POST {api}/{shardId}/{entity}/updateentitytemplate` | Replaces the **whole** custom template: whatever is missing from the body is lost — see [entity-template.md](./entity-template.md) |
|
|
26
|
+
| Aggregate | `POST {api}/{shardId}/{entity}/aggregate` | Grouping / aggregation (GROUP BY) — see [aggregate.md](./aggregate.md) |
|
|
27
|
+
| History | `POST {api}/{shardId}/{entity}/history/query` | Past versions (same body as query). Always filter by `id` — see [history.md](./history.md) |
|
|
28
|
+
| Removed | `POST {api}/{shardId}/{entity}/history/removed/query` | Deleted entities (+ `/history/removed/count`) — see [history.md](./history.md) |
|
|
29
|
+
| Massupdate | `POST {api}/{shardId}/{entity}/massupdate` | Bulk EDIT, like `UPDATE … WHERE` in SQL — see [update.md](./update.md) |
|
|
30
|
+
| Massdelete | `POST {api}/{shardId}/{entity}/massdelete` | Bulk DELETE, like `DELETE … WHERE` in SQL — see [delete.md](./delete.md) |
|
|
31
|
+
| Export | | Returns entities as an Excel file |
|
|
32
|
+
| File | | File upload — see [files.md](./files.md) |
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
◂ Back to [README](./README.md)
|
|
2
|
+
|
|
3
|
+
# Entity template (custom fields)
|
|
4
|
+
|
|
5
|
+
The **template** of a dynamic entity describes its custom fields: the ones the backoffice
|
|
6
|
+
(or an extension) adds on top of the native columns. Once declared in the
|
|
7
|
+
template, a custom field behaves exactly like a native field on `query`,
|
|
8
|
+
`count`, mutations, export…
|
|
9
|
+
|
|
10
|
+
Three routes, all scoped by the usual `shardId`:
|
|
11
|
+
|
|
12
|
+
| Verb | Route | Role |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `GET` | `{api}/{shardId}/{entity}/worktemplate` | Read the consolidated template (native + custom) |
|
|
15
|
+
| `PATCH` | `{api}/{shardId}/{entity}/template` | **Partial edit** — touch only the named fields |
|
|
16
|
+
| `POST` | `{api}/{shardId}/{entity}/updateentitytemplate` | **Full replacement** of the custom template |
|
|
17
|
+
|
|
18
|
+
If the entity is also exposed under a nested route (e.g.
|
|
19
|
+
`{communityId}/forums/{forumId}/subjects/`), the three suffixes exist there too.
|
|
20
|
+
|
|
21
|
+
> ⚠️ **Writing to the template of a production community or event changes a
|
|
22
|
+
> customer's data model.** To declare a field, use `PATCH`: it is the only one
|
|
23
|
+
> of the two writes that cannot erase custom fields you did not write.
|
|
24
|
+
|
|
25
|
+
`inwink_mcp_find_api_endpoint` publishes the PATCH body, typed, with the list of accepted
|
|
26
|
+
field types: call it for the exact payload shape. This page covers what it does not
|
|
27
|
+
say — the compared semantics of the three routes, and their blind spots.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## PATCH — add / modify / remove a field (preferred)
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
PATCH {api}/{shardId}/{entity}/template
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"replaceFields": {
|
|
40
|
+
"feedbackType": {
|
|
41
|
+
"type": "selectlist",
|
|
42
|
+
"labels": { "fr": "Type de retour", "en": "Feedback type" },
|
|
43
|
+
"valuesList": [
|
|
44
|
+
{ "key": "bug", "labels": { "fr": "Anomalie", "en": "Bug" } },
|
|
45
|
+
{ "key": "idea", "labels": { "fr": "Idée", "en": "Idea" } }
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"scopes": { "feedbackType": ["private"] }
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The API reads the stored template, applies the patch to it, then writes it back. **Any key not
|
|
54
|
+
mentioned in the patch is left as is** — this is what makes the operation safe without
|
|
55
|
+
having to read the template beforehand.
|
|
56
|
+
|
|
57
|
+
- `replaceFields` — map `field key → definition`. The entry fully **replaces** the
|
|
58
|
+
field definition (no property-by-property merge): send the complete
|
|
59
|
+
field definition, not just the property that changes. A key absent from the template is
|
|
60
|
+
added to it.
|
|
61
|
+
- `replaceFields: { "myKey": null }` — **removes** the field from the template. Two side effects:
|
|
62
|
+
its entry in `scopes` remains, and the key is not recorded in `oldKeys`, which the
|
|
63
|
+
PATCH body does not carry.
|
|
64
|
+
- `scopes` — map `field key → array of scopes`. Each entry **overwrites** the scopes array
|
|
65
|
+
of that key; a patch cannot remove an entry from `scopes`. A patch that
|
|
66
|
+
contains only `scopes` is valid: it is used to expose or hide a field, including a
|
|
67
|
+
native field, without redefining any field.
|
|
68
|
+
- A field added by a patch is placed at the end of `fields`.
|
|
69
|
+
- The dictionary key is authoritative: a `key` property inside the definition is
|
|
70
|
+
overwritten with it.
|
|
71
|
+
- Response: `200` with no body; `204` if the body is empty.
|
|
72
|
+
|
|
73
|
+
### What is outside the scope of PATCH
|
|
74
|
+
|
|
75
|
+
The PATCH body carries only `replaceFields` and `scopes`, and expresses deletion only
|
|
76
|
+
on fields. Three needs therefore require POST:
|
|
77
|
+
|
|
78
|
+
- **removing an entry from `scopes`** — a patch rewrites it, never removes it;
|
|
79
|
+
- **setting `oldKeys`** — absent from the PATCH body;
|
|
80
|
+
- **resetting a template**, or **enforcing the order of `fields`**.
|
|
81
|
+
|
|
82
|
+
None of these three needs comes up when declaring a custom field: stay on PATCH.
|
|
83
|
+
|
|
84
|
+
## POST — replace the whole template
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
POST {api}/{shardId}/{entity}/updateentitytemplate
|
|
88
|
+
```
|
|
89
|
+
*(`POST {api}/{shardId}/{entity}/template` is a second endpoint, with the same body and the same
|
|
90
|
+
effect.)*
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"fields": [
|
|
95
|
+
{ "key": "feedbackType", "type": "selectlist", "valuesList": [] }
|
|
96
|
+
],
|
|
97
|
+
"scopes": { "feedbackType": ["private"] },
|
|
98
|
+
"oldKeys": []
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The body **becomes** the stored template: any custom field absent from `fields` is lost, and
|
|
103
|
+
any scope absent from `scopes` along with it. Note that `fields` is here an **array** whose every
|
|
104
|
+
element carries its own `key`, whereas `PATCH` and `GET worktemplate` use a **map**.
|
|
105
|
+
|
|
106
|
+
Use `POST` only if you own the entire template, or for one
|
|
107
|
+
of the three needs listed above. In particular, **the result of `GET worktemplate` cannot be
|
|
108
|
+
sent back as is**: the shape of `fields` differs and the response contains the native
|
|
109
|
+
fields, which the write rejects.
|
|
110
|
+
|
|
111
|
+
## GET worktemplate — read
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
GET {api}/{shardId}/{entity}/worktemplate
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"fields": { "mail": { "key": "mail", "type": "Mail" } },
|
|
120
|
+
"scopes": { "mail": ["bo"] },
|
|
121
|
+
"oldKeys": ["id", "eventId", "mail"],
|
|
122
|
+
"version": "2026-09-21T09:14:22Z"
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- `fields` — consolidated map of **native fields + custom fields**, in display shape
|
|
127
|
+
(`display`, `validation`, `file`…), different from the write shape.
|
|
128
|
+
- `oldKeys` — the keys of the entity's **static** fields (its native columns), in
|
|
129
|
+
camelCase. This is the list of names already taken: a custom field cannot reuse them.
|
|
130
|
+
- `version` — date of the template's last modification. Neither of the two writes takes
|
|
131
|
+
this token as input: there is no optimistic concurrency control, hence the value of
|
|
132
|
+
`PATCH`, whose read-write window stays server-side.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Rejected fields
|
|
137
|
+
|
|
138
|
+
Some keys or some types cannot be saved as a custom field. By
|
|
139
|
+
default the API **silently ignores them** and responds `200`. To have them reported,
|
|
140
|
+
add the header:
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
iwk-Validation: strict
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The request then responds `400` with, per offending key,
|
|
147
|
+
`errors.<key> = "forbidden field: <reason>"`:
|
|
148
|
+
|
|
149
|
+
| Reason | Cause |
|
|
150
|
+
|---|---|
|
|
151
|
+
| `MissingKey` | empty key |
|
|
152
|
+
| `StaticField` | the key is a native column of the entity (see `oldKeys`) |
|
|
153
|
+
| `LockedField` | the key is a dynamic field locked by the platform |
|
|
154
|
+
| `DeclaredAsStatic` | you set `isStatic: true` on the field |
|
|
155
|
+
| `DeclaredAsLocked` | you set `isLocked: true` on the field |
|
|
156
|
+
| `UnsupportedType` | `type` missing, unknown, or reserved for the platform |
|
|
157
|
+
|
|
158
|
+
On `POST`, the rejected field is removed but its entry in `scopes` is kept.
|
|
159
|
+
|
|
160
|
+
## Field definition
|
|
161
|
+
|
|
162
|
+
`type` is written by its name (`Text`, `SelectList`, `Bool`…). **The list of types accepted
|
|
163
|
+
for a custom field is the one published by `inwink_mcp_find_api_endpoint`** in the `type`
|
|
164
|
+
enumeration of the PATCH body: the API reads it from its own validator, so it cannot diverge —
|
|
165
|
+
do not copy it from here.
|
|
166
|
+
|
|
167
|
+
The numeric value is accepted too, and that is the form in which the type may appear
|
|
168
|
+
elsewhere (notably in the output of `inwink_mcp_get_entity_description`): `Text` 1,
|
|
169
|
+
`MultiLineText` 2, `SelectList` 3, `MultiSelectList` 4, `Regex` 5, `Mail` 6, `Date` 7,
|
|
170
|
+
`Number` 8, `Bool` 9, `NullableBool` 10, `File` 11, `Time` 12, `Picture` 13, `Image` 14,
|
|
171
|
+
`FileVideo` 15, `SelectTree` 16, `MultiSelectTree` 17, `NestedEntity` 50, `Object` 95,
|
|
172
|
+
`Document` 113.
|
|
173
|
+
|
|
174
|
+
Common properties:
|
|
175
|
+
|
|
176
|
+
- Shared — `isMandatory`, `isLocalizable`, `isPersonalData`, `isTechnical`,
|
|
177
|
+
`isCollection`, `defaultValue`, `defaultDisplay`.
|
|
178
|
+
- Display, per language — `labels`, `placeholders`, `descriptions`, `remarks`:
|
|
179
|
+
`{ "fr": "…", "en": "…" }`.
|
|
180
|
+
- `Number` — `min`, `max`, `nbDecimalLimit`. `Regex` — `regex`.
|
|
181
|
+
- `SelectList` / `MultiSelectList` / `*Tree` — `valuesList`, a list of entries
|
|
182
|
+
`{ "key": "…", "labels": { "fr": "…" }, "valuesList": [] }` (nested `valuesList` for
|
|
183
|
+
trees), plus `valuesListSort` for display order. On native fields,
|
|
184
|
+
`GET worktemplate` marks these entries `isSelectable: true`.
|
|
185
|
+
- Files (`File`, `Image`, `FileVideo`, `Document`) — `isPublicFile`, `maxSize`,
|
|
186
|
+
`mimeTypes`, `aspectRatio`. See [files.md](./files.md) for uploading values.
|
|
187
|
+
|
|
188
|
+
Do not set `isStatic` or `isLocked`: these flags describe what the platform
|
|
189
|
+
declares itself and cause the field to be rejected.
|
|
190
|
+
|
|
191
|
+
## scopes
|
|
192
|
+
|
|
193
|
+
`scopes` maps a field key to an array of scope names, which decides who sees the
|
|
194
|
+
field (`public`, `bo`, `private`, `own`… depending on the API and the entity). These are strings
|
|
195
|
+
interpreted by the entity's configuration, not a closed enumeration: to find out
|
|
196
|
+
which ones are meaningful on a given entity, look at the `scopes` that `GET worktemplate`
|
|
197
|
+
already returns for its fields.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
*See also: [update.md](./update.md), [entities.md](./entities.md), [files.md](./files.md).*
|