funifier-mcp 0.2.26 → 0.2.28
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/.cursor/rules/funifier.mdc +38 -41
- package/.github/copilot-instructions.md +38 -41
- package/AGENTS.md +56 -49
- package/README.md +40 -22
- package/datasource-funifier-docs/.coverage.json +326 -0
- package/datasource-funifier-docs/.validation.json +593 -0
- package/datasource-funifier-docs/knowledge/guides/aggregates.md +182 -70
- package/datasource-funifier-docs/knowledge/guides/database-access.md +174 -88
- package/datasource-funifier-docs/knowledge/guides/java-entities.md +294 -204
- package/datasource-funifier-docs/knowledge/guides/java-libraries.md +202 -226
- package/datasource-funifier-docs/knowledge/guides/java-managers.md +343 -265
- package/datasource-funifier-docs/knowledge/guides/trigger-examples.md +180 -236
- package/datasource-funifier-docs/knowledge/guides/triggers-guide.md +273 -191
- package/datasource-funifier-docs/knowledge/index.md +4 -1
- package/datasource-funifier-docs/knowledge/modules/achievement.md +1126 -28
- package/datasource-funifier-docs/knowledge/modules/action-log.md +469 -62
- package/datasource-funifier-docs/knowledge/modules/action.md +522 -70
- package/datasource-funifier-docs/knowledge/modules/auth.md +718 -69
- package/datasource-funifier-docs/knowledge/modules/avatar.md +483 -18
- package/datasource-funifier-docs/knowledge/modules/backup.md +603 -25
- package/datasource-funifier-docs/knowledge/modules/challenge.md +1048 -220
- package/datasource-funifier-docs/knowledge/modules/compact.md +469 -26
- package/datasource-funifier-docs/knowledge/modules/competition.md +811 -109
- package/datasource-funifier-docs/knowledge/modules/crossword.md +504 -28
- package/datasource-funifier-docs/knowledge/modules/csv-data.md +645 -20
- package/datasource-funifier-docs/knowledge/modules/custom-object.md +701 -36
- package/datasource-funifier-docs/knowledge/modules/database.md +730 -164
- package/datasource-funifier-docs/knowledge/modules/folder.md +935 -280
- package/datasource-funifier-docs/knowledge/modules/kpi-formulas.md +410 -15
- package/datasource-funifier-docs/knowledge/modules/lastmile.md +568 -29
- package/datasource-funifier-docs/knowledge/modules/leaderboard.md +595 -126
- package/datasource-funifier-docs/knowledge/modules/level.md +536 -54
- package/datasource-funifier-docs/knowledge/modules/lottery.md +809 -76
- package/datasource-funifier-docs/knowledge/modules/marketplace.md +688 -17
- package/datasource-funifier-docs/knowledge/modules/mystery.md +662 -52
- package/datasource-funifier-docs/knowledge/modules/notification.md +564 -26
- package/datasource-funifier-docs/knowledge/modules/patterns.md +519 -814
- package/datasource-funifier-docs/knowledge/modules/player.md +773 -73
- package/datasource-funifier-docs/knowledge/modules/point.md +380 -83
- package/datasource-funifier-docs/knowledge/modules/public.md +508 -178
- package/datasource-funifier-docs/knowledge/modules/question.md +619 -99
- package/datasource-funifier-docs/knowledge/modules/quiz.md +565 -120
- package/datasource-funifier-docs/knowledge/modules/scheduler.md +1092 -39
- package/datasource-funifier-docs/knowledge/modules/security.md +674 -112
- package/datasource-funifier-docs/knowledge/modules/staging.md +742 -19
- package/datasource-funifier-docs/knowledge/modules/story.md +565 -29
- package/datasource-funifier-docs/knowledge/modules/studio-page.md +470 -144
- package/datasource-funifier-docs/knowledge/modules/swap.md +552 -84
- package/datasource-funifier-docs/knowledge/modules/team.md +563 -45
- package/datasource-funifier-docs/knowledge/modules/trigger.md +876 -134
- package/datasource-funifier-docs/knowledge/modules/upload.md +468 -95
- package/datasource-funifier-docs/knowledge/modules/virtual-good.md +510 -63
- package/datasource-funifier-docs/knowledge/modules/webhook.md +375 -28
- package/datasource-funifier-docs/knowledge/modules/websocket.md +459 -26
- package/datasource-funifier-docs/knowledge/modules/widget.md +613 -27
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +42 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/init.test.js +74 -3
- package/dist/cli/init.test.js.map +1 -1
- package/dist/cli/persona.d.ts +3 -0
- package/dist/cli/persona.d.ts.map +1 -0
- package/dist/cli/persona.js +25 -0
- package/dist/cli/persona.js.map +1 -0
- package/dist/mcp/bundle.js +119 -93
- package/dist/mcp/check-update.d.ts +5 -0
- package/dist/mcp/check-update.d.ts.map +1 -1
- package/dist/mcp/check-update.js +21 -10
- package/dist/mcp/check-update.js.map +1 -1
- package/dist/mcp/check-update.test.d.ts +2 -0
- package/dist/mcp/check-update.test.d.ts.map +1 -0
- package/dist/mcp/check-update.test.js +33 -0
- package/dist/mcp/check-update.test.js.map +1 -0
- package/dist/mcp/index.js +2 -2
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/prompts/templates.d.ts.map +1 -1
- package/dist/mcp/prompts/templates.js +35 -0
- package/dist/mcp/prompts/templates.js.map +1 -1
- package/dist/mcp/resources/documentation.d.ts +1 -1
- package/dist/mcp/resources/documentation.d.ts.map +1 -1
- package/dist/mcp/resources/documentation.js +39 -3
- package/dist/mcp/resources/documentation.js.map +1 -1
- package/dist/mcp/tools/connect.d.ts.map +1 -1
- package/dist/mcp/tools/connect.js +18 -8
- package/dist/mcp/tools/connect.js.map +1 -1
- package/dist/mcp/tools/database.d.ts.map +1 -1
- package/dist/mcp/tools/database.js +59 -47
- package/dist/mcp/tools/database.js.map +1 -1
- package/dist/mcp/tools/database.test.js +2 -2
- package/dist/mcp/tools/database.test.js.map +1 -1
- package/dist/mcp/tools/delete.d.ts.map +1 -1
- package/dist/mcp/tools/delete.js +13 -3
- package/dist/mcp/tools/delete.js.map +1 -1
- package/dist/mcp/tools/execute.d.ts.map +1 -1
- package/dist/mcp/tools/execute.js +20 -9
- package/dist/mcp/tools/execute.js.map +1 -1
- package/dist/mcp/tools/folder.d.ts.map +1 -1
- package/dist/mcp/tools/folder.js +22 -12
- package/dist/mcp/tools/folder.js.map +1 -1
- package/dist/mcp/tools/get.d.ts.map +1 -1
- package/dist/mcp/tools/get.js +16 -6
- package/dist/mcp/tools/get.js.map +1 -1
- package/dist/mcp/tools/index.d.ts +1 -1
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js +28 -1
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/list.d.ts.map +1 -1
- package/dist/mcp/tools/list.js +38 -14
- package/dist/mcp/tools/list.js.map +1 -1
- package/dist/mcp/tools/logs.d.ts.map +1 -1
- package/dist/mcp/tools/logs.js +15 -5
- package/dist/mcp/tools/logs.js.map +1 -1
- package/dist/mcp/tools/save.d.ts.map +1 -1
- package/dist/mcp/tools/save.js +14 -4
- package/dist/mcp/tools/save.js.map +1 -1
- package/dist/mcp/tools/save.test.js +3 -3
- package/dist/mcp/tools/save.test.js.map +1 -1
- package/dist/mcp/tools/search-docs.d.ts +3 -0
- package/dist/mcp/tools/search-docs.d.ts.map +1 -0
- package/dist/mcp/tools/search-docs.js +102 -0
- package/dist/mcp/tools/search-docs.js.map +1 -0
- package/package.json +6 -2
- package/skills/acquire-funifier-knowledge/SKILL.md +155 -0
- package/skills/acquire-funifier-knowledge/assets/templates/CONCERNS.md +25 -0
- package/skills/acquire-funifier-knowledge/assets/templates/CUSTOM_ENDPOINTS.md +24 -0
- package/skills/acquire-funifier-knowledge/assets/templates/CUSTOM_PAGES.md +24 -0
- package/skills/acquire-funifier-knowledge/assets/templates/GAME_MECHANICS.md +35 -0
- package/skills/acquire-funifier-knowledge/assets/templates/INTEGRATIONS.md +35 -0
- package/skills/acquire-funifier-knowledge/assets/templates/LEADERBOARDS.md +24 -0
- package/skills/acquire-funifier-knowledge/assets/templates/OVERVIEW.md +86 -0
- package/skills/acquire-funifier-knowledge/assets/templates/PLAYER_MODEL.md +31 -0
- package/skills/acquire-funifier-knowledge/assets/templates/SCHEDULERS.md +25 -0
- package/skills/acquire-funifier-knowledge/assets/templates/TECHNIQUES_AND_PATTERNS.md +26 -0
- package/skills/acquire-funifier-knowledge/assets/templates/TRIGGERS.md +27 -0
- package/skills/acquire-funifier-knowledge/references/funifier-inventory-checklist.md +81 -0
- package/skills/acquire-funifier-knowledge/references/game-techniques-taxonomy.md +62 -0
- package/skills/acquire-funifier-knowledge/references/mcp-call-patterns.md +118 -0
- package/skills/funifier/SKILL.md +88 -0
- package/skills/funifier/references/configure-security.md +96 -0
- package/skills/{funifier-create-action/SKILL.md → funifier/references/create-action.md} +0 -33
- package/skills/funifier/references/create-aggregate.md +144 -0
- package/skills/funifier/references/create-challenge.md +116 -0
- package/skills/funifier/references/create-competition.md +98 -0
- package/skills/funifier/references/create-crossword.md +574 -0
- package/skills/funifier/references/create-custom-object.md +91 -0
- package/skills/funifier/references/create-custom-page.md +135 -0
- package/skills/funifier/references/create-folder.md +104 -0
- package/skills/funifier/references/create-lastmile.md +643 -0
- package/skills/{funifier-create-leaderboard/SKILL.md → funifier/references/create-leaderboard.md} +0 -33
- package/skills/funifier/references/create-level.md +94 -0
- package/skills/funifier/references/create-lottery.md +913 -0
- package/skills/funifier/references/create-mystery.md +769 -0
- package/skills/funifier/references/create-notification.md +75 -0
- package/skills/{funifier-create-point/SKILL.md → funifier/references/create-point.md} +0 -33
- package/skills/funifier/references/create-quiz.md +98 -0
- package/skills/funifier/references/create-scheduler.md +141 -0
- package/skills/funifier/references/create-story.md +636 -0
- package/skills/funifier/references/create-swap.md +95 -0
- package/skills/{funifier-create-trigger/SKILL.md → funifier/references/create-trigger.md} +0 -33
- package/skills/funifier/references/create-virtual-good.md +96 -0
- package/skills/funifier/references/create-webhook.md +72 -0
- package/skills/funifier/references/create-websocket.md +71 -0
- package/skills/funifier/references/create-widget.md +76 -0
- package/skills/funifier/references/debug.md +87 -0
- package/skills/funifier/references/help.md +81 -0
- package/skills/funifier/references/implement-frontend.md +106 -0
- package/skills/funifier/references/import-csv.md +75 -0
- package/skills/funifier/references/manage-player.md +82 -0
- package/skills/funifier/references/manage-team.md +76 -0
- package/skills/funifier/references/upload-file.md +91 -0
- package/skills/funifier-create-aggregate/SKILL.md +0 -127
- package/skills/funifier-create-challenge/SKILL.md +0 -88
- package/skills/funifier-create-custom-page/SKILL.md +0 -127
- package/skills/funifier-create-level/SKILL.md +0 -87
- package/skills/funifier-create-quiz/SKILL.md +0 -87
- package/skills/funifier-create-scheduler/SKILL.md +0 -127
- package/skills/funifier-create-virtual-good/SKILL.md +0 -87
- package/skills/funifier-debug/SKILL.md +0 -92
- package/skills/funifier-help/SKILL.md +0 -86
- package/skills/funifier-implement-frontend/SKILL.md +0 -90
- package/skills/funifier-index/SKILL.md +0 -58
|
@@ -1,52 +1,227 @@
|
|
|
1
|
-
# Triggers Funifier
|
|
1
|
+
# Triggers Funifier — Guia de Conceitos
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 1. Visão Geral
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
**API Endpoint:** `/v3/trigger`
|
|
5
|
+
### 1.1 O que é este documento
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
Este documento descreve os conceitos de triggers Funifier — assinatura do script, variáveis disponíveis, eventos, entidades, regra de persistência e cadeia de conquistas — para escrever código Java/Groovy que executa no Funifier Engine quando um evento acontece. É o hub dos triggers; catálogos de managers/entidades/bibliotecas e exemplos de produção vivem em arquivos próprios.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
2
|
|
13
|
-
|
|
9
|
+
**Acesso Studio:** `/studio/trigger` · **API:** `/v3/trigger`
|
|
10
|
+
|
|
11
|
+
### 1.2 Quando consultar
|
|
12
|
+
|
|
13
|
+
- Consulte ao **criar uma trigger** e precisar entender `event`, `entity`, `script`.
|
|
14
|
+
- Consulte ao precisar saber **quais variáveis** o script recebe (`event`, `entity`, `player`, `database`, `manager`, `context`).
|
|
15
|
+
- Consulte ao escolher o **evento certo** (incl. eventos de bulk/CSV).
|
|
16
|
+
- Consulte ao precisar **rejeitar uma criação** ou entender por que `throw` não cancela.
|
|
17
|
+
- Consulte ao precisar ler a **origem de uma conquista** (`context.extra`).
|
|
18
|
+
|
|
19
|
+
### 1.3 Quando NÃO consultar
|
|
20
|
+
|
|
21
|
+
- **NÃO** consulte para os **métodos dos managers** — use `datasource-funifier-docs/knowledge/guides/java-managers.md`.
|
|
22
|
+
- **NÃO** consulte para **campos das entidades** — use `datasource-funifier-docs/knowledge/guides/java-entities.md`.
|
|
23
|
+
- **NÃO** consulte para **bibliotecas** (JsonUtil, Guid, Unirest, Email) — use `datasource-funifier-docs/knowledge/guides/java-libraries.md`.
|
|
24
|
+
- **NÃO** consulte para **exemplos de produção prontos** — use `datasource-funifier-docs/knowledge/guides/trigger-examples.md`.
|
|
25
|
+
|
|
26
|
+
### 1.4 Índice de decisão
|
|
27
|
+
|
|
28
|
+
| Problema / Situação | O que fazer | Seção |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| Montar o documento da trigger | Configuração (event/entity/script) | §2 |
|
|
31
|
+
| Saber o que o script recebe | Assinatura e variáveis implícitas | §3 |
|
|
32
|
+
| Escolher o evento | Eventos oficiais e estendidos | §4 |
|
|
33
|
+
| Escolher a entidade | Entidades disponíveis | §5 |
|
|
34
|
+
| Saber o tipo do `entity` para cada combinação | Combinações Evento × Entidade | §6 |
|
|
35
|
+
| Saber qual ação/conquista originou o evento | `context.extra` (cadeia de conquistas) | §7 |
|
|
36
|
+
| Rejeitar uma criação inválida | Regra de persistência + BusinessException | §8 |
|
|
37
|
+
| Processar import/insert em lote | `entity` como List (bulk) | §9 |
|
|
38
|
+
|
|
39
|
+
### 1.5 Restrições globais críticas
|
|
40
|
+
|
|
41
|
+
> ⚠️ **`throw` NÃO cancela a persistência.** O Funifier persiste o documento; lançar exceção não faz rollback (`trigger-examples.md`). Consequência: tentativas de "bloquear" criação com `throw` falham silenciosamente. → `before_create` serve só para **enriquecer** (normalizar, defaults, metadados); para **rejeitar**, use `after_create` + `database.delete(...)` (§8).
|
|
42
|
+
|
|
43
|
+
> ⚠️ **Em Groovy, acesse o ID com `entity.id`, não `entity._id`.** Consequência: `_id` retorna `null` (`patterns.md` §10). → Use `.id` em código; `_id` só no JSON/documento. Vale para `entity`, `player`, `ActionLog`, `Achievement`.
|
|
44
|
+
|
|
45
|
+
> ⚠️ **O evento depende do método HTTP que originou a operação.** `PUT` → `before_update`/`after_update`; `POST` → `before_create`/`after_create` (`patterns.md` §1.5, `modules/trigger.md` §3.1). Consequência: a trigger esperada não roda. → Escolha o método no frontend conforme o evento da trigger (ex: Signup usa `PUT` para acionar `before_update`).
|
|
46
|
+
|
|
47
|
+
> ⚠️ **Nunca dispare `track`/`trackSynchonous` para a mesma ação que acionou a trigger.** Consequência: loop infinito (`java-managers.md` §1.5). → Filtre por `entity.actionId` antes ou use outra ação.
|
|
48
|
+
|
|
49
|
+
> ⚠️ **Timeout default de trigger: 5s** (configurável via campo `timeout` no `POST /v3/trigger`; não aparece no Studio). O teto independente do `@TimedInterrupt` é 200s. Tabela completa em `patterns.md` §1.5.
|
|
50
|
+
|
|
51
|
+
### 1.6 Documentos relacionados
|
|
52
|
+
|
|
53
|
+
> 📄 `datasource-funifier-docs/knowledge/guides/trigger-examples.md` — exemplos de produção (JSON + Groovy)
|
|
54
|
+
> 📄 `datasource-funifier-docs/knowledge/guides/java-managers.md` — métodos de `manager.get*Manager()`
|
|
55
|
+
> 📄 `datasource-funifier-docs/knowledge/guides/java-entities.md` — campos do `entity` por tipo
|
|
56
|
+
> 📄 `datasource-funifier-docs/knowledge/guides/java-libraries.md` — JsonUtil, Guid, DateUtil, Unirest, Email
|
|
57
|
+
> 📄 `datasource-funifier-docs/knowledge/guides/database-access.md` — `database.getCollection(...)`
|
|
58
|
+
> 📄 `datasource-funifier-docs/knowledge/modules/patterns.md` §1.5 — sandbox, timeouts, eventos por método HTTP
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 2. Configuração de uma Trigger
|
|
63
|
+
|
|
64
|
+
Quando usar: ao criar/atualizar o documento da trigger.
|
|
65
|
+
Não usar quando: já tem o documento e precisa só do código → §3.
|
|
66
|
+
Depende de: `Trigger` (entidade — `java-entities.md` §10).
|
|
67
|
+
Disponível em: Trigger.
|
|
68
|
+
|
|
69
|
+
### Descrição
|
|
70
|
+
|
|
71
|
+
Uma trigger é um documento com três informações essenciais: **evento** (quando roda), **entidade** (que objeto está vinculado) e **script** (código a executar).
|
|
72
|
+
|
|
73
|
+
### Uso
|
|
14
74
|
|
|
15
75
|
```json
|
|
16
76
|
{
|
|
17
77
|
"name": "Make the player's name uppercase",
|
|
18
78
|
"_id": "DTv7uHc",
|
|
19
|
-
"description": "
|
|
79
|
+
"description": "Antes de criar o player, deixa o nome em maiúsculas",
|
|
20
80
|
"entity": "player",
|
|
21
81
|
"event": "before_create",
|
|
22
82
|
"script": "void trigger(event, entity, player, database){ entity.name = entity.name.toUpperCase(); }"
|
|
23
83
|
}
|
|
24
84
|
```
|
|
25
85
|
|
|
26
|
-
|
|
86
|
+
O campo `timeout` (segundos) só é configurável via API (`patterns.md` §1.5).
|
|
87
|
+
|
|
88
|
+
### Armadilhas conhecidas
|
|
89
|
+
|
|
90
|
+
- **Atualizar a trigger via `POST` parcial** → o `script` pode ser apagado (full replace; `patterns.md` §1.5). Correção: reenviar o documento completo.
|
|
91
|
+
|
|
92
|
+
---
|
|
27
93
|
|
|
28
|
-
|
|
94
|
+
## 3. Assinatura do Script e Variáveis Implícitas
|
|
95
|
+
|
|
96
|
+
Quando usar: ao escrever o corpo do script.
|
|
97
|
+
Não usar quando: —
|
|
98
|
+
Depende de: `manager` (managers), `context` (cadeia de conquistas §7), `database` (Jongo).
|
|
99
|
+
Disponível em: Trigger.
|
|
100
|
+
|
|
101
|
+
### Descrição
|
|
102
|
+
|
|
103
|
+
O script define a função `trigger` com quatro parâmetros. Além deles, o runtime expõe variáveis **implícitas** (não declaradas na assinatura): `manager`, `context` e `println`.
|
|
104
|
+
|
|
105
|
+
### Uso
|
|
106
|
+
|
|
107
|
+
```java
|
|
108
|
+
void trigger(event, entity, player, database) {
|
|
109
|
+
// PARÂMETROS:
|
|
110
|
+
// event — String do evento (ex: "before_create")
|
|
111
|
+
// entity — objeto manipulado (Player, ActionLog, Achievement, HashMap de __c…)
|
|
112
|
+
// player — String com o ID do jogador
|
|
113
|
+
// database — conexão Jongo (database.getCollection(...) — ver database-access.md)
|
|
114
|
+
|
|
115
|
+
// IMPLÍCITOS (não na assinatura):
|
|
116
|
+
// manager — ManagerFactory: manager.getPlayerManager()… (java-managers.md)
|
|
117
|
+
// context — contexto da execução; context.extra traz a origem (§7)
|
|
118
|
+
// println — log para o trigger_log
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Exemplo mínimo (enriquecimento):
|
|
123
|
+
```groovy
|
|
124
|
+
void trigger(event, entity, player, database) {
|
|
125
|
+
entity.name = entity.name.toUpperCase(); // mutação persiste (before_create)
|
|
126
|
+
println("normalizado: " + entity.id); // .id, não ._id (§1.5)
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Armadilhas conhecidas
|
|
131
|
+
|
|
132
|
+
- **Esperar `manager`/`context` na assinatura** → são implícitos; use-os direto.
|
|
133
|
+
- **Usar `entity._id`** → `null` em Groovy. Correção: `entity.id` (§1.5).
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 4. Eventos
|
|
138
|
+
|
|
139
|
+
Quando usar: ao definir `event` na trigger.
|
|
140
|
+
Não usar quando: —
|
|
141
|
+
Depende de: método HTTP da operação (§1.5).
|
|
142
|
+
Disponível em: Trigger.
|
|
143
|
+
|
|
144
|
+
### Descrição
|
|
145
|
+
|
|
146
|
+
Eventos definem **quando** a trigger roda. Os oficiais aparecem no dropdown do Studio; os estendidos só por texto livre.
|
|
147
|
+
|
|
148
|
+
### Uso
|
|
149
|
+
|
|
150
|
+
**Oficiais (dropdown):**
|
|
29
151
|
|
|
30
152
|
| Evento | Quando é acionado |
|
|
31
153
|
|--------|-------------------|
|
|
32
|
-
| `
|
|
33
|
-
| `
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
36
|
-
| `
|
|
37
|
-
|
|
154
|
+
| `before_win` / `after_win` | Antes/depois de registrar uma conquista |
|
|
155
|
+
| `before_lose` / `after_lose` | Antes/depois de remover uma conquista |
|
|
156
|
+
| `before_create` / `after_create` | Antes/depois de persistir um novo documento |
|
|
157
|
+
| `before_update` / `after_update` | Antes/depois de atualizar |
|
|
158
|
+
| `before_delete` / `after_delete` | Antes/depois de deletar |
|
|
159
|
+
|
|
160
|
+
**Estendidos (free-text — não aparecem no dropdown):**
|
|
161
|
+
|
|
162
|
+
| Evento | Quando é acionado |
|
|
163
|
+
|--------|-------------------|
|
|
164
|
+
| `before_bulk` / `after_bulk` | Antes/depois de insert/update em lote via API |
|
|
165
|
+
| `csv_before_bulk` / `csv_after_bulk` | Antes/depois de processar um import CSV |
|
|
166
|
+
|
|
167
|
+
> Nos eventos de bulk/CSV, `entity` é uma **List**, não um único documento (§9).
|
|
168
|
+
|
|
169
|
+
### Armadilhas conhecidas
|
|
170
|
+
|
|
171
|
+
- **`before_create` esperando bloquear via `throw`** → não cancela (§1.5/§8).
|
|
172
|
+
- **`POST` esperando acionar `before_update`** → `POST` dispara `before_create` (§1.5).
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 5. Entidades
|
|
177
|
+
|
|
178
|
+
Quando usar: ao definir `entity` na trigger.
|
|
179
|
+
Não usar quando: —
|
|
180
|
+
Depende de: `java-entities.md` (tipos resultantes).
|
|
181
|
+
Disponível em: Trigger.
|
|
182
|
+
|
|
183
|
+
### Descrição
|
|
184
|
+
|
|
185
|
+
A entidade vincula a trigger a um tipo de objeto. O Studio oferece um dropdown fixo + entidades dinâmicas; texto livre aceita qualquer nome.
|
|
186
|
+
|
|
187
|
+
### Uso
|
|
188
|
+
|
|
189
|
+
**Dropdown hardcoded:** `action`, `catalog`, `catalog_item`, `crown`, `leaderboard`, `level`, `player`, `team`, `challenge`, `point_category`, `character_star_stats_level`, `upload`, `mystery_box`, `lottery`
|
|
38
190
|
|
|
39
|
-
|
|
191
|
+
**Dinâmicas** (via `/v3/database/collections`): `achievement` e todas as coleções `__c` do projeto.
|
|
40
192
|
|
|
41
|
-
|
|
42
|
-
|
|
193
|
+
**Excluídas** (não aparecem; acesse por código): `action_log`, `challenge_progress`, `player_status`, `security`, `technique_field`, `join_log`.
|
|
194
|
+
|
|
195
|
+
**Free-text:** o formulário aceita qualquer nome de entidade/evento não listado.
|
|
196
|
+
|
|
197
|
+
### Armadilhas conhecidas
|
|
198
|
+
|
|
199
|
+
- **Procurar `action_log` no dropdown** → não aparece (é excluída). Para reagir a logs, use `entity: action` com evento `before_win`/`after_win`.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 6. Combinações Evento × Entidade
|
|
204
|
+
|
|
205
|
+
Quando usar: para saber o **tipo do `entity`** numa dada combinação.
|
|
206
|
+
Não usar quando: precisar dos campos desse tipo → `java-entities.md`.
|
|
207
|
+
Depende de: §4, §5, `java-entities.md`.
|
|
208
|
+
Disponível em: Trigger.
|
|
209
|
+
|
|
210
|
+
### Descrição
|
|
211
|
+
|
|
212
|
+
Cada combinação evento+entidade entrega um `entity` de tipo específico. Os mais usados:
|
|
213
|
+
|
|
214
|
+
### Uso
|
|
215
|
+
|
|
216
|
+
| Evento | Entidade | Quando | Tipo do `entity` |
|
|
217
|
+
|--------|----------|--------|----------------|
|
|
43
218
|
| `before_create` | `player` | Antes de cadastrar jogador | Player |
|
|
44
219
|
| `after_create` | `player` | Depois de cadastrar jogador | Player |
|
|
45
220
|
| `before_update` | `player` | Antes de alterar jogador | Player |
|
|
46
221
|
| `after_delete` | `player` | Depois de remover jogador | Player |
|
|
47
222
|
| `after_create` | `challenge` | Depois de criar desafio | Challenge |
|
|
48
223
|
| `after_win` | `challenge` | Depois de completar desafio | Achievement |
|
|
49
|
-
| `before_create` | `action` | Antes de criar ação | Action |
|
|
224
|
+
| `before_create` | `action` | Antes de criar definição de ação | Action |
|
|
50
225
|
| `before_win` | `action` | Antes de registrar action log | ActionLog |
|
|
51
226
|
| `after_win` | `level` | Depois de subir de nível | Achievement |
|
|
52
227
|
| `after_win` | `catalog_item` | Depois de comprar item | Achievement |
|
|
@@ -57,215 +232,122 @@ Uma trigger é composta de três informações essenciais:
|
|
|
57
232
|
| `before_create` | `achievement` | Antes de registrar recompensa | Achievement |
|
|
58
233
|
| `before_create` | `<custom>__c` | Antes de criar objeto customizado | HashMap |
|
|
59
234
|
|
|
60
|
-
|
|
235
|
+
### Armadilhas conhecidas
|
|
61
236
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// event: String com o evento (ex: "before_create")
|
|
65
|
-
// entity: Objeto sendo manipulado (Player, ActionLog, Achievement, etc.)
|
|
66
|
-
// player: String com o ID do jogador
|
|
67
|
-
// database: Objeto para acessar o banco de dados
|
|
68
|
-
}
|
|
69
|
-
```
|
|
237
|
+
- **Assumir que `before_win action` entrega um Action** → entrega um **ActionLog** (o registro de execução), não a definição.
|
|
238
|
+
- **Tratar `__c` como POJO** → é `HashMap`; use `entity.get("campo")` (`java-entities.md` §12).
|
|
70
239
|
|
|
71
|
-
|
|
240
|
+
---
|
|
72
241
|
|
|
73
|
-
|
|
74
|
-
```json
|
|
75
|
-
{"_id": "john", "name": "John Travolta", "email": "john@funifier.com", "image": {"small": {"url": "..."}, "medium": {"url": "..."}, "original": {"url": "..."}}, "teams": ["sales"], "extra": {"country": "USA", "department": "IT"}}
|
|
76
|
-
```
|
|
242
|
+
## 7. context.extra — Cadeia de Conquistas
|
|
77
243
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
244
|
+
Quando usar: ao precisar saber qual ação/conquista originou o evento atual.
|
|
245
|
+
Não usar quando: o evento não vem de uma cadeia (`context.extra` pode ser `null`).
|
|
246
|
+
Depende de: `Achievement`, `ActionLog` (`java-entities.md`).
|
|
247
|
+
Disponível em: Trigger (eventos `before_win`, `before_create`, `after_create`).
|
|
82
248
|
|
|
83
|
-
###
|
|
84
|
-
```json
|
|
85
|
-
{"_id": "64a5d2", "player": "john", "total": 25.0, "type": 0, "item": "xp", "time": {"$date": "2023-07-05T20:57:33.303Z"}}
|
|
86
|
-
```
|
|
87
|
-
Tipos: `TYPE_POINT=0`, `TYPE_CHALLENGE=1`, `TYPE_VIRTUAL_GOOD=2`, `TYPE_LEVEL=3`
|
|
88
|
-
|
|
89
|
-
### Challenge
|
|
90
|
-
```json
|
|
91
|
-
{"challenge": "Watch Video", "active": true, "_id": "DTo8dS3", "rules": [{"actionId": "watch_video", "operator": 5, "total": 0}], "points": [{"total": 10.0, "category": "xp", "operation": 0}]}
|
|
92
|
-
```
|
|
249
|
+
### Descrição
|
|
93
250
|
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
{"_id": "sell", "action": "Sell", "attributes": [{"name": "product", "type": "String"}, {"name": "price", "type": "Number"}], "active": true}
|
|
97
|
-
```
|
|
251
|
+
Quando uma conquista é gerada por uma cadeia (uma ação dispara um desafio, que concede pontos…), `context.extra` expõe a origem. Disponível nos eventos acima quando há cadeia.
|
|
98
252
|
|
|
99
|
-
|
|
253
|
+
### Uso
|
|
100
254
|
|
|
101
|
-
### PlayerManager
|
|
102
255
|
```java
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
256
|
+
context.extra.parentAchievement // Achievement que gerou este evento
|
|
257
|
+
context.extra.parentAchievement.id // String
|
|
258
|
+
context.extra.parentAchievement.type // int (constantes em java-entities.md §3)
|
|
259
|
+
context.extra.parentAchievement.item // String
|
|
260
|
+
context.extra.parentAchievement.player // String
|
|
261
|
+
context.extra.parentAchievement.total // double
|
|
262
|
+
|
|
263
|
+
context.extra.parentActionLog // ActionLog que originou a cadeia
|
|
264
|
+
context.extra.parentActionLog.id // String
|
|
265
|
+
context.extra.parentActionLog.actionId // String
|
|
266
|
+
context.extra.parentActionLog.userId // String
|
|
267
|
+
context.extra.parentActionLog.attributes // Map
|
|
268
|
+
|
|
269
|
+
context.extra.originActionLog // ActionLog raiz (ponta da cadeia)
|
|
106
270
|
```
|
|
107
271
|
|
|
108
|
-
|
|
109
|
-
```java
|
|
110
|
-
Action a = manager.getActionManager().findActionById("sell");
|
|
111
|
-
manager.getActionManager().track(actionLog);
|
|
112
|
-
List<Achievement> results = manager.getActionManager().trackSynchonous(actionLog);
|
|
113
|
-
```
|
|
272
|
+
Exemplo de uso em `trigger-examples.md` (Exemplo 2 — taggear conquista com origem).
|
|
114
273
|
|
|
115
|
-
###
|
|
116
|
-
```java
|
|
117
|
-
CatalogItem item = manager.getCatalogManager().findItemById("DTj7lVn");
|
|
118
|
-
manager.getCatalogManager().purchase(achievement, true);
|
|
119
|
-
manager.getCatalogManager().undoPurchase("id");
|
|
120
|
-
```
|
|
274
|
+
### Armadilhas conhecidas
|
|
121
275
|
|
|
122
|
-
|
|
123
|
-
```java
|
|
124
|
-
Lottery l = manager.getLotteryManager().find("DTj0x5z");
|
|
125
|
-
manager.getLotteryManager().insertTicket(ticket);
|
|
126
|
-
manager.getLotteryManager().execute("DTj0x5z");
|
|
127
|
-
```
|
|
276
|
+
- **Acessar `context.extra.parentAchievement` sem checar null** → NPE. Correção: `if (context.extra == null) return;` e checar cada campo.
|
|
128
277
|
|
|
129
|
-
|
|
130
|
-
```java
|
|
131
|
-
Achievement a = new Achievement();
|
|
132
|
-
a.player = "john"; a.total = 10; a.type = 0; a.item = "xp";
|
|
133
|
-
a.time = new Date(); a._id = Guid.newShortGuid();
|
|
134
|
-
manager.getAchievementManager().addAchievement(a);
|
|
135
|
-
```
|
|
278
|
+
---
|
|
136
279
|
|
|
137
|
-
|
|
138
|
-
```java
|
|
139
|
-
// Salvar
|
|
140
|
-
manager.getJongoConnection().getCollection("email__c").save(payload);
|
|
280
|
+
## 8. Regra de Persistência e Rejeição de Criação
|
|
141
281
|
|
|
142
|
-
|
|
143
|
-
|
|
282
|
+
Quando usar: ao precisar validar e **rejeitar** uma criação inválida.
|
|
283
|
+
Não usar quando: só precisa enriquecer/normalizar → use `before_create` (mutação direta).
|
|
284
|
+
Depende de: `database.delete(...)`, BusinessException (definida no próprio script).
|
|
285
|
+
Disponível em: Trigger.
|
|
144
286
|
|
|
145
|
-
|
|
146
|
-
manager.getJongoConnection().getCollection("car__c").remove("{_id: 'car001'}");
|
|
147
|
-
```
|
|
287
|
+
### Descrição
|
|
148
288
|
|
|
149
|
-
|
|
289
|
+
O Funifier persiste o documento; `throw` não cancela (§1.5). Portanto: `before_create` enriquece; **rejeição** se faz em `after_create`, deletando o documento já salvo e devolvendo a mensagem no `entity`.
|
|
150
290
|
|
|
151
|
-
###
|
|
291
|
+
### Uso
|
|
152
292
|
|
|
153
|
-
```
|
|
154
|
-
/* "event": "before_create", "entity": "achievement" */
|
|
293
|
+
```groovy
|
|
155
294
|
void trigger(event, entity, player, database) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
295
|
+
try {
|
|
296
|
+
if (condicaoInvalida) throw new BusinessException("Motivo da rejeição");
|
|
297
|
+
// ... mais validações ...
|
|
298
|
+
} catch (BusinessException e) {
|
|
299
|
+
// a exceção é capturada DENTRO do trigger — não propaga para a plataforma
|
|
300
|
+
database.delete(entity.id, "collection__c");
|
|
301
|
+
entity.clear();
|
|
302
|
+
entity.put("message", e.getMessage());
|
|
303
|
+
return;
|
|
161
304
|
}
|
|
162
305
|
}
|
|
163
|
-
```
|
|
164
306
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
void trigger(event, entity, player, database) {
|
|
170
|
-
if(entity.type == Achievement.TYPE_POINT && entity.total >= 100) {
|
|
171
|
-
Player p = manager.getPlayerManager().findById(player);
|
|
172
|
-
for(String friend : p.friends) {
|
|
173
|
-
Achievement a = new Achievement();
|
|
174
|
-
a.player = friend; a.total = 1; a.type = 0;
|
|
175
|
-
a.item = entity.item; a.time = new Date();
|
|
176
|
-
a._id = Guid.newShortGuid();
|
|
177
|
-
manager.getAchievementManager().addAchievement(a);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
307
|
+
public class BusinessException extends Exception {
|
|
308
|
+
private String message;
|
|
309
|
+
public BusinessException(String msg) { super(msg); this.message = msg; }
|
|
310
|
+
public String getMessage() { return this.message; }
|
|
180
311
|
}
|
|
181
312
|
```
|
|
182
313
|
|
|
183
|
-
|
|
314
|
+
`BusinessException` centraliza o cleanup quando há múltiplas validações. Para uma validação simples, o `database.delete` + `entity.clear()` + `entity.put("message", ...)` direto basta.
|
|
184
315
|
|
|
185
|
-
|
|
186
|
-
/* "event": "after_create", "entity": "player" */
|
|
187
|
-
void trigger(event, entity, player, database) {
|
|
188
|
-
long total = manager.getPlayerManager().findTotal();
|
|
189
|
-
Email email = EmailBuilder
|
|
190
|
-
.startingBlank()
|
|
191
|
-
.from("Company", "your@company.com")
|
|
192
|
-
.to(entity.getName(), entity.email)
|
|
193
|
-
.withSubject("Welcome!")
|
|
194
|
-
.withPlainText("Welcome " + entity.name + ", you are member number " + total)
|
|
195
|
-
.buildEmail();
|
|
196
|
-
MailerBuilder.withSMTPServer("host", 587, "login", "password")
|
|
197
|
-
.buildMailer().sendMail(email);
|
|
198
|
-
}
|
|
199
|
-
```
|
|
316
|
+
### Armadilhas conhecidas
|
|
200
317
|
|
|
201
|
-
|
|
318
|
+
- **Usar `before_create` + `throw` para rejeitar** → o documento persiste mesmo assim. Correção: `after_create` + delete (`trigger-examples.md` Exemplo 5b).
|
|
319
|
+
- **Esquecer `entity.clear()`** → o documento rejeitado retém dados (sensíveis, no caso de signup). Correção: limpar e devolver só `message`.
|
|
202
320
|
|
|
203
|
-
|
|
204
|
-
/* "event": "after_win", "entity": "catalog_item" */
|
|
205
|
-
void trigger(event, entity, player, database) {
|
|
206
|
-
Player buyer = manager.getPlayerManager().findById(entity.player);
|
|
207
|
-
CatalogItem item = manager.getCatalogManager().findItemById(entity.item);
|
|
208
|
-
HashMap zap = new HashMap();
|
|
209
|
-
zap.put("purchase", entity);
|
|
210
|
-
zap.put("buyer", buyer);
|
|
211
|
-
zap.put("item", item);
|
|
212
|
-
HttpResponse<String> response = Unirest.post("https://hooks.zapier.com/hooks/catch/80/b6/")
|
|
213
|
-
.header("Content-Type", "application/json")
|
|
214
|
-
.body(JsonUtil.toJson(zap))
|
|
215
|
-
.asString();
|
|
216
|
-
}
|
|
217
|
-
```
|
|
321
|
+
---
|
|
218
322
|
|
|
219
|
-
|
|
323
|
+
## 9. `entity` como List (Eventos de Bulk)
|
|
220
324
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
entity.extra.put("code", code);
|
|
226
|
-
}
|
|
227
|
-
```
|
|
325
|
+
Quando usar: ao reagir a `before_bulk`/`after_bulk`/`csv_*` (§4).
|
|
326
|
+
Não usar quando: o evento é de documento único (`entity` é um objeto).
|
|
327
|
+
Depende de: §4 (eventos estendidos).
|
|
328
|
+
Disponível em: Trigger.
|
|
228
329
|
|
|
229
|
-
###
|
|
330
|
+
### Descrição
|
|
230
331
|
|
|
231
|
-
|
|
232
|
-
/* "event": "before_win", "entity": "action" */
|
|
233
|
-
void trigger(event, entity, player, database) {
|
|
234
|
-
String id = entity.attributes.product;
|
|
235
|
-
Object product = database.getCollection("product__c").findOne("{_id:#}", id).as(Object.class);
|
|
236
|
-
entity.attributes.put("price", product.price);
|
|
237
|
-
}
|
|
238
|
-
```
|
|
332
|
+
Nos eventos de lote, `entity` é uma **List** de documentos, não um único. Itere e processe cada item.
|
|
239
333
|
|
|
240
|
-
###
|
|
334
|
+
### Uso
|
|
241
335
|
|
|
242
|
-
```
|
|
243
|
-
/* "event": "before_win", "entity": "action" */
|
|
336
|
+
```groovy
|
|
244
337
|
void trigger(event, entity, player, database) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
.and("{\"$limit\":1}")
|
|
251
|
-
.as(Object.class));
|
|
252
|
-
if(highest != null && highest.size() > 0) {
|
|
253
|
-
Object highestPointsPlayer = highest.get(0);
|
|
254
|
-
entity.attributes.put("highest", highestPointsPlayer.total);
|
|
338
|
+
if (entity == null || entity.isEmpty()) return;
|
|
339
|
+
for (Object raw : entity) {
|
|
340
|
+
HashMap<String, Object> item = (HashMap<String, Object>) raw;
|
|
341
|
+
if (item == null) continue;
|
|
342
|
+
// processar item...
|
|
255
343
|
}
|
|
344
|
+
println("bulk processado: " + entity.size());
|
|
256
345
|
}
|
|
257
346
|
```
|
|
258
347
|
|
|
259
|
-
|
|
348
|
+
Exemplo completo em `trigger-examples.md` (Exemplo 6).
|
|
260
349
|
|
|
261
|
-
|
|
262
|
-
- **com.mashape.unirest** - Requisições HTTP
|
|
263
|
-
- **org.jongo** - Acesso ao MongoDB
|
|
264
|
-
- **JsonUtil** - Conversão JSON
|
|
265
|
-
- **Guid** - Geração de IDs únicos
|
|
266
|
-
- **DateUtil** - Cálculos e expressões de data
|
|
350
|
+
### Armadilhas conhecidas
|
|
267
351
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
> - `guides/java-entities.md` — Entidades, campos e coleções MongoDB
|
|
271
|
-
> - `guides/java-libraries.md` — JsonUtil, Guid, DateUtil, Unirest, EmailBuilder, Jongo
|
|
352
|
+
- **Tratar `entity` como documento único em evento de bulk** → `ClassCastException`. Correção: iterar a List.
|
|
353
|
+
- **`entity.size()` em evento não-bulk** → `entity` não é List. Correção: usar List só nos eventos de §4.
|
|
@@ -11,6 +11,7 @@ A Funifier funciona como um **backend de aplicações**. Independentemente do ti
|
|
|
11
11
|
| Recurso | Ficheiro | Para que serve |
|
|
12
12
|
|---------|----------|----------------|
|
|
13
13
|
| **Auth** | `modules/auth.md` | Login de jogadores, geração de tokens JWT, autenticação via API |
|
|
14
|
+
| **Security** | `modules/security.md` | Configuração do documento de segurança — apps com app_secret, roles de jogador, escopos, pipeline de autorização e emissão de tokens Bearer |
|
|
14
15
|
| **Player** | `modules/player.md` | Cadastro e gestão de utilizadores da aplicação |
|
|
15
16
|
| **Database** | `modules/database.md` | CRUD em qualquer coleção, queries MongoDB, aggregates |
|
|
16
17
|
| **Custom Object** | `modules/custom-object.md` | Criar tabelas/coleções próprias (sufixo `__c`) para dados de negócio |
|
|
@@ -84,6 +85,7 @@ A Funifier funciona como um **backend de aplicações**. Independentemente do ti
|
|
|
84
85
|
| Módulo | Ficheiro | Descrição | Quando usar |
|
|
85
86
|
|--------|----------|-----------|-------------|
|
|
86
87
|
| Auth | `modules/auth.md` | Autenticação e tokens | Gerar tokens de acesso; configurar API keys; autenticação OAuth |
|
|
88
|
+
| Security | `modules/security.md` | Configuração de segurança | Configurar apps (app_secret, scope, whitelist) e roles de jogador; entender escopos hierárquicos, pipeline de autorização e emissão de tokens; diagnóstico de erros 401 |
|
|
87
89
|
| Folder | `modules/folder.md` | Trilhas e cursos | Criar trilhas de aprendizagem e cursos; organizar conteúdos em hierarquia com monitoramento de progresso do jogador |
|
|
88
90
|
| Backup | `modules/backup.md` | Backup e restauração | Criar backups da gamificação; restaurar configurações |
|
|
89
91
|
| Compact | `modules/compact.md` | Compactação de dados | Compactar dados históricos para otimizar performance |
|
|
@@ -98,6 +100,7 @@ A Funifier funciona como um **backend de aplicações**. Independentemente do ti
|
|
|
98
100
|
|------|----------|-----------|-------------|
|
|
99
101
|
| Aggregates | `guides/aggregates.md` | Consultas avançadas MongoDB | Criar relatórios, dashboards, rankings customizados; usar expressões de data Funifier |
|
|
100
102
|
| Triggers | `guides/triggers-guide.md` | Guia completo de triggers | Referência de eventos, entidades, managers e exemplos de código Java |
|
|
103
|
+
| Trigger Examples | `guides/trigger-examples.md` | Exemplos de produção de triggers | Código Groovy pronto para padrões reais: atualizar coleção relacionada, criar achievement, inicializar jogador, normalizar/rejeitar `__c`, processar lote, registrar ação via `track` |
|
|
101
104
|
| Database Access | `guides/database-access.md` | Acesso ao banco de dados | Referência de acesso via API REST e via código Java (Jongo) |
|
|
102
105
|
| Java Managers | `guides/java-managers.md` | Referência de managers Java | Métodos disponíveis em cada manager (PlayerManager, ActionManager, etc.) para uso em triggers, schedulers e public endpoints |
|
|
103
106
|
| Java Entities | `guides/java-entities.md` | Referência de entidades Java | Campos e tipos dos objetos (Player, Achievement, ActionLog, etc.) e mapeamento para coleções MongoDB |
|
|
@@ -116,6 +119,6 @@ Para consultas que envolvem **múltiplos módulos**, carregue cada ficheiro indi
|
|
|
116
119
|
|
|
117
120
|
Para **relatórios e queries avançadas**, consulte `guides/aggregates.md`.
|
|
118
121
|
|
|
119
|
-
Para **lógica customizada com código**, consulte `guides/triggers-guide.md` e `guides/database-access.md`.
|
|
122
|
+
Para **lógica customizada com código**, consulte `guides/triggers-guide.md` (conceitos e referência de eventos) e `guides/trigger-examples.md` (exemplos Groovy prontos), além de `guides/database-access.md`.
|
|
120
123
|
|
|
121
124
|
Para **referência completa de recursos Java** (managers, entidades, bibliotecas), consulte `guides/java-managers.md`, `guides/java-entities.md` e `guides/java-libraries.md`.
|