funifier-mcp 0.2.25 → 0.2.27
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 +5 -2
- 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 +1011 -77
- 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/core/api-client.d.ts +21 -1
- package/dist/core/api-client.d.ts.map +1 -1
- package/dist/core/api-client.js +154 -1
- package/dist/core/api-client.js.map +1 -1
- package/dist/core/constants.d.ts +14 -0
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +14 -0
- package/dist/core/constants.js.map +1 -1
- package/dist/core/types/Folder.d.ts +16 -0
- package/dist/core/types/Folder.d.ts.map +1 -0
- package/dist/core/types/Folder.js +3 -0
- package/dist/core/types/Folder.js.map +1 -0
- package/dist/core/types/FolderContent.d.ts +10 -0
- package/dist/core/types/FolderContent.d.ts.map +1 -0
- package/dist/core/types/FolderContent.js +3 -0
- package/dist/core/types/FolderContent.js.map +1 -0
- package/dist/core/types/FolderContentType.d.ts +10 -0
- package/dist/core/types/FolderContentType.d.ts.map +1 -0
- package/dist/core/types/FolderContentType.js +3 -0
- package/dist/core/types/FolderContentType.js.map +1 -0
- package/dist/core/types/FolderLog.d.ts +11 -0
- package/dist/core/types/FolderLog.d.ts.map +1 -0
- package/dist/core/types/FolderLog.js +3 -0
- package/dist/core/types/FolderLog.js.map +1 -0
- package/dist/core/types/index.d.ts +4 -0
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/core/types/index.js +4 -0
- package/dist/core/types/index.js.map +1 -1
- package/dist/mcp/bundle.js +121 -87
- package/dist/mcp/check-update.d.ts +2 -0
- package/dist/mcp/check-update.d.ts.map +1 -0
- package/dist/mcp/check-update.js +44 -0
- package/dist/mcp/check-update.js.map +1 -0
- package/dist/mcp/index.js +5 -2
- package/dist/mcp/index.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/_char-guard.js +1 -1
- package/dist/mcp/tools/_char-guard.js.map +1 -1
- package/dist/mcp/tools/_fetch-current.d.ts +1 -1
- package/dist/mcp/tools/_fetch-current.d.ts.map +1 -1
- package/dist/mcp/tools/_fetch-current.js +12 -0
- package/dist/mcp/tools/_fetch-current.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 +33 -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 +4 -0
- package/dist/mcp/tools/folder.d.ts.map +1 -0
- package/dist/mcp/tools/folder.js +68 -0
- package/dist/mcp/tools/folder.js.map +1 -0
- 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 +5 -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 +26 -4
- package/dist/mcp/tools/save.js.map +1 -1
- package/dist/mcp/tools/save.test.js +192 -1
- 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 +132 -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 +47 -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/datasource-funifier-docs/.search-index.json +0 -17318
- package/datasource-funifier-docs/.skills-map.json +0 -73
- 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,138 +1,435 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `point`
|
|
2
2
|
|
|
3
3
|
**Acesso Studio:** `/studio/point`
|
|
4
4
|
**API Endpoint:** `/v3/point`
|
|
5
|
+
**Endpoint Legado:** _(não existe — não há controller de point em `rest/engine`)_
|
|
6
|
+
**Coleção MongoDB:** `point_category` (config). Existe ainda uma coleção `point` de saldos por jogador — **legada/inerte** (vide §3.4 e §7).
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. Visão Geral
|
|
11
|
+
|
|
12
|
+
O módulo `point` é o **catálogo de tipos de ponto** de uma gamificação. Cada documento define um "tipo de moeda" do jogo — XP, Karma, Coins, Reputação, etc. — com nome amigável, abreviação, imagem e tags de técnica de jogo.
|
|
13
|
+
|
|
14
|
+
Papel arquitetural (confirmado no código):
|
|
15
|
+
|
|
16
|
+
- O módulo `point` armazena **apenas a configuração/metadados** do tipo de ponto na coleção `point_category` (`Entity.java:228` → `POINT_CATEGORY("point_category", PointCategory.class)`). Ele **não** guarda saldo de jogador.
|
|
17
|
+
- O **saldo de pontos do jogador é derivado da coleção `achievement`** (registros `type=0 / TYPE_POINT`, `item=<_id do ponto>`), somando `total` via aggregation. Esta é a fonte da verdade — vide o módulo `achievement`. O `_id` do `PointCategory` é exatamente o valor usado no campo `item` desses achievements.
|
|
18
|
+
- O `PointCategory` é consumido por outros módulos **só para resolver nome/imagem** a partir do `_id`:
|
|
19
|
+
- `challenge` — `ChallengeManager` (linhas 401, 421, 445) faz `findById(point.category)` para montar a descrição textual da recompensa (`RewardPoint.category` carrega o `_id` do ponto).
|
|
20
|
+
- `achievement` — `AchievementManager.findOptionsByType` (2841-2843) e `findOptionByTypeAndItem` (2903-2907) resolvem `_id → category/image` para dropdowns do Studio e decoração de respostas.
|
|
21
|
+
- `package` — `PackageManager` (301, 380, 438, 488) exporta/importa pontos como parte de um pacote (`findAll`, `findById`, `add`, `delete`).
|
|
22
|
+
- `technique` — `GameTechniqueManager` faz backfill da tag `techniques` e calcula analytics de uso (mapa Octalysis).
|
|
23
|
+
|
|
24
|
+
Problemas que resolve:
|
|
25
|
+
|
|
26
|
+
- Declarar os tipos de ponto que existem na gamificação e dar a eles nome de exibição (`category`), abreviação (`shortName`) e imagem.
|
|
27
|
+
- Servir como tabela de lookup `_id → metadados` para os módulos que geram/consomem pontos (challenge, action, achievement, level, leaderboard, catalog).
|
|
28
|
+
|
|
29
|
+
> ⚠️ **Correção em relação à documentação anterior:** o módulo **não** decide acúmulo, troca ou gasto de pontos. Ele é puramente declarativo. A lógica de crédito/débito/saldo vive em `achievement`. Vide §7 para o detalhamento das funcionalidades que a doc anterior atribuía erroneamente ao campo `techniques`.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 2. Arquitetura e Fluxos
|
|
34
|
+
|
|
35
|
+
### 2.1 Classes envolvidas
|
|
36
|
+
|
|
37
|
+
| Classe | Arquivo | Papel |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `PointCategory` | `engine/point/PointCategory.java` | **Entidade de config** (documento raiz da coleção `point_category`) |
|
|
40
|
+
| `Point` | `engine/point/Point.java` | Entidade de **saldo por jogador** (coleção `point`) — **legada/inerte**, vide §3.4 |
|
|
41
|
+
| `PointDaoMongo` | `engine/point/PointDaoMongo.java` | DAO Jongo das duas coleções |
|
|
42
|
+
| `PointManager` | `engine/point/PointManager.java` | Manager (delega ao DAO; resolvido via `ManagerFactory.getPointManager()`) |
|
|
43
|
+
| `PointRest` | `rest/v3/rest/PointRest.java` | Controller REST v3 (`@Path("v3/point")`) |
|
|
44
|
+
| `Image` / `ImageItem` | `engine/image/` | Sub-entidade de imagem (small/medium/original) |
|
|
45
|
+
|
|
46
|
+
Não há `Repository`/`Service` separado — `PointManager` chama `PointDaoMongo` diretamente, que usa `Jongo` sobre a conexão do tenant (`manager.getJongoConnection()`).
|
|
47
|
+
|
|
48
|
+
### 2.2 Pipeline — CRUD de tipo de ponto (caminho vivo)
|
|
49
|
+
|
|
50
|
+
Toda chamada REST entra pelo `FrontController.getInstance(authBean.getApiKey())`, que resolve o `ManagerFactory` (e a conexão Mongo) **do tenant dono daquele apiKey**. A partir daí:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
GET /v3/point → PointRest.findAll → PointManager.findAll → PointDaoMongo.findAll(point_category) → JsonUtil.toJsonRemoveNullFields(list)
|
|
54
|
+
GET /v3/point/{id} → PointRest.find → PointManager.findById → PointDaoMongo.findById(point_category) → toJsonRemoveNullFields(obj)
|
|
55
|
+
POST /v3/point → PointRest.insert → PointManager.add → PointDaoMongo.add(point_category) → toJsonRemoveNullFields(obj), 201
|
|
56
|
+
DELETE /v3/point/{id} → PointRest.delete → PointManager.delete → PointDaoMongo.delete(point_category) → 204
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Algoritmo de `add` (= o que o POST executa) — `PointDaoMongo.java:44-48`:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
se point._id é null OU vazio:
|
|
63
|
+
point._id = Guid.newShortGuid() # gera id curto automaticamente
|
|
64
|
+
collection("point_category").save(point) # Jongo save = upsert por _id
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Consequência: **POST é create-or-replace por `_id`** (não há PATCH). Se você enviar um `_id` já existente, o documento é **substituído por inteiro** (full replace), não mesclado. Campos omitidos no body somem do documento.
|
|
68
|
+
|
|
69
|
+
> Tudo é **síncrono**, sem transação. Não há disparo de trigger/webhook no CRUD de `point` (o módulo não chama `before_win`/`after_win` nem registra `*_created`).
|
|
70
|
+
|
|
71
|
+
### 2.3 Como um jogador realmente ganha pontos (integração entre módulos)
|
|
72
|
+
|
|
73
|
+
O módulo `point` só fornece metadados nesse fluxo. O crédito acontece em `achievement`:
|
|
74
|
+
|
|
75
|
+
### Sequência — jogador ganha pontos
|
|
76
|
+
|
|
77
|
+
```mermaid
|
|
78
|
+
sequenceDiagram
|
|
79
|
+
participant Client
|
|
80
|
+
participant ActionMgr as ActionManager
|
|
81
|
+
participant AchMgr as AchievementManager
|
|
82
|
+
participant PointCfg as point_category (config)
|
|
83
|
+
participant Ach as achievement (coleção)
|
|
84
|
+
|
|
85
|
+
Client->>ActionMgr: POST /v3/action/log (actionId, userId)
|
|
86
|
+
ActionMgr->>AchMgr: fireAction(actionLog)
|
|
87
|
+
Note over AchMgr: avalia RewardPoints da action/challenge
|
|
88
|
+
AchMgr->>AchMgr: addAchievement(type=0, item=<pointId>, total=N)
|
|
89
|
+
AchMgr->>Ach: insert { player, type:0, item:<pointId>, total:N }
|
|
90
|
+
Note over PointCfg: point_category NÃO é alterado<br/>(usado só p/ nome/imagem em respostas)
|
|
91
|
+
Client->>Ach: saldo = aggregate $match{type:0,item:<pointId>} + $sum:$total
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
O `point` (config) entra apenas quando a UI precisa exibir o nome/imagem do ponto (`AchievementManager.findOptionByTypeAndItem`, linha 2903). **Mudar um `PointCategory` não recalcula nada** — apenas troca o rótulo exibido dali pra frente.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 3. Estrutura dos Objetos
|
|
99
|
+
|
|
100
|
+
### 3.1 `PointCategory` — documento raiz (coleção `point_category`)
|
|
101
|
+
|
|
102
|
+
Definição: `engine/point/PointCategory.java`. Anotada com `@JsonIgnoreProperties(ignoreUnknown=true)` (linha 11) — **campos desconhecidos no POST são silenciosamente ignorados**.
|
|
103
|
+
|
|
104
|
+
| Campo | Tipo | Padrão | Obrigatório | Descrição |
|
|
105
|
+
|---|---|---|---|---|
|
|
106
|
+
| `_id` | String | auto (GUID curto se vazio) | não* | Identificador do ponto. Mapeado de `_id` via `@JsonProperty`. Se ausente/vazio no POST, `add()` gera `Guid.newShortGuid()`. |
|
|
107
|
+
| `category` | String | null | recomendado | Nome amigável exibido nas interfaces (ex.: `"Experience Points"`). |
|
|
108
|
+
| `shortName` | String | null | recomendado | Abreviação curta (ex.: `"XP"`). |
|
|
109
|
+
| `image` | `Image` | null | não | Imagem do ponto (3 tamanhos — §3.2). |
|
|
110
|
+
| `extra` | `Map<String,Object>` | `{}` (HashMap vazio) | não | Campos customizados livres. Inicializado como mapa vazio, não null. |
|
|
111
|
+
| `techniques` | `List<String>` | null | não | Tags de técnica de jogo (códigos GT). **Apenas categorização** — vide §3.3 e §7. |
|
|
112
|
+
|
|
113
|
+
\* Nenhum campo é validado como obrigatório no servidor. O `add()` aceita `category`/`shortName` nulos sem erro. **Não há validação de formato do `_id`** (espaços e maiúsculas não são rejeitados pelo backend — "minúsculas sem espaços" é convenção, não regra de código).
|
|
114
|
+
|
|
115
|
+
#### Campos legados / silenciosamente ignorados
|
|
116
|
+
|
|
117
|
+
- **`icon` (String)** — declarado em `PointCategory.java:19`, mas getter/setter estão **comentados** (linhas 62-70) e o campo é package-private. Com a visibilidade padrão do Jackson (apenas getters/setters/atributos públicos), o **REST não desserializa `icon`** mesmo que você o envie no POST — o valor permanece `null`. É um campo morto, resquício de versão antiga (substituído por `image`).
|
|
118
|
+
- **`apiKey`** — havia um campo `apiKey` na entidade (comentado em `PointCategory.java:16,32`). Não existe mais. Se enviado no POST, cai na regra `ignoreUnknown=true` e é descartado.
|
|
119
|
+
|
|
120
|
+
#### Comportamento de serialização da resposta
|
|
121
|
+
|
|
122
|
+
Todas as respostas passam por `JsonUtil.toJsonRemoveNullFields(...)` (`PointRest.java:42,60,93`): **campos `null` são removidos do JSON de resposta**. Logo, um ponto sem `image`/`techniques` retorna sem essas chaves. O `extra` (mapa vazio, não null) tende a aparecer como `{}`.
|
|
123
|
+
|
|
124
|
+
### 3.2 `Image` / `ImageItem` — sub-entidade de imagem
|
|
125
|
+
|
|
126
|
+
`Image` (`engine/image/Image.java`) tem três variações de tamanho, cada uma um `ImageItem`:
|
|
127
|
+
|
|
128
|
+
| Campo de `Image` | Tipo |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `small` | `ImageItem` |
|
|
131
|
+
| `medium` | `ImageItem` |
|
|
132
|
+
| `original` | `ImageItem` |
|
|
133
|
+
|
|
134
|
+
`ImageItem` (`engine/image/ImageItem.java`):
|
|
135
|
+
|
|
136
|
+
| Campo | Tipo | Observação |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| `_id` | String | id do arquivo (usado em operações de upload/exclusão) |
|
|
139
|
+
| `type` | String | |
|
|
140
|
+
| `name` | String | |
|
|
141
|
+
| `url` | String | URL pública da imagem |
|
|
142
|
+
| `size` | int | default 0 |
|
|
143
|
+
| `width` | int | default 0 |
|
|
144
|
+
| `height` | int | default 0 |
|
|
145
|
+
| `depth` | int | default 0 |
|
|
146
|
+
| `format` | String | |
|
|
147
|
+
|
|
148
|
+
Na prática basta preencher `url` nos três tamanhos. Os campos numéricos default `0` são aceitos.
|
|
149
|
+
|
|
150
|
+
### 3.3 Técnicas de jogo (`techniques`)
|
|
151
|
+
|
|
152
|
+
`techniques` é uma `List<String>` livre de **códigos GT** (catálogo Octalysis). O catálogo-mestre fica em `system/technique/GameTechniqueManager.java`. Os códigos relevantes para pontos:
|
|
153
|
+
|
|
154
|
+
| Código | Nome (catálogo) | Core Drive | Descrição (pt) |
|
|
155
|
+
|---|---|---|---|
|
|
156
|
+
| `GT01` | Status Points | CD2 (Desenvolvimento & Realização) | "Unidades de medição do status do jogador. Pontos de consumo podem ser usados para comprar coisas." (`GameTechniqueManager.java:130`) |
|
|
157
|
+
| `GT75` | Exchangeable Points | CD4 (Posse & Propriedade) | "Pontos que podem ser trocados e podem fazer rodar a economia." (`GameTechniqueManager.java:204`) |
|
|
158
|
+
|
|
159
|
+
**Como `techniques` é preenchido (backfill automático):** `engine/technique/GameTechniqueManager.autoConfigureMissingTechniqueFields()` procura documentos em `point_category` **sem techniques** (query `notechniques`, linha 63: `techniques` ausente OU array vazio) e adiciona **apenas `GT01`** (linhas 67, 78-87). **`GT75` nunca é atribuído automaticamente.**
|
|
160
|
+
|
|
161
|
+
**O que `techniques` realmente faz:** serve só de **tag de categorização** para o mapa de técnicas do Studio (`GameTechniqueManager.findConfiguredTechniques` agrega o uso por técnica/core-drive). **Não há nenhum efeito comportamental no módulo `point`** — vide §7.
|
|
162
|
+
|
|
163
|
+
### 3.4 `Point` — saldo por jogador (coleção `point`) — LEGADO
|
|
164
|
+
|
|
165
|
+
`engine/point/Point.java`. Documento da coleção `point` (constante `PointDaoMongo.COLLECTION = "point"`, linha 10), distinta de `point_category`.
|
|
166
|
+
|
|
167
|
+
| Campo | Tipo | Descrição |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `_id` | String | GUID curto (gerado em `creditPoints`/`debitPoints`) |
|
|
170
|
+
| `categoryId` | String | id do `PointCategory` |
|
|
171
|
+
| `category` | String | nome da categoria (copiado de `PointCategory.getCategory()`) |
|
|
172
|
+
| `userId` | String | jogador dono do saldo |
|
|
173
|
+
| `points` | int | pontos obtidos (acumulado) — só incrementado em `creditPoints` |
|
|
174
|
+
| `balance` | int | saldo disponível para troca — incrementado no crédito, decrementado no débito |
|
|
175
|
+
|
|
176
|
+
> **Esta coleção/entidade é inerte no engine atual.** Os métodos que a manipulam (`creditPoints`, `debitPoints`, `transferPoints`, `findByUserId`) **não têm nenhum chamador** (vide §7). O saldo real do jogador vem de `achievement`, não daqui. A classe `Point` é apenas **exposta a scripts server-side** (Groovy/Java) via `import com.funifier.engine.point.Point` injetado pelos runners (`TriggerRunner`, `SchedulerRunner`, `AuthRunner`, `LastMileManager`, `CsvManager`, `PublicManager`, `PreparedManager`, `WebSocketManager`) — mas o core nunca a usa.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## 4. Endpoints
|
|
181
|
+
|
|
182
|
+
Controller: `PointRest` (`@Path("v3/point")`, `@Produces(application/json; charset=UTF-8)`). Todos exigem `Authorization: Bearer <token>`.
|
|
183
|
+
|
|
184
|
+
### `GET /v3/point`
|
|
185
|
+
|
|
186
|
+
| Aspecto | Detalhe |
|
|
187
|
+
|---|---|
|
|
188
|
+
| Finalidade | Lista todos os tipos de ponto (`point_category`) do tenant |
|
|
189
|
+
| Autenticação | Bearer token |
|
|
190
|
+
| Resposta | Array de `PointCategory`, campos null removidos |
|
|
191
|
+
| Código | 200 |
|
|
192
|
+
|
|
193
|
+
### `GET /v3/point/{id}`
|
|
194
|
+
|
|
195
|
+
| Aspecto | Detalhe |
|
|
196
|
+
|---|---|
|
|
197
|
+
| Finalidade | Busca um tipo de ponto por `_id` |
|
|
198
|
+
| Autenticação | Bearer token |
|
|
199
|
+
| Resposta | Objeto `PointCategory` (null se inexistente) |
|
|
200
|
+
| Código | 200 |
|
|
201
|
+
|
|
202
|
+
**Path params:**
|
|
7
203
|
|
|
8
|
-
|
|
204
|
+
| Param | Tipo | Descrição |
|
|
205
|
+
|---|---|---|
|
|
206
|
+
| `id` | String | `_id` do ponto |
|
|
207
|
+
|
|
208
|
+
> Observação: o apidoc inline desse método está rotulado como "Find Action" (`PointRest.java:48`) — é erro de copy-paste; o método retorna `PointCategory`.
|
|
9
209
|
|
|
10
|
-
|
|
210
|
+
### `POST /v3/point`
|
|
11
211
|
|
|
12
|
-
|
|
212
|
+
| Aspecto | Detalhe |
|
|
213
|
+
|---|---|
|
|
214
|
+
| Finalidade | Cria **ou substitui** um tipo de ponto |
|
|
215
|
+
| Autenticação | Bearer token |
|
|
216
|
+
| Full replace ou patch | **Full replace** por `_id` (Jongo `save`). Não é patch. |
|
|
217
|
+
| Resposta | O `PointCategory` salvo (com `_id` gerado, se aplicável) |
|
|
218
|
+
| Código | 201 CREATED |
|
|
13
219
|
|
|
14
|
-
|
|
220
|
+
**Comportamento real:**
|
|
221
|
+
- `_id` ausente/vazio ⇒ GUID curto gerado automaticamente.
|
|
222
|
+
- `_id` presente ⇒ upsert: substitui o documento inteiro. Campos omitidos são apagados.
|
|
223
|
+
- Campos desconhecidos no body ⇒ ignorados (`@JsonIgnoreProperties`).
|
|
224
|
+
- `icon` no body ⇒ ignorado (sem setter público — §3.1).
|
|
225
|
+
- Sem validação de obrigatoriedade ou de formato de `_id`.
|
|
15
226
|
|
|
16
|
-
|
|
227
|
+
**Exemplo:**
|
|
17
228
|
|
|
18
229
|
```json
|
|
230
|
+
POST /v3/point
|
|
19
231
|
{
|
|
20
232
|
"_id": "xp",
|
|
21
233
|
"category": "Experience Points",
|
|
22
|
-
"shortName": "XP"
|
|
23
|
-
"techniques": ["GT01"]
|
|
234
|
+
"shortName": "XP"
|
|
24
235
|
}
|
|
25
236
|
```
|
|
26
237
|
|
|
27
|
-
|
|
238
|
+
### `DELETE /v3/point/{id}`
|
|
28
239
|
|
|
29
|
-
|
|
240
|
+
| Aspecto | Detalhe |
|
|
241
|
+
|---|---|
|
|
242
|
+
| Finalidade | Remove o tipo de ponto da coleção `point_category` |
|
|
243
|
+
| Autenticação | Bearer token |
|
|
244
|
+
| Código | 204 NO_CONTENT |
|
|
30
245
|
|
|
31
|
-
|
|
246
|
+
**Comportamento real:** remove apenas o documento de `point_category`. **Não** remove achievements (`type=0, item=<id>`) já gerados, nem referências em `challenge`/`action`/`level`. O histórico/saldo derivado do ponto **continua existindo** em `achievement` após o delete.
|
|
32
247
|
|
|
33
|
-
|
|
34
|
-
{
|
|
35
|
-
"_id": "coin",
|
|
36
|
-
"category": "Coins",
|
|
37
|
-
"shortName": "Coins",
|
|
38
|
-
"techniques": ["GT75"]
|
|
39
|
-
}
|
|
40
|
-
```
|
|
248
|
+
> **Não existe `PUT`/`PATCH`.** O método `PointManager.update()` (remove-then-save full replace, `PointDaoMongo.java:50-54`) **não é exposto por nenhum endpoint** e não tem chamadores — é código morto (§7).
|
|
41
249
|
|
|
42
|
-
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 5. Regras de Negócio
|
|
253
|
+
|
|
254
|
+
Regras presentes no código mas ausentes do schema:
|
|
255
|
+
|
|
256
|
+
- **`_id` como chave de negócio:** o `_id` do ponto é o identificador usado em todos os outros módulos: `RewardPoint.category` (recompensa de action/challenge), `Requirement.item` (custo na loja), `achievement.item` (lançamento de saldo), `levelConfig.pointCategory` e `level.point` (gatilho de level up). Renomear/excluir um ponto **quebra silenciosamente** essas referências por id.
|
|
257
|
+
- **Saldo é eventual e calculado:** não há campo de saldo no módulo `point`. Qualquer total é uma aggregation sobre `achievement` (consistência eventual; sem cache no módulo).
|
|
258
|
+
- **Multi-tenant rígido por apiKey:** cada requisição opera sobre a base do tenant resolvido por `FrontController.getInstance(apiKey)`. Pontos de um projeto nunca enxergam os de outro. Não há isolamento adicional por usuário dentro do tenant — qualquer token válido do tenant pode listar/criar/excluir pontos (não há checagem de role no `PointRest`).
|
|
259
|
+
- **POST destrutivo:** por ser full-replace, reenviar um ponto sem um campo previamente salvo o remove. Para "editar", releia o objeto, altere e reenvie completo.
|
|
260
|
+
- **`techniques` não é regra de negócio:** apesar de `GT01`/`GT75` sugerirem comportamentos distintos, o módulo trata `techniques` como lista opaca de tags. Não há ramificação de lógica por técnica.
|
|
43
261
|
|
|
44
262
|
---
|
|
45
263
|
|
|
46
|
-
|
|
264
|
+
## 6. Comportamentos Automáticos
|
|
47
265
|
|
|
48
|
-
|
|
266
|
+
| Comportamento | Trigger | Impacto | Persistência |
|
|
267
|
+
|---|---|---|---|
|
|
268
|
+
| Geração de `_id` | POST com `_id` vazio | `Guid.newShortGuid()` gravado como `_id` | `point_category` |
|
|
269
|
+
| Upsert/full-replace | POST com `_id` existente | Documento substituído por inteiro | `point_category` |
|
|
270
|
+
| Remoção de campos null na resposta | Qualquer GET/POST | `JsonUtil.toJsonRemoveNullFields` | — (só resposta) |
|
|
271
|
+
| Descarte de campos desconhecidos | POST | `@JsonIgnoreProperties(ignoreUnknown=true)` | — |
|
|
272
|
+
| Backfill de `techniques=["GT01"]` | Rotina de manutenção `autoConfigureMissingTechniqueFields()` | Adiciona `GT01` a pontos sem techniques + grava `game_technique_field` | `point_category`, `game_technique_field` |
|
|
49
273
|
|
|
50
|
-
|
|
274
|
+
> Não há comportamento encadeado de behaviors/triggers no CRUD de point. O backfill de techniques é uma rotina administrativa do sistema, não disparada pelo CRUD.
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## 7. Suportado vs NÃO Suportado
|
|
279
|
+
|
|
280
|
+
### ✅ Suportado
|
|
281
|
+
|
|
282
|
+
- CRUD de tipos de ponto via `/v3/point` (list, find, create/replace, delete).
|
|
283
|
+
- Geração automática de `_id` quando omitido.
|
|
284
|
+
- Imagem em 3 tamanhos (`image.small/medium/original`).
|
|
285
|
+
- Campos customizados via `extra`.
|
|
286
|
+
- Tag de técnica `techniques` (categorização para o mapa Octalysis do Studio).
|
|
287
|
+
- Uso do `_id` do ponto como referência por outros módulos (challenge, action, achievement, level, leaderboard, catalog, package).
|
|
288
|
+
- Crédito de pontos ao jogador via `achievement` (feito pelo módulo `achievement`, não por este).
|
|
289
|
+
|
|
290
|
+
### ❌ NÃO Suportado
|
|
291
|
+
|
|
292
|
+
- **Transferência de pontos entre jogadores (player-to-player).** `PointManager.transferPoints` (linhas 26-38) existe, mas tem **zero chamadores** — não é exposto por REST nem chamado por nenhum manager. É código morto.
|
|
293
|
+
- **Crédito/débito direto de saldo (`creditPoints`/`debitPoints`).** Existem em `PointManager`/`PointDaoMongo` (18-42) mas **sem chamadores no engine**. A chamada que os usaria em compras está **comentada** em `PurchaseManager.java:115` (`//manager.getPointManager().debitPoints(...)`) — evidência de que o sistema de saldo na coleção `point` foi **descontinuado** em favor da aggregation de `achievement`.
|
|
294
|
+
- **A coleção `point` (entidade `Point`) como fonte de saldo.** Inerte no core; apenas importável em scripts customizados.
|
|
295
|
+
- **`PUT`/`PATCH` (edição parcial).** Não há endpoint. POST é full-replace. `PointManager.update()` é código morto (zero chamadores).
|
|
296
|
+
- **Endpoint legado `/2.0.0/point`.** Não existe controller de point em `rest/engine`.
|
|
297
|
+
- **Campo `icon`.** Aceito no schema da classe, mas o REST não o desserializa (sem setter público) — sempre `null`.
|
|
298
|
+
- **Validação de `_id`/campos obrigatórios.** O backend não rejeita `_id` com espaços/maiúsculas nem `category`/`shortName` ausentes.
|
|
299
|
+
|
|
300
|
+
> ### Correção importante sobre `techniques` (GT01 × GT75)
|
|
301
|
+
>
|
|
302
|
+
> A documentação anterior afirmava: _"se jogadores podem transferir/trocar o ponto entre si, use `GT75`; para o resto use `GT01`; qualquer ponto pode ser usado na loja"_. Confrontando com o código:
|
|
303
|
+
>
|
|
304
|
+
> - `GT75` ("Exchangeable Points", CD4) **é uma técnica real do catálogo** (`system/technique/GameTechniqueManager.java:204`) — não foi inventada. Mas **marcar um ponto com `GT75` não habilita transferência alguma**: o mecanismo de troca (`transferPoints`) é código morto.
|
|
305
|
+
> - `techniques` **não altera o comportamento do módulo point**. É só tag de analytics/Octalysis. Não existe ramificação de lógica por GT no engine de pontos.
|
|
306
|
+
> - O **gasto na loja** funciona para **qualquer ponto**, independente de `techniques`, via `Requirement` com `OPERATION_DEDUCT` em `catalog_item` (gera achievement negativo). Não é o `GT75` que "habilita a loja".
|
|
307
|
+
> - O backfill automático só aplica `GT01`. Um ponto sem técnica recebe `GT01` ("Status Points").
|
|
308
|
+
>
|
|
309
|
+
> **Conclusão:** trate `techniques` como rótulo descritivo opcional. Não dependa dele para nenhum comportamento.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 8. Segurança e Permissões
|
|
314
|
+
|
|
315
|
+
- **Autenticação:** `Authorization: Bearer <token>` em todos os métodos (`@BeanParam AuthBean`).
|
|
316
|
+
- **Isolamento por tenant:** `FrontController.getInstance(authBean.getApiKey())` direciona toda operação à base do tenant dono do apiKey. Não há vazamento entre projetos.
|
|
317
|
+
- **Autorização intra-tenant:** o `PointRest` **não** faz checagem de papel/escopo — qualquer token válido do tenant pode criar e **excluir** tipos de ponto. Operações de escrita devem ser restritas a tokens administrativos por convenção operacional (não há enforcement no controller).
|
|
318
|
+
- **Superfície de injeção:** as queries Mongo do módulo são **parametrizadas** via placeholders Jongo (`"{_id:#}"`, `"{userId:#}"`, `"{categoryId:#, userId:#}"`) — sem concatenação de string com input do usuário. Não há superfície de injeção NoSQL no módulo `point` em si. (Atenção: aggregations livres do tenant via `/v3/database/...` são outra superfície, fora deste módulo.)
|
|
319
|
+
- **DELETE não-transacional e sem cascata:** excluir um ponto não limpa referências; pode deixar challenges/levels apontando para um `_id` inexistente (NPE potencial em `ChallengeManager` ao montar descrição — `cat.getCategory()` com `cat == null`).
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## 9. Observabilidade e Troubleshooting
|
|
324
|
+
|
|
325
|
+
### Diagnóstico rápido
|
|
51
326
|
|
|
52
|
-
```json
|
|
53
|
-
"image": {
|
|
54
|
-
"small": { "url": "https://...", "size": 0, "width": 0, "height": 0, "depth": 0 },
|
|
55
|
-
"medium": { "url": "https://...", "size": 0, "width": 0, "height": 0, "depth": 0 },
|
|
56
|
-
"original": { "url": "https://...", "size": 0, "width": 0, "height": 0, "depth": 0 }
|
|
57
|
-
}
|
|
58
327
|
```
|
|
328
|
+
# O ponto existe?
|
|
329
|
+
GET /v3/point/<id>
|
|
59
330
|
|
|
60
|
-
|
|
331
|
+
# Listar todos os tipos de ponto do projeto
|
|
332
|
+
GET /v3/point
|
|
333
|
+
```
|
|
61
334
|
|
|
62
|
-
|
|
335
|
+
### Saldo do jogador (vem de achievement, não de point)
|
|
63
336
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
337
|
+
```
|
|
338
|
+
# Total de um ponto para um jogador (fonte da verdade)
|
|
339
|
+
POST /v3/database/achievement/aggregate
|
|
340
|
+
[
|
|
341
|
+
{ "$match": { "player": "<userId>", "type": 0, "item": "<pointId>" } },
|
|
342
|
+
{ "$group": { "_id": null, "total": { "$sum": "$total" } } }
|
|
343
|
+
]
|
|
344
|
+
```
|
|
71
345
|
|
|
72
|
-
|
|
346
|
+
### Investigações úteis
|
|
347
|
+
|
|
348
|
+
```
|
|
349
|
+
# Quais challenges referenciam este ponto (antes de excluir)?
|
|
350
|
+
POST /v3/database/challenge/aggregate
|
|
351
|
+
[ { "$match": { "points.category": "<pointId>" } } ]
|
|
352
|
+
|
|
353
|
+
# Algum level usa este ponto como gatilho?
|
|
354
|
+
POST /v3/database/level/aggregate
|
|
355
|
+
[ { "$match": { "point": "<pointId>" } } ]
|
|
356
|
+
|
|
357
|
+
# Conferir/limpar a coleção legada de saldos (deveria estar vazia/inerte)
|
|
358
|
+
POST /v3/database/point/aggregate
|
|
359
|
+
[ { "$match": { "categoryId": "<pointId>" } } ]
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Erros comuns e causas
|
|
363
|
+
|
|
364
|
+
| Sintoma | Causa provável |
|
|
365
|
+
|---|---|
|
|
366
|
+
| "Editei um ponto e sumiram campos" | POST é full-replace — releia, altere, reenvie completo. |
|
|
367
|
+
| "Mandei `icon` e não persistiu" | `icon` é campo morto, não desserializado. Use `image`. |
|
|
368
|
+
| "Marquei `GT75` e os pontos não transferem" | Transferência é código morto; `techniques` não muda comportamento (§7). |
|
|
369
|
+
| "Saldo não bate com o esperado" | Saldo vem de `achievement` (`type:0,item:<id>`), não do módulo point. Verifique os lançamentos. |
|
|
370
|
+
| "Excluí o ponto e o ranking quebrou" | DELETE não faz cascata; challenges/levels ficam apontando para `_id` inexistente. |
|
|
371
|
+
| Resposta sem `techniques`/`image` | Campos null são removidos pelo `toJsonRemoveNullFields`; não significa erro. |
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## 10. Exemplos Práticos
|
|
376
|
+
|
|
377
|
+
### Mínimo funcional
|
|
73
378
|
|
|
74
|
-
**XP (ponto normal):**
|
|
75
379
|
```json
|
|
380
|
+
POST /v3/point
|
|
76
381
|
{
|
|
77
382
|
"_id": "xp",
|
|
78
383
|
"category": "Experience Points",
|
|
79
|
-
"shortName": "XP"
|
|
80
|
-
"techniques": ["GT01"],
|
|
81
|
-
"extra": {}
|
|
384
|
+
"shortName": "XP"
|
|
82
385
|
}
|
|
83
386
|
```
|
|
84
387
|
|
|
85
|
-
|
|
388
|
+
### Avançado (todos os campos relevantes)
|
|
389
|
+
|
|
86
390
|
```json
|
|
391
|
+
POST /v3/point
|
|
87
392
|
{
|
|
88
393
|
"_id": "coin",
|
|
89
394
|
"category": "Coins",
|
|
90
|
-
"shortName": "
|
|
395
|
+
"shortName": "C$",
|
|
396
|
+
"image": {
|
|
397
|
+
"small": { "url": "https://cdn.exemplo.com/coin.png" },
|
|
398
|
+
"medium": { "url": "https://cdn.exemplo.com/coin.png" },
|
|
399
|
+
"original": { "url": "https://cdn.exemplo.com/coin.png" }
|
|
400
|
+
},
|
|
91
401
|
"techniques": ["GT75"],
|
|
92
|
-
"extra": {}
|
|
402
|
+
"extra": { "color": "#FFD700", "decimals": 0 }
|
|
93
403
|
}
|
|
94
404
|
```
|
|
95
405
|
|
|
96
|
-
|
|
97
|
-
```json
|
|
98
|
-
[
|
|
99
|
-
{ "_id": "xp", "category": "Experience Points", "shortName": "XP", "techniques": ["GT01"] },
|
|
100
|
-
{ "_id": "coin", "category": "Coins", "shortName": "Coins", "techniques": ["GT75"] },
|
|
101
|
-
{ "_id": "karma", "category": "Karma", "shortName": "K", "techniques": ["GT01"] }
|
|
102
|
-
]
|
|
103
|
-
```
|
|
406
|
+
> Aqui `techniques: ["GT75"]` é apenas rótulo descritivo ("ponto de economia/troca") para o mapa do Studio. Não habilita transferência nem comportamento especial.
|
|
104
407
|
|
|
105
|
-
|
|
408
|
+
### Anti-pattern — o que NÃO fazer
|
|
106
409
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
### Criar / Atualizar Ponto
|
|
112
|
-
**Método:** POST
|
|
113
|
-
**Endpoint:** `/v3/point`
|
|
114
|
-
|
|
115
|
-
POST com `_id` existente = update (upsert).
|
|
116
|
-
|
|
117
|
-
### Excluir Ponto
|
|
118
|
-
**Método:** DELETE
|
|
119
|
-
**Endpoint:** `/v3/point/:id`
|
|
120
|
-
|
|
121
|
-
> ⚠ Não delete um ponto referenciado em challenges ativos. Verifique com:
|
|
122
|
-
> ```
|
|
123
|
-
> funifier_database action=aggregate collection=challenge pipeline='[{"$match": {"points.category": "<point_id>"}}]'
|
|
124
|
-
> ```
|
|
410
|
+
```json
|
|
411
|
+
// ❌ Esperar que GT75 ative troca entre jogadores
|
|
412
|
+
{ "_id": "social", "category": "Social Coin", "techniques": ["GT75"] }
|
|
413
|
+
// Não há transferência player-to-player no engine. transferPoints é código morto.
|
|
125
414
|
|
|
126
|
-
|
|
415
|
+
// ❌ Tentar "editar parcialmente" via POST
|
|
416
|
+
{ "_id": "xp", "shortName": "EXP" }
|
|
417
|
+
// Isto APAGA category/image/etc. do ponto "xp" (full replace). Reenvie o objeto completo.
|
|
127
418
|
|
|
128
|
-
|
|
419
|
+
// ❌ Usar o campo icon
|
|
420
|
+
{ "_id": "xp", "category": "XP", "icon": "star" }
|
|
421
|
+
// "icon" é ignorado (campo morto). Use "image".
|
|
422
|
+
```
|
|
129
423
|
|
|
130
|
-
|
|
424
|
+
---
|
|
131
425
|
|
|
132
|
-
## Checklist
|
|
426
|
+
## Checklist de Configuração
|
|
133
427
|
|
|
134
|
-
- [ ] `_id`
|
|
135
|
-
- [ ] `
|
|
136
|
-
- [ ]
|
|
137
|
-
- [ ]
|
|
138
|
-
- [ ]
|
|
428
|
+
- [ ] `_id` definido (ou omitido de propósito para gerar GUID). Convenção: minúsculas, sem espaços (não é validado pelo backend).
|
|
429
|
+
- [ ] `category` e `shortName` preenchidos (não são obrigatórios no servidor, mas a UI depende deles).
|
|
430
|
+
- [ ] Ponto criado **antes** dos challenges/actions/levels que o referenciam por `_id`.
|
|
431
|
+
- [ ] Para editar, reenviar o objeto **completo** (POST é full-replace) — não envie só o campo alterado.
|
|
432
|
+
- [ ] Usar `image` (não `icon` — campo morto).
|
|
433
|
+
- [ ] Não depender de `techniques`/`GT75` para comportamento: é só rótulo. Transferência/saldo não vivem aqui.
|
|
434
|
+
- [ ] Antes de `DELETE`, conferir referências em `challenge.points.category` e `level.point` (delete não faz cascata).
|
|
435
|
+
- [ ] Lembrar que saldo do jogador é calculado de `achievement` (`type:0, item:<_id>`), não do módulo point.
|