funifier-mcp 0.1.0 → 0.2.3

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.
Files changed (114) hide show
  1. package/.cursor/rules/funifier.mdc +91 -0
  2. package/.github/copilot-instructions.md +83 -0
  3. package/AGENTS.md +97 -0
  4. package/README.md +351 -351
  5. package/datasource-funifier-docs/knowledge/guides/aggregates.md +152 -0
  6. package/datasource-funifier-docs/knowledge/guides/database-access.md +132 -0
  7. package/datasource-funifier-docs/knowledge/guides/java-entities.md +373 -0
  8. package/datasource-funifier-docs/knowledge/guides/java-libraries.md +330 -0
  9. package/datasource-funifier-docs/knowledge/guides/java-managers.md +509 -0
  10. package/datasource-funifier-docs/knowledge/guides/triggers-guide.md +271 -0
  11. package/datasource-funifier-docs/knowledge/index.md +121 -0
  12. package/datasource-funifier-docs/knowledge/modules/achievement.md +46 -0
  13. package/datasource-funifier-docs/knowledge/modules/action-log.md +88 -0
  14. package/datasource-funifier-docs/knowledge/modules/action.md +80 -0
  15. package/datasource-funifier-docs/knowledge/modules/auth.md +104 -0
  16. package/datasource-funifier-docs/knowledge/modules/avatar.md +28 -0
  17. package/datasource-funifier-docs/knowledge/modules/backup.md +40 -0
  18. package/datasource-funifier-docs/knowledge/modules/challenge.md +91 -0
  19. package/datasource-funifier-docs/knowledge/modules/compact.md +40 -0
  20. package/datasource-funifier-docs/knowledge/modules/competition.md +149 -0
  21. package/datasource-funifier-docs/knowledge/modules/crossword.md +41 -0
  22. package/datasource-funifier-docs/knowledge/modules/csv-data.md +30 -0
  23. package/datasource-funifier-docs/knowledge/modules/custom-object.md +53 -0
  24. package/datasource-funifier-docs/knowledge/modules/database.md +241 -0
  25. package/datasource-funifier-docs/knowledge/modules/folder.md +111 -0
  26. package/datasource-funifier-docs/knowledge/modules/kpi-formulas.md +23 -0
  27. package/datasource-funifier-docs/knowledge/modules/lastmile.md +45 -0
  28. package/datasource-funifier-docs/knowledge/modules/leaderboard.md +98 -0
  29. package/datasource-funifier-docs/knowledge/modules/level.md +83 -0
  30. package/datasource-funifier-docs/knowledge/modules/lottery.md +112 -0
  31. package/datasource-funifier-docs/knowledge/modules/marketplace.md +27 -0
  32. package/datasource-funifier-docs/knowledge/modules/mystery.md +82 -0
  33. package/datasource-funifier-docs/knowledge/modules/notification.md +40 -0
  34. package/datasource-funifier-docs/knowledge/modules/patterns.md +1096 -0
  35. package/datasource-funifier-docs/knowledge/modules/player.md +101 -0
  36. package/datasource-funifier-docs/knowledge/modules/point.md +67 -0
  37. package/datasource-funifier-docs/knowledge/modules/public.md +253 -0
  38. package/datasource-funifier-docs/knowledge/modules/question.md +136 -0
  39. package/datasource-funifier-docs/knowledge/modules/quiz.md +163 -0
  40. package/datasource-funifier-docs/knowledge/modules/scheduler.md +58 -0
  41. package/datasource-funifier-docs/knowledge/modules/security.md +169 -0
  42. package/datasource-funifier-docs/knowledge/modules/staging.md +28 -0
  43. package/datasource-funifier-docs/knowledge/modules/static-repo.md +41 -0
  44. package/datasource-funifier-docs/knowledge/modules/story.md +42 -0
  45. package/datasource-funifier-docs/knowledge/modules/studio-page.md +180 -0
  46. package/datasource-funifier-docs/knowledge/modules/swap.md +132 -0
  47. package/datasource-funifier-docs/knowledge/modules/team.md +75 -0
  48. package/datasource-funifier-docs/knowledge/modules/trigger.md +189 -0
  49. package/datasource-funifier-docs/knowledge/modules/upload.md +155 -0
  50. package/datasource-funifier-docs/knowledge/modules/virtual-good.md +99 -0
  51. package/datasource-funifier-docs/knowledge/modules/webhook.md +41 -0
  52. package/datasource-funifier-docs/knowledge/modules/websocket.md +41 -0
  53. package/datasource-funifier-docs/knowledge/modules/widget.md +42 -0
  54. package/datasource-funifier-docs/process-gtm-saas.md +143 -0
  55. package/datasource-funifier-docs/process-instagram.md +88 -0
  56. package/datasource-funifier-docs/process.md +1826 -0
  57. package/datasource-funifier-docs/readme.md +132 -0
  58. package/dist/cli/config-writers.d.ts +15 -0
  59. package/dist/cli/config-writers.d.ts.map +1 -0
  60. package/dist/cli/config-writers.js +55 -0
  61. package/dist/cli/config-writers.js.map +1 -0
  62. package/dist/cli/config-writers.test.d.ts +2 -0
  63. package/dist/cli/config-writers.test.d.ts.map +1 -0
  64. package/dist/cli/config-writers.test.js +55 -0
  65. package/dist/cli/config-writers.test.js.map +1 -0
  66. package/dist/cli/copy.d.ts +6 -0
  67. package/dist/cli/copy.d.ts.map +1 -0
  68. package/dist/cli/copy.js +63 -0
  69. package/dist/cli/copy.js.map +1 -0
  70. package/dist/cli/copy.test.d.ts +2 -0
  71. package/dist/cli/copy.test.d.ts.map +1 -0
  72. package/dist/cli/copy.test.js +94 -0
  73. package/dist/cli/copy.test.js.map +1 -0
  74. package/dist/cli/init.d.ts +2 -0
  75. package/dist/cli/init.d.ts.map +1 -0
  76. package/dist/cli/init.js +167 -0
  77. package/dist/cli/init.js.map +1 -0
  78. package/dist/cli/paths.d.ts +7 -0
  79. package/dist/cli/paths.d.ts.map +1 -0
  80. package/dist/cli/paths.js +62 -0
  81. package/dist/cli/paths.js.map +1 -0
  82. package/dist/cli/paths.test.d.ts +2 -0
  83. package/dist/cli/paths.test.d.ts.map +1 -0
  84. package/dist/cli/paths.test.js +50 -0
  85. package/dist/cli/paths.test.js.map +1 -0
  86. package/dist/cli/platforms.d.ts +22 -0
  87. package/dist/cli/platforms.d.ts.map +1 -0
  88. package/dist/cli/platforms.js +50 -0
  89. package/dist/cli/platforms.js.map +1 -0
  90. package/dist/cli/prompts.d.ts +7 -0
  91. package/dist/cli/prompts.d.ts.map +1 -0
  92. package/dist/cli/prompts.js +49 -0
  93. package/dist/cli/prompts.js.map +1 -0
  94. package/dist/index.js +1 -1
  95. package/dist/index.js.map +1 -1
  96. package/dist/mcp/bundle.js +98 -50
  97. package/dist/mcp/index.js +18 -1
  98. package/dist/mcp/index.js.map +1 -1
  99. package/package.json +70 -65
  100. package/skills/funifier-create-action/SKILL.md +86 -86
  101. package/skills/funifier-create-aggregate/SKILL.md +126 -87
  102. package/skills/funifier-create-challenge/SKILL.md +87 -87
  103. package/skills/funifier-create-custom-page/SKILL.md +126 -87
  104. package/skills/funifier-create-leaderboard/SKILL.md +87 -87
  105. package/skills/funifier-create-level/SKILL.md +86 -86
  106. package/skills/funifier-create-point/SKILL.md +86 -86
  107. package/skills/funifier-create-quiz/SKILL.md +86 -86
  108. package/skills/funifier-create-scheduler/SKILL.md +126 -87
  109. package/skills/funifier-create-trigger/SKILL.md +127 -88
  110. package/skills/funifier-create-virtual-good/SKILL.md +86 -86
  111. package/skills/funifier-debug/SKILL.md +90 -90
  112. package/skills/funifier-help/SKILL.md +85 -85
  113. package/skills/funifier-implement-frontend/SKILL.md +89 -89
  114. package/skills/funifier-index/SKILL.md +50 -50
@@ -0,0 +1,101 @@
1
+ # Player (Jogador)
2
+
3
+ **Acesso Studio:** `/studio/player`
4
+ **API Endpoint:** `/v3/player`
5
+
6
+ ## O que é
7
+
8
+ Cadastro e gerenciamento dos participantes da gamificação. Permite cadastrar e detalhar cada jogador, incluindo nome, login, email, equipes, amigos, foto, avatar e informações adicionais como telefone, integração com redes sociais e data de aniversário. Também é possível definir senha para cada jogador.
9
+
10
+ ## Quando usar
11
+
12
+ - Em todo projeto de gamificação (obrigatório)
13
+ - Para cadastrar participantes da gamificação
14
+ - Para associar jogadores a equipes
15
+ - Para armazenar informações extras (departamento, cargo, etc.)
16
+
17
+ ## Checklist de Configuração no Studio
18
+
19
+ - [ ] Definir o _id do jogador (login)
20
+ - [ ] Definir nome do jogador
21
+ - [ ] Definir email (se necessário para notificações)
22
+ - [ ] Associar a equipes (se aplicável)
23
+ - [ ] Definir campos extras no campo "extra" (departamento, cargo, etc.)
24
+ - [ ] Definir senha (se autenticação for necessária)
25
+
26
+ ## API Endpoints
27
+
28
+ ### Listar Jogadores
29
+ **Método:** GET
30
+ **Endpoint:** `/v3/player`
31
+ **Descrição:** Retorna todos os jogadores cadastrados.
32
+
33
+ **Exemplo de Resposta:**
34
+ ```json
35
+ [
36
+ {
37
+ "_id": "jerry",
38
+ "name": "Jerry",
39
+ "email": "jerry@yourdomain.com",
40
+ "extra": { "company": "Tom & Jerry Inc." },
41
+ "created": 1694990893810,
42
+ "updated": 1694990893880
43
+ }
44
+ ]
45
+ ```
46
+
47
+ ### Criar e Atualizar Jogador
48
+ **Método:** POST
49
+ **Endpoint:** `/v3/player`
50
+ **Descrição:** Cria um novo jogador com atributos personalizados ou atualiza um jogador existente.
51
+
52
+ **Exemplo de Body:**
53
+ ```json
54
+ {
55
+ "_id": "jerry",
56
+ "name": "Jerry",
57
+ "email": "jerry@yourdomain.com",
58
+ "image": {
59
+ "small": { "url": "https://my.funifier.com/images/funny.png" },
60
+ "medium": { "url": "https://my.funifier.com/images/funny.png" },
61
+ "original": { "url": "https://my.funifier.com/images/funny.png" }
62
+ },
63
+ "teams": ["cartoon"],
64
+ "friends": ["tom", "spike"],
65
+ "extra": {
66
+ "country": "USA",
67
+ "company": "Tom & Jerry Inc."
68
+ }
69
+ }
70
+ ```
71
+
72
+ ### Excluir Jogador
73
+ **Método:** DELETE
74
+ **Endpoint:** `/v3/player/:id`
75
+ **Descrição:** Remove o jogador e todas as suas informações.
76
+
77
+ ### Consultar Status do Jogador
78
+ **Método:** GET
79
+ **Endpoint:** `/v3/player/:id/status`
80
+ **Descrição:** Retorna estatísticas do jogador (pontos, nível, desafios, itens).
81
+
82
+ **Exemplo de Resposta:**
83
+ ```json
84
+ {
85
+ "name": "Jerry",
86
+ "total_challenges": 0,
87
+ "total_points": 0,
88
+ "level_progress": {
89
+ "percent_completed": 0,
90
+ "next_level": { "level": "Apprentice", "minPoints": 10 }
91
+ },
92
+ "_id": "jerry"
93
+ }
94
+ ```
95
+
96
+ ## Validações e Testes
97
+
98
+ - [ ] Jogador aparece na lista GET /v3/player
99
+ - [ ] Status do jogador retorna dados corretos via GET /v3/player/:id/status
100
+ - [ ] Campos extras estão acessíveis no objeto "extra"
101
+ - [ ] Equipes do jogador estão corretas no array "teams"
@@ -0,0 +1,67 @@
1
+ # Point (Ponto)
2
+
3
+ **Acesso Studio:** `/studio/point`
4
+ **API Endpoint:** `/v3/point`
5
+
6
+ ## O que é
7
+
8
+ Configuração dos diferentes tipos de pontuação que os jogadores podem conquistar. Permite criar e personalizar unidades de medida de progresso, como XP, moedas virtuais, pontos de conhecimento ou métricas customizadas. Os pontos são fundamentais para recompensar ações, mensurar desempenho e alimentar outros módulos como rankings, lojas virtuais e desafios.
9
+
10
+ ## Quando usar
11
+
12
+ - Em todo projeto de gamificação (obrigatório)
13
+ - Para criar moedas virtuais de troca (ex: coins)
14
+ - Para criar pontos de experiência (ex: XP)
15
+ - Para criar métricas customizadas (ex: karma, conhecimento)
16
+
17
+ ## Checklist de Configuração no Studio
18
+
19
+ - [ ] Definir _id do ponto (letras minúsculas, ex: xp, coin, karma)
20
+ - [ ] Definir category (nome amigável, ex: "Experience Points")
21
+ - [ ] Definir shortName (abreviação, ex: "XP")
22
+ - [ ] Configurar antes dos Challenges (Points são dependência)
23
+
24
+ ## API Endpoints
25
+
26
+ ### Listar Pontos
27
+ **Método:** GET
28
+ **Endpoint:** `/v3/point`
29
+
30
+ **Exemplo de Resposta:**
31
+ ```json
32
+ [
33
+ {
34
+ "category": "Exchangeable Coins",
35
+ "shortName": "Coins",
36
+ "extra": {},
37
+ "techniques": ["GT75"],
38
+ "_id": "coin"
39
+ }
40
+ ]
41
+ ```
42
+
43
+ ### Criar Ponto
44
+ **Método:** POST
45
+ **Endpoint:** `/v3/point`
46
+
47
+ **Exemplo de Body:**
48
+ ```json
49
+ {
50
+ "_id": "xp",
51
+ "category": "Experience Points",
52
+ "shortName": "XP",
53
+ "extra": {},
54
+ "techniques": ["GT01"]
55
+ }
56
+ ```
57
+
58
+ ### Excluir Ponto
59
+ **Método:** DELETE
60
+ **Endpoint:** `/v3/point/:id`
61
+
62
+ ## Validações e Testes
63
+
64
+ - [ ] Ponto aparece na lista GET /v3/point
65
+ - [ ] _id é único e sem caracteres especiais
66
+ - [ ] shortName está curto e representativo
67
+ - [ ] Ponto é criado ANTES de challenges que o referenciam
@@ -0,0 +1,253 @@
1
+ # Public (Endpoints Públicos)
2
+
3
+ **Acesso Studio:** `/studio/public`
4
+ **API Endpoint:** `/v3/public`
5
+
6
+ ## O que é
7
+
8
+ Criação e gerenciamento de endpoints públicos personalizados. Esses endpoints são ideais para integração com plataformas externas (como Circle, Zapier, Typeform), pois não exigem autenticação via token. A autenticação é feita via `apikey` incluída na URL pública no formato: `/v3/pub/{apikey}/{slug}`.
9
+
10
+ ## Quando usar
11
+
12
+ - Para receber dados de formulários externos (Typeform, Google Forms)
13
+ - Para integrar com automações (Zapier, Make)
14
+ - Para criar webhooks de recebimento
15
+ - Para endpoints que não requerem autenticação por token
16
+
17
+ ## Checklist de Configuração no Studio
18
+
19
+ - [ ] Definir _id (slug) do endpoint
20
+ - [ ] Definir título e descrição
21
+ - [ ] Definir método HTTP (GET, POST, etc.)
22
+ - [ ] Escrever script Java com método `public Object handle(Object payload)`
23
+ - [ ] Ativar endpoint (active: true)
24
+ - [ ] Testar via URL pública
25
+
26
+ ## API Endpoints
27
+
28
+ ### Listar Public Endpoints
29
+ **Método:** GET
30
+ **Endpoint:** `/v3/database/public_endpoint`
31
+
32
+ **Exemplo de Resposta:**
33
+ ```json
34
+ [
35
+ {
36
+ "_id": "recebe_email",
37
+ "title": "Recebe Email",
38
+ "description": "Recebe email e registra na colecao email__c",
39
+ "active": true,
40
+ "method": "POST",
41
+ "script": "public Object handle(Object payload) { payload._id = payload.email; manager.getJongoConnection().getCollection(\"email__c\").save(payload); Map<String, Object> response = new HashMap<>(); response.put(\"email\", payload.email); return response; }",
42
+ "sample": "{ \"email\": \"user@email.com\" }",
43
+ "extra": {}
44
+ }
45
+ ]
46
+ ```
47
+
48
+ ### Criar Public Endpoint
49
+ **Método:** POST
50
+ **Endpoint:** `/v3/public`
51
+
52
+ ### Executar Public Endpoint
53
+ **Método:** POST (ou conforme configurado)
54
+ **Endpoint:** `/v3/pub/{apikey}/{slug}`
55
+ **Descrição:** Executa o endpoint público. Não requer token de autenticação.
56
+
57
+ ## Script Runtime Environment (Wrapper Class)
58
+
59
+ O script que você escreve no Studio **não é standalone** — ele é inserido dentro de uma classe Java wrapper gerada automaticamente pelo Funifier. Isso tem implicações importantes:
60
+
61
+ ### Estrutura do Wrapper
62
+
63
+ ```java
64
+ // --- Imports automáticos (NÃO escreva import no seu script) ---
65
+ import groovyx.net.http.*
66
+ import static groovyx.net.http.Method.*
67
+ import static groovyx.net.http.ContentType.*
68
+ import groovy.json.*
69
+ import groovy.transform.TimedInterrupt
70
+ import java.util.concurrent.TimeUnit
71
+ import java.util.Arrays
72
+ import java.util.Scanner
73
+ import org.apache.http.HttpResponse
74
+ import org.apache.http.client.HttpClient
75
+ import org.apache.http.client.methods.HttpGet
76
+ import org.apache.http.client.methods.HttpPost
77
+ import org.apache.http.impl.client.HttpClientBuilder
78
+ import org.apache.commons.io.IOUtils
79
+ import java.lang.StringBuffer
80
+ import java.io.*
81
+ import com.fasterxml.jackson.core.JsonProcessingException
82
+ // Unirest (HTTP client)
83
+ import com.mashape.unirest.http.HttpResponse
84
+ import com.mashape.unirest.http.JsonNode
85
+ import com.mashape.unirest.http.Unirest
86
+ import com.mashape.unirest.http.exceptions.UnirestException
87
+ import com.mashape.unirest.request.GetRequest
88
+ import com.mashape.unirest.request.HttpRequestWithBody
89
+ // Mail (Simple Java Mail)
90
+ import org.simplejavamail.email.Email
91
+ import org.simplejavamail.email.EmailBuilder
92
+ import org.simplejavamail.mailer.MailerBuilder
93
+ // Funifier entities
94
+ import com.funifier.engine.action.*
95
+ import com.funifier.engine.achievement.*
96
+ import com.funifier.engine.lottery.*
97
+ import com.funifier.engine.challenge.*
98
+ import com.funifier.engine.constant.*
99
+ import com.funifier.engine.guid.*
100
+ import com.funifier.engine.level.*
101
+ import com.funifier.engine.notify.*
102
+ import com.funifier.engine.player.*
103
+ import com.funifier.engine.point.*
104
+ import com.funifier.engine.team.*
105
+ import com.funifier.engine.catalog.*
106
+ import com.funifier.engine.mail.*
107
+ // Funifier utils
108
+ import com.funifier.engine.util.DateUtil
109
+ import com.funifier.engine.util.JsonUtil
110
+ import com.funifier.engine.util.HttpUtil
111
+ import com.funifier.engine.util.HttpClientFunifier
112
+ import com.funifier.engine.util.MustacheUtils
113
+ import com.funifier.controller.ManagerFactory
114
+
115
+ @TimedInterrupt(value = 5L, unit = TimeUnit.SECONDS)
116
+ class FunifierPublicEndpoint {
117
+ ManagerFactory manager = null;
118
+ void setManager(ManagerFactory c) { manager = c; }
119
+
120
+ // --- SEU SCRIPT É INSERIDO AQUI ---
121
+ }
122
+ ```
123
+
124
+ ### Regras para escrever scripts
125
+
126
+ 1. **NÃO use `import`** — todos os imports necessários já estão no wrapper. Se precisar de uma classe não importada, use o nome completo (fully qualified): `com.example.MinhaClasse`
127
+ 2. **O método principal é `public Object handle(Object payload)`** — este é o entry point
128
+ 3. **`manager` está disponível** como campo da classe (ManagerFactory)
129
+ 4. **Timeout padrão de 10 segundos** — o executor limita a execução. **Pode ser customizado** via campo `timeout` (em segundos) no objeto do endpoint — ver seção "Campo timeout" abaixo. Nota: o `@TimedInterrupt(5s)` no wrapper Groovy é uma segunda camada de proteção
130
+ 5. **Groovy, não Java puro** — o script roda em Groovy, então features como GString, closures e tipagem dinâmica funcionam
131
+ 6. **Cuidado com `$` em GStrings** — operadores MongoDB (`$set`, `$inc`) e strings com `$` são interpretados como variáveis Groovy. Use `String.valueOf((char)0x24)` para escapar:
132
+ ```groovy
133
+ def d = String.valueOf((char)0x24) // = "$"
134
+ def setCmd = '{"' + d + 'set": {"name": "Novo Nome"}}'
135
+ ```
136
+ 7. **Use apenas ASCII em comentários** — caracteres UTF-8 especiais (em dash `—`, acentos em comentários) podem causar erros de parse no Groovy
137
+ 8. **`instanceof` é bloqueado** pelo SecureASTCustomizer — use `getClass().getName()` ou try/catch
138
+ 9. **NÃO use `groovy.json.JsonSlurper`** para parsear JSON que será retornado na response — o `LazyMap` do JsonSlurper causa `ClassCastException: [B incompatible with [C` quando o Funifier tenta serializar. Use `JsonUtil.fromJsonToMap(jsonString)` em vez de `slurper.parseText(jsonString)`
139
+ 10. **Player.extra é público** — acesse direto com `player.extra`, não com `player.getExtra()` (método não existe)
140
+ 11. **Para salvar player:** `manager.getPlayerManager().findById(id)` → modifique → `manager.getPlayerManager().insert(player)` (upsert)
141
+
142
+ ### Campo `timeout` (Customizar timeout do script)
143
+
144
+ O timeout padrão de **10 segundos** (confirmado no source: `PublicManager.java` linha 255) pode ser insuficiente para endpoints que fazem chamadas HTTP externas (ex: verificar token OAuth, chamar APIs de IA, download de imagens). O campo `timeout` permite aumentar esse limite.
145
+
146
+ **Campo:** `timeout` (Long, em **segundos**)
147
+ **Padrão:** `null` (usa 10 segundos — source: `PublicManager.java:255`)
148
+ **Nota:** Este campo **não aparece no formulário do Studio** — só pode ser configurado via API.
149
+
150
+ ```bash
151
+ # Exemplo: definir timeout de 30 segundos para o endpoint google_login
152
+ curl -X POST "https://service2.funifier.com/v3/public" \
153
+ -H "Authorization: Basic <token>" \
154
+ -H "Content-Type: application/json" \
155
+ -d '{"_id": "google_login", "timeout": 30}'
156
+ ```
157
+
158
+ **Este campo também existe em Triggers e Schedulers** — mesma estrutura, mesma API (`/v3/trigger`, `/v3/scheduler`).
159
+
160
+ **Mecanismo de execução (Java):**
161
+ ```java
162
+ // O executor usa Executors.newSingleThreadExecutor() com Future.get(timeout, TimeUnit.SECONDS)
163
+ long timeout = 10; // padrão
164
+ if (endpoint.timeout != null && endpoint.timeout > 0) {
165
+ timeout = endpoint.timeout;
166
+ }
167
+ Object result = future.get(timeout, TimeUnit.SECONDS);
168
+ ```
169
+
170
+ **Nota:** O `@TimedInterrupt(value = 5L, unit = TimeUnit.SECONDS)` no wrapper Groovy é uma segunda camada de proteção. O timeout do executor (campo `timeout`) é a camada principal e deve ser >= ao TimedInterrupt para funcionar corretamente.
171
+
172
+ **Estrutura da classe PublicEndpoint (Java):**
173
+ ```java
174
+ public class PublicEndpoint {
175
+ public String _id; // slug (URL identifier)
176
+ public String apikey; // gamification apikey
177
+ public String title; // friendly name
178
+ public String description; // internal description
179
+ public boolean active; // enabled/disabled
180
+ public String method; // "POST" or "GET" (default: "POST")
181
+ public String script; // Groovy script body
182
+ public Long timeout; // timeout in SECONDS (null = default 10s)
183
+ public String sample; // example payload
184
+ public Date updated; // last update timestamp
185
+ public Map<String, Object> extra; // extra metadata
186
+ }
187
+ ```
188
+
189
+ **Quando usar timeout customizado:**
190
+ - Endpoints que fazem chamadas HTTP externas (OAuth, APIs externas)
191
+ - Endpoints com BCrypt hashing (custo computacional)
192
+ - Endpoints que fazem múltiplas operações em sequência
193
+ - **Recomendação:** 20-30s para endpoints com chamadas externas
194
+
195
+ ### Atualizar Public Endpoint via API
196
+
197
+ ```
198
+ POST /v3/public
199
+ Authorization: Basic <base64(apiKey + ":")>
200
+ Content-Type: application/json
201
+
202
+ {
203
+ "_id": "slug_do_endpoint",
204
+ "title": "Titulo",
205
+ "description": "Descricao",
206
+ "active": true,
207
+ "method": "POST",
208
+ "script": "public Object handle(Object payload) { ... }",
209
+ "sample": "{}",
210
+ "extra": {}
211
+ }
212
+ ```
213
+
214
+ O mesmo endpoint serve para criar e atualizar (upsert por `_id`)
215
+
216
+ ### Bibliotecas HTTP disponíveis
217
+
218
+ | Biblioteca | Uso recomendado |
219
+ |-----------|----------------|
220
+ | **Unirest** | HTTP client mais simples — `Unirest.post(url).header(...).body(...).asJson()` |
221
+ | **Apache HttpClient** | Alternativa mais verbosa |
222
+ | **groovyx.net.http** | HTTP Builder para Groovy |
223
+ | **HttpUtil / HttpClientFunifier** | Utilitários Funifier |
224
+
225
+ ### Exemplo usando Unirest
226
+
227
+ ```groovy
228
+ public Object handle(Object payload) {
229
+ def response = Unirest.post("https://api.external.com/endpoint")
230
+ .header("Content-Type", "application/json")
231
+ .header("Authorization", "Bearer my-token")
232
+ .body(JsonUtil.toJson(payload))
233
+ .asString()
234
+
235
+ def result = new groovy.json.JsonSlurper().parseText(response.getBody())
236
+ return result
237
+ }
238
+ ```
239
+
240
+ > ⚠️ **Triggers e Schedulers usam a mesma estrutura de wrapper** com os mesmos imports pré-disponíveis. A diferença é apenas o método principal: triggers usam `void trigger(event, entity, player, database)` e schedulers usam `void execute()`.
241
+
242
+ ## Boas Práticas
243
+
244
+ - Não expor dados sensíveis em endpoints públicos
245
+ - Não realizar operações críticas sem validação adicional
246
+ - Validar payload recebido no script Java
247
+
248
+ ## Validações e Testes
249
+
250
+ - [ ] Endpoint aparece na lista
251
+ - [ ] URL pública é acessível sem token
252
+ - [ ] Script processa payload corretamente
253
+ - [ ] Resposta é retornada conforme esperado
@@ -0,0 +1,136 @@
1
+ # Question (Pergunta)
2
+
3
+ **Acesso Studio:** `/studio/question`
4
+ **API Endpoint:** `/v3/question`
5
+
6
+ ## O que é
7
+
8
+ Configuração de perguntas e respostas para os jogadores. Permite criar perguntas em diferentes formatos (múltipla escolha, verdadeiro/falso, com mídia), definir respostas corretas ou colher opiniões, e aplicar pesos diferentes para as perguntas. A apresentação pode ser no formato tradicional ou em mini games como caça-palavras e cruzadinhas.
9
+
10
+ ## Quando usar
11
+
12
+ - Para criar quizzes e avaliações
13
+ - Para pesquisas de opinião
14
+ - Para treinamentos e capacitação
15
+ - Para mini games educativos
16
+
17
+ ## Checklist de Configuração no Studio
18
+
19
+ - [ ] Definir tipo da pergunta (MULTIPLE_CHOICE, TRUE_FALSE, etc.)
20
+ - [ ] Definir título e texto da pergunta
21
+ - [ ] Criar opções de resposta com grades (pontuação)
22
+ - [ ] Definir se permite uma ou múltiplas respostas (select)
23
+ - [ ] Configurar embaralhamento (shuffle)
24
+ - [ ] Definir peso/grade da pergunta
25
+
26
+ ## API Endpoints
27
+
28
+ ### Listar Perguntas
29
+ **Método:** GET
30
+ **Endpoint:** `/v3/question`
31
+
32
+ ### Criar Pergunta
33
+ **Método:** POST
34
+ **Endpoint:** `/v3/question`
35
+
36
+ **Exemplo de Body:**
37
+ ```json
38
+ {
39
+ "_id": "64a5b2c2d8dcca49bcf7eb6e",
40
+ "type": "MULTIPLE_CHOICE",
41
+ "title": "Visual Components",
42
+ "question": "In Funifier, what is the small visual components that can be added to a web page to display feedbacks?",
43
+ "grade": 1,
44
+ "choices": [
45
+ { "answer": "1", "label": "Points", "grade": 0, "extra": {} },
46
+ { "answer": "2", "label": "Badges", "grade": 0, "extra": {} },
47
+ { "answer": "3", "label": "Challenges", "grade": 0, "extra": {} },
48
+ { "answer": "4", "label": "Leaderboards", "grade": 0, "extra": {} },
49
+ { "answer": "5", "label": "Widgets", "grade": 1, "extra": {} }
50
+ ],
51
+ "techniques": ["GT05"],
52
+ "select": "one_answer",
53
+ "answerNumbering": "uppercase_letters",
54
+ "shuffle": false,
55
+ "feedbacks": [],
56
+ "extra": {}
57
+ }
58
+ ```
59
+
60
+ ### Deletar Pergunta
61
+ **Método:** DELETE
62
+ **Endpoint:** `/v3/question/:id`
63
+
64
+ ### Listar Respostas de Jogadores
65
+ **Método:** GET
66
+ **Endpoint:** `/v3/question/log?question=:id`
67
+
68
+ ### Criar Resposta de Jogador
69
+ **Método:** POST
70
+ **Endpoint:** `/v3/question/log`
71
+
72
+ **Exemplo de Body:**
73
+ ```json
74
+ {
75
+ "question": "64a5b2c2d8dcca49bcf7eb6e",
76
+ "answer": ["5"],
77
+ "player": "tom"
78
+ }
79
+ ```
80
+
81
+ ### Deletar Resposta
82
+ **Método:** DELETE
83
+ **Endpoint:** `/v3/question/log/:id`
84
+
85
+ ## Tipos de Pergunta
86
+
87
+ | Tipo | Descrição |
88
+ |------|-----------|
89
+ | `MULTIPLE_CHOICE` | Múltipla escolha (uma ou várias respostas) |
90
+ | `TRUE_FALSE` | Verdadeiro ou Falso |
91
+ | `ESSAY` | Dissertativa (resposta livre) |
92
+ | `CROSSWORD` | Caça-palavras (mini game) |
93
+ | `WORD_SEARCH` | Cruzadinha (mini game) |
94
+
95
+ ## Campos Importantes
96
+
97
+ | Campo | Tipo | Descrição |
98
+ |-------|------|-----------|
99
+ | `quiz` | String | ID do quiz pai (vincula pergunta ao quiz) |
100
+ | `type` | String | Tipo da pergunta (ver tabela acima) |
101
+ | `question` | String | Texto da pergunta |
102
+ | `grade` | Number | Peso/pontuação da pergunta |
103
+ | `choices` | Array | Opções de resposta (ver estrutura abaixo) |
104
+ | `select` | String | `one_answer` ou `multiple_answers` |
105
+ | `shuffle` | Boolean | Embaralhar opções |
106
+ | `techniques` | Array | IDs de técnicas de jogos vinculadas |
107
+
108
+ ### Estrutura de Choice (Opção de Resposta)
109
+
110
+ ```json
111
+ {
112
+ "answer": "1", // identificador único da opção
113
+ "label": "Funifier", // texto exibido
114
+ "grade": 1, // pontuação se escolhida (0 = errada)
115
+ "gradePercent": 100, // percentual de acerto
116
+ "gradeCheck": true, // indica se é resposta correta
117
+ "extra": {} // metadados adicionais
118
+ }
119
+ ```
120
+
121
+ ## Formatos de Apresentação
122
+
123
+ Perguntas podem incluir conteúdo rico:
124
+ - Texto com HTML
125
+ - Imagens (campo `image`)
126
+ - Vídeos e áudio (via `extra`)
127
+ - Mini games (caça-palavras, cruzadinha)
128
+
129
+ ## Validações e Testes
130
+
131
+ - [ ] Pergunta aparece na lista GET /v3/question
132
+ - [ ] Resposta do jogador é registrada corretamente (POST /v3/question/log)
133
+ - [ ] Grade é calculada com base na resposta
134
+ - [ ] Opções de resposta estão corretas
135
+ - [ ] Vinculação com quiz funciona (campo `quiz`)
136
+ - [ ] Registro em lote funciona (POST /v3/question/log/bulk)