deploy-webapp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,338 @@
1
+ # Deploy WebApp - Guia Passo a Passo
2
+
3
+ Este projeto automatiza o processo de migração de workflows do ambiente QA para PROD no WebApp.
4
+
5
+ ## 📋 Índice
6
+
7
+ 1. [Pré-requisitos](#pré-requisitos)
8
+ 2. [Configuração](#configuração)
9
+ 3. [Estrutura de Arquivos](#estrutura-de-arquivos)
10
+ 4. [Como Executar](#como-executar)
11
+ 5. [Empacotamento](#empacotamento)
12
+ 6. [Fluxo do Processo](#fluxo-do-processo)
13
+ 7. [Sequência de Operações](#sequência-de-operações)
14
+ 8. [Troubleshooting](#troubleshooting)
15
+
16
+ ## 🔧 Pré-requisitos
17
+
18
+ - Node.js instalado
19
+ - Yarn ou npm instalado
20
+ - Acesso aos ambientes QA e PROD
21
+ - Credenciais de autenticação para ambos os ambientes
22
+
23
+ ## ⚙️ Configuração
24
+
25
+ ### 1. Instalar Dependências
26
+
27
+ ```bash
28
+ yarn install
29
+ # ou
30
+ npm install
31
+ ```
32
+
33
+ ### 2. Configurar Variáveis de Ambiente
34
+
35
+ Crie um arquivo `.env` na raiz do projeto com as seguintes variáveis:
36
+
37
+ ```env
38
+ # Configurações Gerais
39
+ CLIENT=seu_client_id
40
+ SERVICE_KEY=sua_service_key
41
+
42
+ # Ambiente QA
43
+ CLIENT_ID_QA=client_id_qa
44
+ EMAIL_LOGIN_QA=email@qa.com
45
+ PASSWORD_LOGIN_QA=senha_qa
46
+ URL_QA=https://url-qa.com
47
+
48
+ # Ambiente PROD
49
+ CLIENT_ID_PROD=client_id_prod
50
+ EMAIL_LOGIN_PROD=email@prod.com
51
+ PASSWORD_LOGIN_PROD=senha_prod
52
+ URL_PROD=https://url-prod.com
53
+ ```
54
+
55
+ ### 3. Preparar Arquivos de Configuração
56
+
57
+ #### `src/utils/ids.csv`
58
+
59
+ Arquivo CSV com os IDs dos workflows a serem migrados. Formato:
60
+
61
+ ```csv
62
+ workflow_id
63
+ d8e1d640-f734-4051-b296-1938cbf47e86
64
+ outro-workflow-id
65
+ ```
66
+
67
+ #### `src/utils/updateWorkflow.json`
68
+
69
+ Arquivo JSON com configurações de atualização do workflow. Exemplo:
70
+
71
+ ```json
72
+ {
73
+ "flow_form_id": "id do form de produção",
74
+ "pendency_custom_filters": "função stringficada (se tiver)", // DICA: coloque os ids de QA e de PROD junto, feito isso nao tera problemas em deploys futuros
75
+ "updateWorkflowProtocolFunction": "função stringficada (se tiver)" // DICA: coloque os ids de QA e de PROD junto, feito isso nao tera problemas em deploys futuros
76
+ }
77
+ ```
78
+
79
+ ## 📁 Estrutura de Arquivos
80
+
81
+ ```
82
+ deployWebApp/
83
+ ├── src/
84
+ │ ├── 0_index.ts # Ponto de entrada
85
+ │ ├── 0.1_migrator.ts # Lógica principal de migração
86
+ │ ├── apis/
87
+ │ │ ├── qa-client.ts # Cliente API QA
88
+ │ │ └── prod-client.ts # Cliente API PROD
89
+ │ ├── functions/
90
+ │ │ ├── 1_workflow.ts # Processamento de workflows
91
+ │ │ ├── 1.1_workflow_group.ts # Processamento de grupos
92
+ │ │ ├── 1.2_workflow_group_item.ts
93
+ │ │ ├── 2_workflow_step.ts # Processamento de steps
94
+ │ │ ├── 2.1_workflow_step_forms.ts
95
+ │ │ ├── 2.1.1_workflow_forms.ts
96
+ │ │ ├── 3_client_function.ts
97
+ │ │ └── 4_workflow_form_groups.ts
98
+ │ └── utils/
99
+ │ ├── constants.ts # Constantes e configurações
100
+ │ ├── data-processing.ts # Processamento de dados
101
+ │ ├── ids.csv # IDs dos workflows
102
+ │ ├── updateWorkflow.json # Configurações de atualização
103
+ │ ├── history_created.txt # Histórico de criados
104
+ │ └── history_updated.txt # Histórico de atualizados
105
+ └── package.json
106
+ ```
107
+
108
+ ## 🚀 Como Executar
109
+
110
+ ### Executar Migração
111
+
112
+ ```bash
113
+ yarn start
114
+ # ou
115
+ npm start
116
+ ```
117
+
118
+ O script irá:
119
+ 1. Limpar os históricos anteriores
120
+ 2. Fazer login nos ambientes QA e PROD
121
+ 3. Processar cada workflow do arquivo `ids.csv`
122
+ 4. Exibir logs de progresso
123
+ 5. Salvar histórico de operações
124
+
125
+ ## 🔄 Fluxo do Processo
126
+
127
+ ### Visão Geral
128
+
129
+ O processo segue esta sequência para cada workflow:
130
+
131
+ 1. **Publicar Workflow em QA**
132
+ 2. **Obter Workflow de QA**
133
+ 3. **Processar Workflow** (CREATE ou UPDATE em PROD)
134
+ 4. **Processar Workflow Steps**
135
+ 5. **Processar Client Functions**
136
+ 6. **Processar Workflow Form Groups**
137
+ 7. **Publicar Workflow em PROD**
138
+
139
+ ### Sequência Detalhada
140
+
141
+ #### 1. Workflow Principal
142
+
143
+ ```
144
+ GET QA → GET PROD → CREATE/UPDATE PROD
145
+ ```
146
+
147
+ - Se existe em PROD: **UPDATE**
148
+ - Se não existe em PROD: **CREATE**
149
+
150
+ #### 2. Workflow Group
151
+
152
+ ```
153
+ GET QA → GET PROD → CREATE/UPDATE PROD
154
+ ```
155
+
156
+ #### 3. Workflow Group Items
157
+
158
+ ```
159
+ Para cada item:
160
+ GET QA → GET PROD → CREATE/UPDATE PROD
161
+ ```
162
+
163
+ #### 4. Workflow Steps
164
+
165
+ ```
166
+ Para cada step:
167
+ GET QA → GET PROD → CREATE/UPDATE PROD
168
+
169
+ Para cada workflow-step-form:
170
+ GET QA (workflow-form) → GET PROD (workflow-form) → CREATE/UPDATE PROD (workflow-form)
171
+ GET QA (workflow-step-form) → GET PROD (workflow-step-form) → CREATE/UPDATE PROD (workflow-step-form)
172
+ ```
173
+
174
+ #### 5. Workflow Forms
175
+
176
+ **IMPORTANTE:** Sempre segue a sequência:
177
+
178
+ ```
179
+ GET QA → GET PROD → CREATE/UPDATE PROD
180
+ ```
181
+
182
+ A função `WorkflowForms` garante que:
183
+ - Sempre faz GET em QA primeiro
184
+ - Depois faz GET em PROD para verificar existência
185
+ - Finalmente faz CREATE ou UPDATE conforme necessário
186
+
187
+ #### 6. Workflow Form Groups
188
+
189
+ ```
190
+ GET QA → GET PROD → CREATE/UPDATE PROD
191
+
192
+ Para cada workflow-form dentro do grupo:
193
+ GET QA → GET PROD → CREATE/UPDATE PROD
194
+ ```
195
+
196
+ ## 📊 Sequência de Operações
197
+
198
+ ### Ordem de Execução para Cada Workflow
199
+
200
+ ```
201
+ 1. Login QA ✅
202
+ 2. Login PROD ✅
203
+ 3. Publish Workflow QA ✅
204
+ 4. Get Workflow QA ✅
205
+ 5. Get Workflow PROD ✅
206
+ 6. Create/Update Workflow PROD ✅
207
+ 7. Get Workflow Group QA ✅
208
+ 8. Get Workflow Group PROD ✅
209
+ 9. Create/Update Workflow Group PROD ✅
210
+ 10. Para cada Workflow Group Item:
211
+ - Get QA → Get PROD → Create/Update PROD ✅
212
+ 11. Para cada Workflow Step:
213
+ - Get QA → Get PROD → Create/Update PROD ✅
214
+ - Para cada Workflow Step Form:
215
+ - Get Workflow Form QA ✅
216
+ - Get Workflow Form PROD ✅
217
+ - Create/Update Workflow Form PROD ✅
218
+ - Get Workflow Step Form QA ✅
219
+ - Get Workflow Step Form PROD ✅
220
+ - Create/Update Workflow Step Form PROD ✅
221
+ 12. Process Client Function ✅
222
+ 13. Para cada Workflow Form Group:
223
+ - Get QA → Get PROD → Create/Update PROD ✅
224
+ - Para cada Workflow Form:
225
+ - Get QA → Get PROD → Create/Update PROD ✅
226
+ 14. Publish Workflow PROD ✅
227
+ ```
228
+
229
+ ## 🔍 Regras de Negócio
230
+
231
+ ### Sanitização de Dados
232
+
233
+ O sistema sanitiza automaticamente os dados de `workflow-form`:
234
+
235
+ - **placeholder**: Se vazio/null → `" "` (3 espaços)
236
+ - **required**: Se null/undefined → `false`
237
+ - **index**: Se null/undefined → `1`
238
+ - **title**: Se vazio/null → `" "` (3 espaços)
239
+ - **length**: Se null/undefined ou não é número → `0`
240
+
241
+ ### Substituição de Strings
242
+
243
+ O sistema substitui automaticamente:
244
+
245
+ - URLs de QA → URLs de PROD
246
+ - Client IDs de QA → Client IDs de PROD
247
+ - Configurações de ambiente
248
+ - Flags de mock
249
+
250
+ #### Como Adicionar Mais Strings para Mapeamento
251
+
252
+ Para adicionar novas regras de substituição de strings, edite o arquivo `src/utils/constants.ts` e adicione novos objetos ao array `replacementRules`:
253
+
254
+ **Exemplo prático:**
255
+ Se você precisa substituir um ID específico ou uma URL customizada:
256
+
257
+ ```typescript
258
+ // No arquivo constants.ts
259
+ export const CUSTOM_ID_QA = "id-qa-123"; // string como esta em qa
260
+ export const CUSTOM_ID_PROD = "id-prod-456"; // string como vai ficar em prod
261
+
262
+ export const replacementRules = [
263
+ // ... regras existentes ...
264
+ { from: CUSTOM_ID_QA, to: CUSTOM_ID_PROD },
265
+ ];
266
+ ```
267
+
268
+ **Importante:**
269
+ - As substituições são feitas recursivamente em todos os objetos e arrays
270
+ - A ordem das regras importa: as substituições são aplicadas sequencialmente
271
+ - Use strings exatas que correspondem ao que você quer substituir
272
+
273
+ ### Histórico
274
+
275
+ - `history_created.txt`: Registra todos os recursos criados
276
+ - `history_updated.txt`: Registra todos os recursos atualizados
277
+
278
+ ## ⚠️ Troubleshooting
279
+
280
+ ### Erro: "WorkflowForm is not found"
281
+
282
+ **Causa:** Tentativa de UPDATE sem verificar existência em PROD.
283
+
284
+ **Solução:** O sistema já foi corrigido para sempre fazer GET em PROD antes de UPDATE. Se ainda ocorrer, verifique:
285
+ - A função `WorkflowForms` está sendo chamada corretamente
286
+ - O GET em PROD está sendo executado antes do UPDATE
287
+
288
+ ### Erro: "Variáveis de ambiente não definidas"
289
+
290
+ **Solução:** Verifique se o arquivo `.env` existe e contém todas as variáveis necessárias.
291
+
292
+ ### Erro: "Workflow X not found in QA"
293
+
294
+ **Causa:** O workflow não existe no ambiente QA.
295
+
296
+ **Solução:** Verifique se o ID do workflow está correto no arquivo `ids.csv`.
297
+
298
+ ### CREATE executado após "DEPLOYMENT COMPLETED!"
299
+
300
+ **Causa:** Promise não aguardada corretamente.
301
+
302
+ **Solução:** Já corrigido. O sistema agora usa `await` em todas as operações assíncronas.
303
+
304
+ ### Erro de validação: "length must be a number"
305
+
306
+ **Causa:** Campo `length` não está sendo sanitizado.
307
+
308
+ **Solução:** Já corrigido. O sistema agora sanitiza o campo `length` automaticamente.
309
+
310
+ ## 📝 Logs
311
+
312
+ O sistema exibe logs coloridos:
313
+
314
+ - 🟢 **Verde**: Sucesso
315
+ - 🔴 **Vermelho**: Erro
316
+ - 🟡 **Amarelo**: Aviso/Info
317
+ - 🔵 **Azul**: Informação
318
+
319
+ ## 🔐 Segurança
320
+
321
+ - **NUNCA** commite o arquivo `.env` no repositório
322
+ - Mantenha as credenciais seguras
323
+ - Use variáveis de ambiente em produção
324
+ - Revise os logs antes de executar em produção
325
+
326
+ ## 📞 Suporte
327
+
328
+ Em caso de problemas:
329
+
330
+ 1. Verifique os logs de erro
331
+ 2. Confirme que todas as variáveis de ambiente estão configuradas
332
+ 3. Verifique se os arquivos de configuração estão corretos
333
+ 4. Revise o histórico de operações (`history_created.txt` e `history_updated.txt`)
334
+
335
+ ---
336
+
337
+ **Última atualização:** 12/2025
338
+ **Versão:** 1.0.0
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runMigration = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const console_1 = require("console");
40
+ const constants_1 = require("./utils/constants");
41
+ const qa_client_1 = require("./apis/qa-client");
42
+ const prod_client_1 = require("./apis/prod-client");
43
+ const _2_workflow_step_1 = require("./functions/2_workflow_step");
44
+ const _3_client_function_1 = require("./functions/3_client_function");
45
+ const _4_workflow_form_groups_1 = require("./functions/4_workflow_form_groups");
46
+ const _1_workflow_1 = require("./functions/1_workflow");
47
+ const logsDirectory = path.resolve(__dirname, "./utils");
48
+ const runMigration = async () => {
49
+ if (!constants_1.emailLoginQA || !constants_1.passwordLoginQA || !constants_1.emailLoginPROD || !constants_1.passwordLoginPROD || !constants_1.client || !constants_1.serviceKey) {
50
+ throw new Error("Variáveis de ambiente WEBAPP_QA_EMAIL_LOGIN, WEBAPP_QA_PASSWORD_LOGIN, WEBAPP_PROD_EMAIL_LOGIN, WEBAPP_PROD_PASSWORD_LOGIN, CLIENT_ID e/ou SERVICE_KEY não definidas");
51
+ }
52
+ // Limpa os arquivos de histórico antes de começar
53
+ (0, constants_1.clearHistoryCreated)();
54
+ (0, constants_1.clearHistoryUpdated)();
55
+ (0, console_1.log)(`${constants_1.cor.Yellow}Históricos limpos. Iniciando migração...${constants_1.cor.Reset}`);
56
+ const access_token_qa = await (0, qa_client_1.loginQA)(constants_1.client, constants_1.serviceKey, constants_1.emailLoginQA, constants_1.passwordLoginQA);
57
+ const access_token_prod = await (0, prod_client_1.loginPROD)(constants_1.client, constants_1.serviceKey, constants_1.emailLoginPROD, constants_1.passwordLoginPROD);
58
+ const updateWorkflow = path.resolve(logsDirectory, "updateWorkflow.json");
59
+ const getUpdateWorkflow = fs.readFileSync(updateWorkflow, "utf8");
60
+ const updateWorkflowData = JSON.parse(getUpdateWorkflow);
61
+ const csvFilePath = path.resolve(logsDirectory, "ids.csv");
62
+ const csv = require("csvtojson");
63
+ const jsonArray = await csv({ delimiter: ";" }).fromFile(csvFilePath);
64
+ const arrayIds = jsonArray.map((row) => ({
65
+ id: row.workflow_id
66
+ }));
67
+ const execute = async (info) => {
68
+ var _a, _b;
69
+ try {
70
+ //////////////////////// PUBLISH WORKFLOW QA ////////////////////////
71
+ await (0, qa_client_1.publishWorkflowQA)(access_token_qa, info.id, constants_1.client, constants_1.serviceKey, `techforms/workflow/${info.id}`, "workflow");
72
+ //////////////////////// WORKFLOW ////////////////////////
73
+ const workflow = await (0, qa_client_1.getQA)(access_token_qa, undefined, constants_1.client, constants_1.serviceKey, `techforms/workflow/${info.id}`, "workflow", info.id);
74
+ const groupItems = workflow.workflow_group_item || [];
75
+ if (!workflow) {
76
+ (0, console_1.log)(`${constants_1.cor.Blue}Workflow ${info.id} not found in QA${constants_1.cor.Reset}`);
77
+ return;
78
+ }
79
+ await (0, _1_workflow_1.Workflow)(access_token_qa, access_token_prod, workflow, constants_1.client, constants_1.serviceKey, info.id, updateWorkflowData);
80
+ //////////////////////// WORKFLOW STEPS ////////////////////////
81
+ const workflowSteps = workflow.workflow_steps;
82
+ await (0, _2_workflow_step_1.WorkflowSteps)(workflowSteps, access_token_qa, access_token_prod, constants_1.client, constants_1.serviceKey, undefined, undefined, updateWorkflowData);
83
+ //////////////////////// CLIENT-FUNCTION ////////////////////////
84
+ const update_workflow_protocol_function_id = workflow.update_workflow_protocol_function_id;
85
+ await (0, _3_client_function_1.ClientFunction)(update_workflow_protocol_function_id, access_token_qa, access_token_prod, constants_1.client, constants_1.serviceKey, updateWorkflowData);
86
+ //////////////////////// WORKFLOW FORM GROUP ////////////////////////
87
+ const workflowFormGroupQA = workflow.workflow_form_groups;
88
+ await (0, _4_workflow_form_groups_1.WorkflowFormGroups)(workflowFormGroupQA, access_token_qa, access_token_prod, constants_1.client, constants_1.serviceKey, info.id, updateWorkflowData);
89
+ //////////////////////// PUBLISH WORKFLOW PROD ////////////////////////
90
+ await (0, prod_client_1.publishWorkflowPROD)(access_token_prod, info.id, constants_1.client, constants_1.serviceKey, `techforms/workflow/${info.id}`, "workflow");
91
+ }
92
+ catch (error) {
93
+ (0, console_1.log)(`${constants_1.cor.Red}Error to process ID ${info.id}: ${JSON.stringify((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message)}${constants_1.cor.Reset}`);
94
+ }
95
+ };
96
+ for (const info of arrayIds) {
97
+ await execute(info);
98
+ }
99
+ (0, console_1.log)(`${constants_1.cor.Green}DEPLOYMENT COMPLETED!${constants_1.cor.Reset}`);
100
+ };
101
+ exports.runMigration = runMigration;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runMigration = void 0;
7
+ const dotenv_1 = __importDefault(require("dotenv"));
8
+ const _0_1_migrator_1 = require("./0.1_migrator");
9
+ Object.defineProperty(exports, "runMigration", { enumerable: true, get: function () { return _0_1_migrator_1.runMigration; } });
10
+ if (require.main === module) {
11
+ dotenv_1.default.config();
12
+ (0, _0_1_migrator_1.runMigration)().catch(error => {
13
+ console.error("Migration failed:", error);
14
+ process.exit(1);
15
+ });
16
+ }