funifier-mcp 0.2.0 → 0.2.4
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 +91 -0
- package/.github/copilot-instructions.md +83 -0
- package/AGENTS.md +97 -0
- package/README.md +247 -78
- package/datasource-funifier-docs/knowledge/guides/aggregates.md +152 -152
- package/datasource-funifier-docs/knowledge/guides/database-access.md +132 -132
- package/datasource-funifier-docs/knowledge/guides/java-entities.md +373 -373
- package/datasource-funifier-docs/knowledge/guides/java-libraries.md +330 -330
- package/datasource-funifier-docs/knowledge/guides/java-managers.md +509 -509
- package/datasource-funifier-docs/knowledge/guides/triggers-guide.md +271 -271
- package/datasource-funifier-docs/knowledge/index.md +121 -121
- package/datasource-funifier-docs/knowledge/modules/achievement.md +46 -46
- package/datasource-funifier-docs/knowledge/modules/action-log.md +88 -88
- package/datasource-funifier-docs/knowledge/modules/action.md +80 -80
- package/datasource-funifier-docs/knowledge/modules/auth.md +104 -104
- package/datasource-funifier-docs/knowledge/modules/avatar.md +28 -28
- package/datasource-funifier-docs/knowledge/modules/backup.md +40 -40
- package/datasource-funifier-docs/knowledge/modules/challenge.md +91 -91
- package/datasource-funifier-docs/knowledge/modules/compact.md +40 -40
- package/datasource-funifier-docs/knowledge/modules/competition.md +149 -149
- package/datasource-funifier-docs/knowledge/modules/crossword.md +41 -41
- package/datasource-funifier-docs/knowledge/modules/csv-data.md +30 -30
- package/datasource-funifier-docs/knowledge/modules/custom-object.md +53 -53
- package/datasource-funifier-docs/knowledge/modules/database.md +241 -241
- package/datasource-funifier-docs/knowledge/modules/folder.md +111 -111
- package/datasource-funifier-docs/knowledge/modules/kpi-formulas.md +23 -23
- package/datasource-funifier-docs/knowledge/modules/lastmile.md +45 -45
- package/datasource-funifier-docs/knowledge/modules/leaderboard.md +98 -98
- package/datasource-funifier-docs/knowledge/modules/level.md +83 -83
- package/datasource-funifier-docs/knowledge/modules/lottery.md +112 -112
- package/datasource-funifier-docs/knowledge/modules/marketplace.md +27 -27
- package/datasource-funifier-docs/knowledge/modules/mystery.md +82 -82
- package/datasource-funifier-docs/knowledge/modules/notification.md +40 -40
- package/datasource-funifier-docs/knowledge/modules/patterns.md +1096 -1096
- package/datasource-funifier-docs/knowledge/modules/player.md +101 -101
- package/datasource-funifier-docs/knowledge/modules/point.md +67 -67
- package/datasource-funifier-docs/knowledge/modules/public.md +253 -253
- package/datasource-funifier-docs/knowledge/modules/question.md +136 -136
- package/datasource-funifier-docs/knowledge/modules/quiz.md +163 -163
- package/datasource-funifier-docs/knowledge/modules/scheduler.md +58 -58
- package/datasource-funifier-docs/knowledge/modules/security.md +169 -169
- package/datasource-funifier-docs/knowledge/modules/staging.md +28 -28
- package/datasource-funifier-docs/knowledge/modules/static-repo.md +41 -41
- package/datasource-funifier-docs/knowledge/modules/story.md +42 -42
- package/datasource-funifier-docs/knowledge/modules/studio-page.md +180 -180
- package/datasource-funifier-docs/knowledge/modules/swap.md +132 -132
- package/datasource-funifier-docs/knowledge/modules/team.md +75 -75
- package/datasource-funifier-docs/knowledge/modules/trigger.md +189 -189
- package/datasource-funifier-docs/knowledge/modules/upload.md +155 -155
- package/datasource-funifier-docs/knowledge/modules/virtual-good.md +99 -99
- package/datasource-funifier-docs/knowledge/modules/webhook.md +41 -41
- package/datasource-funifier-docs/knowledge/modules/websocket.md +41 -41
- package/datasource-funifier-docs/knowledge/modules/widget.md +42 -42
- package/datasource-funifier-docs/process-gtm-saas.md +143 -143
- package/datasource-funifier-docs/process-instagram.md +88 -88
- package/datasource-funifier-docs/process.md +1826 -1826
- package/datasource-funifier-docs/readme.md +132 -132
- package/dist/cli/config-writers.js +11 -11
- package/dist/mcp/bundle.js +82 -77
- package/package.json +70 -67
- package/skills/funifier-create-aggregate/SKILL.md +126 -126
- package/skills/funifier-create-custom-page/SKILL.md +126 -126
- package/skills/funifier-create-scheduler/SKILL.md +126 -126
- package/skills/funifier-create-trigger/SKILL.md +127 -127
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
# Story (História)
|
|
2
|
-
|
|
3
|
-
**Acesso Studio:** `/studio/story`
|
|
4
|
-
**API Endpoint:** `/v3/story`
|
|
5
|
-
|
|
6
|
-
## O que é
|
|
7
|
-
|
|
8
|
-
Criação de histórias interativas com múltiplos caminhos e finais. Permite criar narrativas gamificadas nas quais o jogador faz escolhas que afetam o desenrolar da trama. Cenários, personagens, imagens e vídeos podem ser utilizados para enriquecer a experiência.
|
|
9
|
-
|
|
10
|
-
## Quando usar
|
|
11
|
-
|
|
12
|
-
- Para treinamentos baseados em storytelling
|
|
13
|
-
- Para campanhas de marketing com desfechos alternativos
|
|
14
|
-
- Para jogos educacionais interativos
|
|
15
|
-
- Para experiências de role-playing
|
|
16
|
-
|
|
17
|
-
## Checklist de Configuração no Studio
|
|
18
|
-
|
|
19
|
-
- [ ] Definir título e descrição da história
|
|
20
|
-
- [ ] Criar cenários/cenas com textos e mídias
|
|
21
|
-
- [ ] Definir ramificações e escolhas
|
|
22
|
-
- [ ] Configurar finais alternativos
|
|
23
|
-
|
|
24
|
-
## API Endpoints
|
|
25
|
-
|
|
26
|
-
### Listar Stories
|
|
27
|
-
**Método:** GET
|
|
28
|
-
**Endpoint:** `/v3/story`
|
|
29
|
-
|
|
30
|
-
### Criar Story
|
|
31
|
-
**Método:** POST
|
|
32
|
-
**Endpoint:** `/v3/story`
|
|
33
|
-
|
|
34
|
-
### Deletar Story
|
|
35
|
-
**Método:** DELETE
|
|
36
|
-
**Endpoint:** `/v3/story/:id`
|
|
37
|
-
|
|
38
|
-
## Validações e Testes
|
|
39
|
-
|
|
40
|
-
- [ ] História aparece na lista
|
|
41
|
-
- [ ] Navegação entre cenários funciona
|
|
42
|
-
- [ ] Escolhas do jogador são registradas
|
|
1
|
+
# Story (História)
|
|
2
|
+
|
|
3
|
+
**Acesso Studio:** `/studio/story`
|
|
4
|
+
**API Endpoint:** `/v3/story`
|
|
5
|
+
|
|
6
|
+
## O que é
|
|
7
|
+
|
|
8
|
+
Criação de histórias interativas com múltiplos caminhos e finais. Permite criar narrativas gamificadas nas quais o jogador faz escolhas que afetam o desenrolar da trama. Cenários, personagens, imagens e vídeos podem ser utilizados para enriquecer a experiência.
|
|
9
|
+
|
|
10
|
+
## Quando usar
|
|
11
|
+
|
|
12
|
+
- Para treinamentos baseados em storytelling
|
|
13
|
+
- Para campanhas de marketing com desfechos alternativos
|
|
14
|
+
- Para jogos educacionais interativos
|
|
15
|
+
- Para experiências de role-playing
|
|
16
|
+
|
|
17
|
+
## Checklist de Configuração no Studio
|
|
18
|
+
|
|
19
|
+
- [ ] Definir título e descrição da história
|
|
20
|
+
- [ ] Criar cenários/cenas com textos e mídias
|
|
21
|
+
- [ ] Definir ramificações e escolhas
|
|
22
|
+
- [ ] Configurar finais alternativos
|
|
23
|
+
|
|
24
|
+
## API Endpoints
|
|
25
|
+
|
|
26
|
+
### Listar Stories
|
|
27
|
+
**Método:** GET
|
|
28
|
+
**Endpoint:** `/v3/story`
|
|
29
|
+
|
|
30
|
+
### Criar Story
|
|
31
|
+
**Método:** POST
|
|
32
|
+
**Endpoint:** `/v3/story`
|
|
33
|
+
|
|
34
|
+
### Deletar Story
|
|
35
|
+
**Método:** DELETE
|
|
36
|
+
**Endpoint:** `/v3/story/:id`
|
|
37
|
+
|
|
38
|
+
## Validações e Testes
|
|
39
|
+
|
|
40
|
+
- [ ] História aparece na lista
|
|
41
|
+
- [ ] Navegação entre cenários funciona
|
|
42
|
+
- [ ] Escolhas do jogador são registradas
|
|
@@ -1,180 +1,180 @@
|
|
|
1
|
-
# Studio Page (Página Customizada do Studio)
|
|
2
|
-
|
|
3
|
-
**Acesso Studio:** `/studio/page`
|
|
4
|
-
|
|
5
|
-
## O que é
|
|
6
|
-
|
|
7
|
-
Páginas customizadas dentro do Funifier Studio para atender necessidades específicas dos administradores. Permitem criar dashboards, CRUDs, gráficos, relatórios — tudo com AngularJS + Bootstrap.
|
|
8
|
-
|
|
9
|
-
## Configuração
|
|
10
|
-
|
|
11
|
-
Cada página é um JSON com:
|
|
12
|
-
- `_id` — Identificador único (auto-gerado se omitido)
|
|
13
|
-
- `display` — `true` para aparecer no menu do Studio, `false` para páginas internas
|
|
14
|
-
- `title` — Nome exibido no menu
|
|
15
|
-
- `slug` — Caminho relativo (ex: `studio/custom/hello`). Suporta parâmetros: `studio/custom/car/form/:id`
|
|
16
|
-
- `html` — Código HTML (usa Bootstrap CSS)
|
|
17
|
-
- `script` — Código JavaScript (roda no contexto AngularJS)
|
|
18
|
-
|
|
19
|
-
## Contexto JavaScript
|
|
20
|
-
|
|
21
|
-
Dentro do `script`, você tem acesso a:
|
|
22
|
-
- `$scope` — Scope do AngularJS
|
|
23
|
-
- `$http` — Para requisições HTTP
|
|
24
|
-
- `$location` — Para navegação entre páginas (`$location.path("/studio/custom/...")`)
|
|
25
|
-
- `$routeParams` — Para ler parâmetros do slug (ex: `$routeParams.id`)
|
|
26
|
-
- `Marketplace` — Objeto utilitário (ver abaixo)
|
|
27
|
-
|
|
28
|
-
### Marketplace API
|
|
29
|
-
|
|
30
|
-
| Método | Descrição | Exemplo de retorno |
|
|
31
|
-
|--------|-----------|-------------------|
|
|
32
|
-
| `Marketplace.auth.getService()` | URL da API Funifier | `https://service2.funifier.com` |
|
|
33
|
-
| `Marketplace.auth.getAuthorization()` | Token de acesso do usuário logado no Studio | Bearer token |
|
|
34
|
-
| `Marketplace.range.parse(content_range)` | Analisa header `content-range` para paginação | `{page, pages, count, ...}` |
|
|
35
|
-
| `Marketplace.range.paginate(page, content_range)` | Gera header `Range` para ir a uma página | `items=0-100` |
|
|
36
|
-
|
|
37
|
-
## Diretivas Disponíveis
|
|
38
|
-
|
|
39
|
-
- `<image-picker>` — Seletor de imagem (URL, local, galeria). Atributos: `on-change`, `show-picker-url`, `show-picker-local`, `show-picker-gallery`, `upload-max-size`, `transform`
|
|
40
|
-
- `<principal-picker>` — Seletor de jogadores/equipes. Atributos: `title`, `model`, `show-picker-player`, `black-list`, `max`
|
|
41
|
-
- `<input-extra>` — Campos extras dinâmicos. Atributos: `title`, `show-inline`, `model`
|
|
42
|
-
|
|
43
|
-
## Bibliotecas Disponíveis
|
|
44
|
-
|
|
45
|
-
- **Highcharts** — Gráficos (pizza, barra, linhas, etc.)
|
|
46
|
-
- **Bootstrap** — CSS framework (classes `btn`, `table`, `form-control`, etc.)
|
|
47
|
-
- **Glyphicons** — Ícones via `glyphicon glyphicon-*`
|
|
48
|
-
- Traduções: `{{'SAVE'|translate}}`, `{{'CANCEL'|translate}}`, `{{'BACK'|translate}}`, `{{'NEW'|translate}}`, `{{'SEARCH_FOR'|translate}}`
|
|
49
|
-
|
|
50
|
-
## Exemplos
|
|
51
|
-
|
|
52
|
-
### 1. Hello World
|
|
53
|
-
```json
|
|
54
|
-
{
|
|
55
|
-
"_id": "hello1",
|
|
56
|
-
"display": true,
|
|
57
|
-
"title": "Hello World!",
|
|
58
|
-
"slug": "studio/custom/hello",
|
|
59
|
-
"html": "<button ng-click=\"hello()\" class=\"btn btn-warning\">Hello</button>",
|
|
60
|
-
"script": "$scope.hello = function(){ alert('Hello World!'); }"
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### 2. Lista Simples (Desafios)
|
|
65
|
-
```javascript
|
|
66
|
-
/* "display": true, "title": "Quest List", "slug": "studio/custom/challenge" */
|
|
67
|
-
$scope.all = [];
|
|
68
|
-
$scope.list = function () {
|
|
69
|
-
$http({method: 'GET', url:Marketplace.auth.getService() + '/v3/database/challenge',
|
|
70
|
-
headers: {"Authorization": Marketplace.auth.getAuthorization(), "content-type": "application/json"}
|
|
71
|
-
}).then(function(data){
|
|
72
|
-
$scope.all = data.data;
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
$scope.list();
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### 3. Lista Paginada (Players)
|
|
79
|
-
```javascript
|
|
80
|
-
/* "display": true, "title": "Player List", "slug": "studio/custom/player" */
|
|
81
|
-
$scope.range = { request: "items=0-100" };
|
|
82
|
-
$scope.gotopage = function(page){
|
|
83
|
-
$scope.range.request = Marketplace.range.paginate(page, $scope.range.response);
|
|
84
|
-
$scope.list();
|
|
85
|
-
};
|
|
86
|
-
$scope.paginate = function (total) {
|
|
87
|
-
var to = $scope.range.page + total;
|
|
88
|
-
$scope.range.request = Marketplace.range.paginate(to, $scope.range.response);
|
|
89
|
-
$scope.list();
|
|
90
|
-
};
|
|
91
|
-
$scope.all = [];
|
|
92
|
-
$scope.list = function () {
|
|
93
|
-
$http({method: 'GET', url:Marketplace.auth.getService() + '/v3/database/player',
|
|
94
|
-
headers: {"Authorization": Marketplace.auth.getAuthorization(), "Range": $scope.range.request, "content-type": "application/json"}
|
|
95
|
-
}).then(function(data){
|
|
96
|
-
$scope.all = data.data;
|
|
97
|
-
$scope.range = Marketplace.range.parse(data.headers(["content-range"]));
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
$scope.list();
|
|
101
|
-
```
|
|
102
|
-
HTML de paginação:
|
|
103
|
-
```html
|
|
104
|
-
<div>
|
|
105
|
-
Page <input type="number" ng-model="range.page" ng-change="gotopage(range.page)" style="width:40px;" /> of {{range.pages}}
|
|
106
|
-
<button ng-click="paginate(-1)" class="btn btn-default"><span class="glyphicon glyphicon-chevron-left"></span></button>
|
|
107
|
-
<button ng-click="paginate(+1)" class="btn btn-default"><span class="glyphicon glyphicon-chevron-right"></span></button>
|
|
108
|
-
</div>
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### 4. CRUD Completo (Carros)
|
|
112
|
-
**Lista** (`display: true`, slug: `studio/custom/car/list`): Lista + busca + paginação + botões editar/excluir + botão "NEW"
|
|
113
|
-
- DELETE: `$http({method: 'DELETE', url: API + "/v3/database/car__c?q=_id:'" + id + "'", ...})`
|
|
114
|
-
- Navegação: `$location.path("/studio/custom/car/form/" + id)` ou `"/studio/custom/car/form/new"`
|
|
115
|
-
|
|
116
|
-
**Formulário** (`display: false`, slug: `studio/custom/car/form/:id`):
|
|
117
|
-
- Carrega via GET: `/v3/database/car__c?strict=true&q=_id:'ID'`
|
|
118
|
-
- Salva via PUT: `/v3/database/car__c`
|
|
119
|
-
- Usa `$routeParams.id` para saber se é edição ou criação (`"new"` = novo)
|
|
120
|
-
- `<image-picker on-change="setImage" ...>` para upload de imagem
|
|
121
|
-
|
|
122
|
-
### 5. Gráfico Highcharts (Active Players)
|
|
123
|
-
```javascript
|
|
124
|
-
/* "display": true, "title": "Daily Active Players", "slug": "studio/custom/kpi/players" */
|
|
125
|
-
$scope.load = function () {
|
|
126
|
-
$http({
|
|
127
|
-
method: 'POST', url: Marketplace.auth.getService() + '/v3/database/action_log/aggregate',
|
|
128
|
-
headers: { Authorization: Marketplace.auth.getAuthorization(), 'content-type': 'application/json'},
|
|
129
|
-
data: [
|
|
130
|
-
{"$match": { "time": { "$gte": { "$date": "-1y" } } } },
|
|
131
|
-
{"$addFields": { "day": { "$dayOfYear": "$time" } } },
|
|
132
|
-
{"$group": { "_id": { "player": "$userId", "day": "$day" }, "time": { "$max": "$time" }}},
|
|
133
|
-
{"$group": { "_id": "$_id.day", "total_users": { "$sum": 1 }, "time": { "$max": "$time" }}},
|
|
134
|
-
{"$project": { "_id": 0, "day_of_year": '$_id', "total": '$total_users', "time": 1}},
|
|
135
|
-
{"$sort": { "day_of_year": 1 } }
|
|
136
|
-
]
|
|
137
|
-
}).then(function (data) {
|
|
138
|
-
var transformedData = data.data.map(function (d) { return [d.time, d.total]; });
|
|
139
|
-
new Highcharts.Chart({
|
|
140
|
-
chart: { renderTo: 'chart', type: 'line' },
|
|
141
|
-
title: { text: 'Daily Active Players' },
|
|
142
|
-
xAxis: { type: 'datetime' },
|
|
143
|
-
yAxis: { title: { text: 'Total' } },
|
|
144
|
-
series: [{ name: 'Total over time', data: transformedData }],
|
|
145
|
-
credits: { enabled: false }
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
};
|
|
149
|
-
$scope.load();
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
## API REST para Gerenciar Páginas
|
|
153
|
-
|
|
154
|
-
**IMPORTANTE:** As páginas customizadas ficam na collection `studio_page` (NÃO `page`).
|
|
155
|
-
|
|
156
|
-
```bash
|
|
157
|
-
# Criar/atualizar página
|
|
158
|
-
curl -X PUT "https://service2.funifier.com/v3/database/studio_page" \
|
|
159
|
-
-H "Authorization: Bearer TOKEN" \
|
|
160
|
-
-H "Content-Type: application/json" \
|
|
161
|
-
-d '{"_id":"minha_pagina", "display":true, "title":"Minha Página", "slug":"studio/custom/minha-pagina", "html":"<h1>Oi</h1>", "script":"/* js */"}'
|
|
162
|
-
|
|
163
|
-
# Listar páginas
|
|
164
|
-
curl "https://service2.funifier.com/v3/database/studio_page" \
|
|
165
|
-
-H "Authorization: Bearer TOKEN"
|
|
166
|
-
|
|
167
|
-
# Deletar página
|
|
168
|
-
curl -X DELETE "https://service2.funifier.com/v3/database/studio_page?q=_id:'ID'" \
|
|
169
|
-
-H "Authorization: Bearer TOKEN"
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
## Checklist
|
|
173
|
-
|
|
174
|
-
- [ ] Definir `_id`, `title`, `slug`, `display`
|
|
175
|
-
- [ ] Escrever `html` com Bootstrap
|
|
176
|
-
- [ ] Escrever `script` com AngularJS
|
|
177
|
-
- [ ] Usar `Marketplace.auth.*` para autenticação
|
|
178
|
-
- [ ] Usar `?strict=true` em GETs para preservar tipos BSON
|
|
179
|
-
- [ ] Testar no Studio (navegar até a URL do slug)
|
|
180
|
-
- [ ] Para CRUDs: criar página de lista (display:true) + formulário (display:false)
|
|
1
|
+
# Studio Page (Página Customizada do Studio)
|
|
2
|
+
|
|
3
|
+
**Acesso Studio:** `/studio/page`
|
|
4
|
+
|
|
5
|
+
## O que é
|
|
6
|
+
|
|
7
|
+
Páginas customizadas dentro do Funifier Studio para atender necessidades específicas dos administradores. Permitem criar dashboards, CRUDs, gráficos, relatórios — tudo com AngularJS + Bootstrap.
|
|
8
|
+
|
|
9
|
+
## Configuração
|
|
10
|
+
|
|
11
|
+
Cada página é um JSON com:
|
|
12
|
+
- `_id` — Identificador único (auto-gerado se omitido)
|
|
13
|
+
- `display` — `true` para aparecer no menu do Studio, `false` para páginas internas
|
|
14
|
+
- `title` — Nome exibido no menu
|
|
15
|
+
- `slug` — Caminho relativo (ex: `studio/custom/hello`). Suporta parâmetros: `studio/custom/car/form/:id`
|
|
16
|
+
- `html` — Código HTML (usa Bootstrap CSS)
|
|
17
|
+
- `script` — Código JavaScript (roda no contexto AngularJS)
|
|
18
|
+
|
|
19
|
+
## Contexto JavaScript
|
|
20
|
+
|
|
21
|
+
Dentro do `script`, você tem acesso a:
|
|
22
|
+
- `$scope` — Scope do AngularJS
|
|
23
|
+
- `$http` — Para requisições HTTP
|
|
24
|
+
- `$location` — Para navegação entre páginas (`$location.path("/studio/custom/...")`)
|
|
25
|
+
- `$routeParams` — Para ler parâmetros do slug (ex: `$routeParams.id`)
|
|
26
|
+
- `Marketplace` — Objeto utilitário (ver abaixo)
|
|
27
|
+
|
|
28
|
+
### Marketplace API
|
|
29
|
+
|
|
30
|
+
| Método | Descrição | Exemplo de retorno |
|
|
31
|
+
|--------|-----------|-------------------|
|
|
32
|
+
| `Marketplace.auth.getService()` | URL da API Funifier | `https://service2.funifier.com` |
|
|
33
|
+
| `Marketplace.auth.getAuthorization()` | Token de acesso do usuário logado no Studio | Bearer token |
|
|
34
|
+
| `Marketplace.range.parse(content_range)` | Analisa header `content-range` para paginação | `{page, pages, count, ...}` |
|
|
35
|
+
| `Marketplace.range.paginate(page, content_range)` | Gera header `Range` para ir a uma página | `items=0-100` |
|
|
36
|
+
|
|
37
|
+
## Diretivas Disponíveis
|
|
38
|
+
|
|
39
|
+
- `<image-picker>` — Seletor de imagem (URL, local, galeria). Atributos: `on-change`, `show-picker-url`, `show-picker-local`, `show-picker-gallery`, `upload-max-size`, `transform`
|
|
40
|
+
- `<principal-picker>` — Seletor de jogadores/equipes. Atributos: `title`, `model`, `show-picker-player`, `black-list`, `max`
|
|
41
|
+
- `<input-extra>` — Campos extras dinâmicos. Atributos: `title`, `show-inline`, `model`
|
|
42
|
+
|
|
43
|
+
## Bibliotecas Disponíveis
|
|
44
|
+
|
|
45
|
+
- **Highcharts** — Gráficos (pizza, barra, linhas, etc.)
|
|
46
|
+
- **Bootstrap** — CSS framework (classes `btn`, `table`, `form-control`, etc.)
|
|
47
|
+
- **Glyphicons** — Ícones via `glyphicon glyphicon-*`
|
|
48
|
+
- Traduções: `{{'SAVE'|translate}}`, `{{'CANCEL'|translate}}`, `{{'BACK'|translate}}`, `{{'NEW'|translate}}`, `{{'SEARCH_FOR'|translate}}`
|
|
49
|
+
|
|
50
|
+
## Exemplos
|
|
51
|
+
|
|
52
|
+
### 1. Hello World
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"_id": "hello1",
|
|
56
|
+
"display": true,
|
|
57
|
+
"title": "Hello World!",
|
|
58
|
+
"slug": "studio/custom/hello",
|
|
59
|
+
"html": "<button ng-click=\"hello()\" class=\"btn btn-warning\">Hello</button>",
|
|
60
|
+
"script": "$scope.hello = function(){ alert('Hello World!'); }"
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. Lista Simples (Desafios)
|
|
65
|
+
```javascript
|
|
66
|
+
/* "display": true, "title": "Quest List", "slug": "studio/custom/challenge" */
|
|
67
|
+
$scope.all = [];
|
|
68
|
+
$scope.list = function () {
|
|
69
|
+
$http({method: 'GET', url:Marketplace.auth.getService() + '/v3/database/challenge',
|
|
70
|
+
headers: {"Authorization": Marketplace.auth.getAuthorization(), "content-type": "application/json"}
|
|
71
|
+
}).then(function(data){
|
|
72
|
+
$scope.all = data.data;
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
$scope.list();
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 3. Lista Paginada (Players)
|
|
79
|
+
```javascript
|
|
80
|
+
/* "display": true, "title": "Player List", "slug": "studio/custom/player" */
|
|
81
|
+
$scope.range = { request: "items=0-100" };
|
|
82
|
+
$scope.gotopage = function(page){
|
|
83
|
+
$scope.range.request = Marketplace.range.paginate(page, $scope.range.response);
|
|
84
|
+
$scope.list();
|
|
85
|
+
};
|
|
86
|
+
$scope.paginate = function (total) {
|
|
87
|
+
var to = $scope.range.page + total;
|
|
88
|
+
$scope.range.request = Marketplace.range.paginate(to, $scope.range.response);
|
|
89
|
+
$scope.list();
|
|
90
|
+
};
|
|
91
|
+
$scope.all = [];
|
|
92
|
+
$scope.list = function () {
|
|
93
|
+
$http({method: 'GET', url:Marketplace.auth.getService() + '/v3/database/player',
|
|
94
|
+
headers: {"Authorization": Marketplace.auth.getAuthorization(), "Range": $scope.range.request, "content-type": "application/json"}
|
|
95
|
+
}).then(function(data){
|
|
96
|
+
$scope.all = data.data;
|
|
97
|
+
$scope.range = Marketplace.range.parse(data.headers(["content-range"]));
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
$scope.list();
|
|
101
|
+
```
|
|
102
|
+
HTML de paginação:
|
|
103
|
+
```html
|
|
104
|
+
<div>
|
|
105
|
+
Page <input type="number" ng-model="range.page" ng-change="gotopage(range.page)" style="width:40px;" /> of {{range.pages}}
|
|
106
|
+
<button ng-click="paginate(-1)" class="btn btn-default"><span class="glyphicon glyphicon-chevron-left"></span></button>
|
|
107
|
+
<button ng-click="paginate(+1)" class="btn btn-default"><span class="glyphicon glyphicon-chevron-right"></span></button>
|
|
108
|
+
</div>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 4. CRUD Completo (Carros)
|
|
112
|
+
**Lista** (`display: true`, slug: `studio/custom/car/list`): Lista + busca + paginação + botões editar/excluir + botão "NEW"
|
|
113
|
+
- DELETE: `$http({method: 'DELETE', url: API + "/v3/database/car__c?q=_id:'" + id + "'", ...})`
|
|
114
|
+
- Navegação: `$location.path("/studio/custom/car/form/" + id)` ou `"/studio/custom/car/form/new"`
|
|
115
|
+
|
|
116
|
+
**Formulário** (`display: false`, slug: `studio/custom/car/form/:id`):
|
|
117
|
+
- Carrega via GET: `/v3/database/car__c?strict=true&q=_id:'ID'`
|
|
118
|
+
- Salva via PUT: `/v3/database/car__c`
|
|
119
|
+
- Usa `$routeParams.id` para saber se é edição ou criação (`"new"` = novo)
|
|
120
|
+
- `<image-picker on-change="setImage" ...>` para upload de imagem
|
|
121
|
+
|
|
122
|
+
### 5. Gráfico Highcharts (Active Players)
|
|
123
|
+
```javascript
|
|
124
|
+
/* "display": true, "title": "Daily Active Players", "slug": "studio/custom/kpi/players" */
|
|
125
|
+
$scope.load = function () {
|
|
126
|
+
$http({
|
|
127
|
+
method: 'POST', url: Marketplace.auth.getService() + '/v3/database/action_log/aggregate',
|
|
128
|
+
headers: { Authorization: Marketplace.auth.getAuthorization(), 'content-type': 'application/json'},
|
|
129
|
+
data: [
|
|
130
|
+
{"$match": { "time": { "$gte": { "$date": "-1y" } } } },
|
|
131
|
+
{"$addFields": { "day": { "$dayOfYear": "$time" } } },
|
|
132
|
+
{"$group": { "_id": { "player": "$userId", "day": "$day" }, "time": { "$max": "$time" }}},
|
|
133
|
+
{"$group": { "_id": "$_id.day", "total_users": { "$sum": 1 }, "time": { "$max": "$time" }}},
|
|
134
|
+
{"$project": { "_id": 0, "day_of_year": '$_id', "total": '$total_users', "time": 1}},
|
|
135
|
+
{"$sort": { "day_of_year": 1 } }
|
|
136
|
+
]
|
|
137
|
+
}).then(function (data) {
|
|
138
|
+
var transformedData = data.data.map(function (d) { return [d.time, d.total]; });
|
|
139
|
+
new Highcharts.Chart({
|
|
140
|
+
chart: { renderTo: 'chart', type: 'line' },
|
|
141
|
+
title: { text: 'Daily Active Players' },
|
|
142
|
+
xAxis: { type: 'datetime' },
|
|
143
|
+
yAxis: { title: { text: 'Total' } },
|
|
144
|
+
series: [{ name: 'Total over time', data: transformedData }],
|
|
145
|
+
credits: { enabled: false }
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
$scope.load();
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## API REST para Gerenciar Páginas
|
|
153
|
+
|
|
154
|
+
**IMPORTANTE:** As páginas customizadas ficam na collection `studio_page` (NÃO `page`).
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Criar/atualizar página
|
|
158
|
+
curl -X PUT "https://service2.funifier.com/v3/database/studio_page" \
|
|
159
|
+
-H "Authorization: Bearer TOKEN" \
|
|
160
|
+
-H "Content-Type: application/json" \
|
|
161
|
+
-d '{"_id":"minha_pagina", "display":true, "title":"Minha Página", "slug":"studio/custom/minha-pagina", "html":"<h1>Oi</h1>", "script":"/* js */"}'
|
|
162
|
+
|
|
163
|
+
# Listar páginas
|
|
164
|
+
curl "https://service2.funifier.com/v3/database/studio_page" \
|
|
165
|
+
-H "Authorization: Bearer TOKEN"
|
|
166
|
+
|
|
167
|
+
# Deletar página
|
|
168
|
+
curl -X DELETE "https://service2.funifier.com/v3/database/studio_page?q=_id:'ID'" \
|
|
169
|
+
-H "Authorization: Bearer TOKEN"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Checklist
|
|
173
|
+
|
|
174
|
+
- [ ] Definir `_id`, `title`, `slug`, `display`
|
|
175
|
+
- [ ] Escrever `html` com Bootstrap
|
|
176
|
+
- [ ] Escrever `script` com AngularJS
|
|
177
|
+
- [ ] Usar `Marketplace.auth.*` para autenticação
|
|
178
|
+
- [ ] Usar `?strict=true` em GETs para preservar tipos BSON
|
|
179
|
+
- [ ] Testar no Studio (navegar até a URL do slug)
|
|
180
|
+
- [ ] Para CRUDs: criar página de lista (display:true) + formulário (display:false)
|