ante-erp-cli 1.11.56 → 1.11.58

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/bin/ante-cli.js CHANGED
@@ -330,8 +330,8 @@ program
330
330
  .option('--guardian <url>', 'Guardian App domain/URL (non-interactive mode)')
331
331
  .option('--facial <url>', 'Facial Web domain/URL (non-interactive mode)')
332
332
  .option('--pos <url>', 'POS App domain/URL (non-interactive mode)')
333
- .option('--client <url>', 'Client App domain/URL (non-interactive mode)')
334
- .option('--backend-client <url>', 'Backend Client API domain/URL (non-interactive mode)')
333
+ .option('--mlm <url>', 'MLM App domain/URL (non-interactive mode)')
334
+ .option('--backend-mlm <url>', 'Backend MLM API domain/URL (non-interactive mode)')
335
335
  .option('--detect', 'Auto-detect public IP address')
336
336
  .option('--ssl, --enable-ssl', 'Enable SSL certificate (Let\'s Encrypt)')
337
337
  .option('--cloudflare-ssl', 'Enable Cloudflare SSL mode (self-signed cert for Full mode)')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ante-erp-cli",
3
- "version": "1.11.56",
3
+ "version": "1.11.58",
4
4
  "description": "Comprehensive CLI tool for managing ANTE ERP self-hosted installations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -82,7 +82,7 @@ function showSuccess(installDir, credentials, config) {
82
82
  const guardianAppUrl = config.guardianAppDomain || 'http://localhost:8082';
83
83
  const facialWebUrl = config.facialAppDomain || 'http://localhost:8083';
84
84
  const posAppUrl = config.posAppDomain || 'http://localhost:8084';
85
- const clientAppUrl = config.clientAppDomain || 'http://localhost:9005';
85
+ const mlmAppUrl = config.mlmAppDomain || 'http://localhost:9005';
86
86
 
87
87
  let accessInfo = chalk.white('Access Information:') + '\n' +
88
88
  chalk.gray('━'.repeat(40)) + '\n' +
@@ -104,8 +104,8 @@ function showSuccess(installDir, credentials, config) {
104
104
  accessInfo += chalk.cyan('POS App: ') + chalk.white(posAppUrl) + '\n';
105
105
  }
106
106
 
107
- if (config.installClient) {
108
- accessInfo += chalk.cyan('Client App: ') + chalk.white(clientAppUrl) + '\n';
107
+ if (config.installMlm) {
108
+ accessInfo += chalk.cyan('MLM App: ') + chalk.white(mlmAppUrl) + '\n';
109
109
  }
110
110
 
111
111
  accessInfo += chalk.cyan('Backend: ') + chalk.white(apiUrl) + '\n' +
@@ -318,39 +318,39 @@ export async function install(options) {
318
318
  const host = detectedIP || 'localhost';
319
319
  const frontendPort = parseInt(options.port) || 8080;
320
320
  const apiPort = 3001;
321
- const backendClientPort = 4001;
321
+ const backendMlmPort = 4001;
322
322
  const gateAppPort = 8081;
323
323
  const guardianAppPort = 8082;
324
324
  const facialWebPort = 8083;
325
325
  const posAppPort = 8084;
326
- const clientAppPort = 9005;
326
+ const mlmAppPort = 9005;
327
327
 
328
328
  const config = {
329
329
  installDir: options.dir || './ante-erp',
330
330
  preset: 'enterprise', // Always install all features
331
331
  frontendDomain: buildURL(host, frontendPort),
332
332
  apiDomain: buildURL(host, apiPort),
333
- clientApiDomain: buildURL(host, backendClientPort),
333
+ mlmApiDomain: buildURL(host, backendMlmPort),
334
334
  gateAppDomain: buildURL(host, gateAppPort),
335
335
  guardianAppDomain: buildURL(host, guardianAppPort),
336
336
  facialAppDomain: buildURL(host, facialWebPort),
337
337
  posAppDomain: buildURL(host, posAppPort),
338
- clientAppDomain: buildURL(host, clientAppPort),
338
+ mlmAppDomain: buildURL(host, mlmAppPort),
339
339
  frontendPort,
340
340
  apiPort,
341
- backendClientPort,
341
+ backendMlmPort,
342
342
  gateAppPort,
343
343
  guardianAppPort,
344
344
  facialWebPort,
345
345
  posAppPort,
346
- clientAppPort,
346
+ mlmAppPort,
347
347
  companyId: 1,
348
348
  installGate: true, // Install all frontends by default
349
349
  installGuardian: true,
350
350
  installFacial: true,
351
351
  installPos: true,
352
- installClient: true,
353
- frontends: ['main', 'gate', 'guardian', 'facial', 'pos', 'client']
352
+ installMlm: true,
353
+ frontends: ['main', 'gate', 'guardian', 'facial', 'pos', 'mlm']
354
354
  };
355
355
 
356
356
  console.log(chalk.green(`✓ ${formatStepTitle(stepNetworkDetect, totalSteps, `Network detected: ${host}`)}\n`));
@@ -363,9 +363,9 @@ export async function install(options) {
363
363
  console.log(chalk.cyan(' Guardian App:'), chalk.white(config.guardianAppDomain));
364
364
  console.log(chalk.cyan(' Facial Web:'), chalk.white(config.facialAppDomain));
365
365
  console.log(chalk.cyan(' POS App:'), chalk.white(config.posAppDomain));
366
- console.log(chalk.cyan(' Client App:'), chalk.white(config.clientAppDomain));
366
+ console.log(chalk.cyan(' MLM App:'), chalk.white(config.mlmAppDomain));
367
367
  console.log(chalk.cyan(' API:'), chalk.white(config.apiDomain));
368
- console.log(chalk.cyan(' Client API:'), chalk.white(config.clientApiDomain));
368
+ console.log(chalk.cyan(' MLM API:'), chalk.white(config.mlmApiDomain));
369
369
  console.log();
370
370
 
371
371
  // Auto-backup existing config if exists (no prompt)
@@ -441,18 +441,18 @@ export async function install(options) {
441
441
  const dockerCompose = generateDockerCompose({
442
442
  frontendPort: config.frontendPort,
443
443
  backendPort: config.apiPort,
444
- backendClientPort: config.backendClientPort,
444
+ backendMlmPort: config.backendMlmPort,
445
445
  gateAppPort: config.gateAppPort,
446
446
  guardianAppPort: config.guardianAppPort,
447
447
  facialWebPort: config.facialWebPort,
448
448
  posAppPort: config.posAppPort,
449
- clientAppPort: config.clientAppPort,
449
+ mlmAppPort: config.mlmAppPort,
450
450
  installMain: true,
451
451
  installGate: config.installGate,
452
452
  installGuardian: config.installGuardian,
453
453
  installFacial: config.installFacial,
454
454
  installPos: config.installPos,
455
- installClient: config.installClient,
455
+ installMlm: config.installMlm,
456
456
  companyId: config.companyId
457
457
  });
458
458
 
@@ -462,24 +462,24 @@ export async function install(options) {
462
462
  socketUrl: config.apiDomain,
463
463
  frontendPort: config.frontendPort,
464
464
  backendPort: config.apiPort,
465
- backendClientPort: config.backendClientPort,
465
+ backendMlmPort: config.backendMlmPort,
466
466
  gateAppPort: config.gateAppPort,
467
467
  guardianAppPort: config.guardianAppPort,
468
468
  facialWebPort: config.facialWebPort,
469
469
  posAppPort: config.posAppPort,
470
- clientAppPort: config.clientAppPort,
470
+ mlmAppPort: config.mlmAppPort,
471
471
  gateAppUrl: config.gateAppDomain,
472
472
  guardianAppUrl: config.guardianAppDomain,
473
473
  facialWebUrl: config.facialAppDomain,
474
474
  posAppUrl: config.posAppDomain,
475
- clientAppUrl: config.clientAppDomain,
476
- clientApiUrl: config.clientApiDomain,
475
+ mlmAppUrl: config.mlmAppDomain,
476
+ mlmApiUrl: config.mlmApiDomain,
477
477
  companyId: config.companyId,
478
478
  installGate: config.installGate,
479
479
  installGuardian: config.installGuardian,
480
480
  installFacial: config.installFacial,
481
481
  installPos: config.installPos,
482
- installClient: config.installClient
482
+ installMlm: config.installMlm
483
483
  });
484
484
 
485
485
  writeFileSync(join(config.installDir, 'docker-compose.yml'), dockerCompose);
@@ -37,10 +37,10 @@ function detectInstalledApps(composeFile) {
37
37
  hasGuardianApp: composeContent.includes('guardian-app:') || composeContent.includes('container_name: ante-guardian-app'),
38
38
  hasFacialWeb: composeContent.includes('facial-web:') || composeContent.includes('container_name: ante-facial-web'),
39
39
  hasPosApp: composeContent.includes('pos-app:') || composeContent.includes('container_name: ante-pos'),
40
- hasClientApp: composeContent.includes('client-app:') || composeContent.includes('container_name: ante-client')
40
+ hasMlmApp: composeContent.includes('mlm-app:') || composeContent.includes('container_name: ante-mlm')
41
41
  };
42
42
  } catch {
43
- return { hasMain: true, hasGateApp: false, hasGuardianApp: false, hasFacialWeb: false, hasPosApp: false, hasClientApp: false };
43
+ return { hasMain: true, hasGateApp: false, hasGuardianApp: false, hasFacialWeb: false, hasPosApp: false, hasMlmApp: false };
44
44
  }
45
45
  }
46
46
 
@@ -78,7 +78,7 @@ export async function regenerateCompose() {
78
78
  console.log(chalk.gray(` Guardian App: ${installed.hasGuardianApp ? '✓ Installed' : '✗ Not installed'}`));
79
79
  console.log(chalk.gray(` Facial Web: ${installed.hasFacialWeb ? '✓ Installed' : '✗ Not installed'}`));
80
80
  console.log(chalk.gray(` POS App: ${installed.hasPosApp ? '✓ Installed' : '✗ Not installed'}`));
81
- console.log(chalk.gray(` Client App: ${installed.hasClientApp ? '✓ Installed' : '✗ Not installed'}\n`));
81
+ console.log(chalk.gray(` MLM App: ${installed.hasMlmApp ? '✓ Installed' : '✗ Not installed'}\n`));
82
82
 
83
83
  // Parse .env file
84
84
  const envConfig = parseEnvFile(envFile);
@@ -86,12 +86,12 @@ export async function regenerateCompose() {
86
86
  // Extract port configuration
87
87
  const frontendPort = parseInt(envConfig.FRONTEND_PORT) || 8080;
88
88
  const backendPort = parseInt(envConfig.BACKEND_PORT) || 3001;
89
- const backendClientPort = parseInt(envConfig.BACKEND_CLIENT_PORT) || 4001;
89
+ const backendMlmPort = parseInt(envConfig.BACKEND_MLM_PORT) || 4001;
90
90
  const gateAppPort = parseInt(envConfig.GATE_APP_PORT) || 8081;
91
91
  const guardianAppPort = parseInt(envConfig.GUARDIAN_APP_PORT) || 8082;
92
92
  const facialWebPort = parseInt(envConfig.FACIAL_WEB_PORT) || 8083;
93
93
  const posAppPort = parseInt(envConfig.POS_APP_PORT) || 8084;
94
- const clientAppPort = parseInt(envConfig.CLIENT_APP_PORT) || 9005;
94
+ const mlmAppPort = parseInt(envConfig.MLM_APP_PORT) || 9005;
95
95
  const companyId = parseInt(envConfig.COMPANY_ID) || 1;
96
96
 
97
97
  console.log(chalk.cyan('Port Configuration:'));
@@ -109,9 +109,9 @@ export async function regenerateCompose() {
109
109
  if (installed.hasPosApp) {
110
110
  console.log(chalk.gray(` POS App: ${posAppPort}`));
111
111
  }
112
- if (installed.hasClientApp) {
113
- console.log(chalk.gray(` Client App: ${clientAppPort}`));
114
- console.log(chalk.gray(` Backend Client: ${backendClientPort}`));
112
+ if (installed.hasMlmApp) {
113
+ console.log(chalk.gray(` MLM App: ${mlmAppPort}`));
114
+ console.log(chalk.gray(` Backend MLM: ${backendMlmPort}`));
115
115
  }
116
116
  console.log(chalk.gray(` Company ID: ${companyId}\n`));
117
117
 
@@ -128,18 +128,18 @@ export async function regenerateCompose() {
128
128
  const newCompose = generateDockerCompose({
129
129
  frontendPort,
130
130
  backendPort,
131
- backendClientPort,
131
+ backendMlmPort,
132
132
  gateAppPort,
133
133
  guardianAppPort,
134
134
  facialWebPort,
135
135
  posAppPort,
136
- clientAppPort,
136
+ mlmAppPort,
137
137
  installMain: installed.hasMain,
138
138
  installGate: installed.hasGateApp,
139
139
  installGuardian: installed.hasGuardianApp,
140
140
  installFacial: installed.hasFacialWeb,
141
141
  installPos: installed.hasPosApp,
142
- installClient: installed.hasClientApp,
142
+ installMlm: installed.hasMlmApp,
143
143
  companyId
144
144
  });
145
145
 
@@ -96,9 +96,9 @@ function getEnvValue(envPath, key) {
96
96
  }
97
97
 
98
98
  /**
99
- * Check if gate-app, guardian-app, facial-web, pos-app, client-app, or backend-client is installed by checking docker-compose.yml
99
+ * Check if gate-app, guardian-app, facial-web, pos-app, mlm-app, or backend-mlm is installed by checking docker-compose.yml
100
100
  * @param {string} composeFile - Path to docker-compose.yml
101
- * @returns {{hasGateApp: boolean, hasGuardianApp: boolean, hasFacialWeb: boolean, hasPosApp: boolean, hasClientApp: boolean, hasBackendClient: boolean}}
101
+ * @returns {{hasGateApp: boolean, hasGuardianApp: boolean, hasFacialWeb: boolean, hasPosApp: boolean, hasMlmApp: boolean, hasBackendMlm: boolean}}
102
102
  */
103
103
  function detectInstalledApps(composeFile) {
104
104
  try {
@@ -108,11 +108,11 @@ function detectInstalledApps(composeFile) {
108
108
  hasGuardianApp: composeContent.includes('guardian-app:') || composeContent.includes('container_name: ante-guardian-app'),
109
109
  hasFacialWeb: composeContent.includes('facial-web:') || composeContent.includes('container_name: ante-facial-web'),
110
110
  hasPosApp: composeContent.includes('pos-app:') || composeContent.includes('container_name: ante-pos'),
111
- hasClientApp: composeContent.includes('client-app:') || composeContent.includes('container_name: ante-client'),
112
- hasBackendClient: composeContent.includes('backend-client:') || composeContent.includes('container_name: ante-backend-client')
111
+ hasMlmApp: composeContent.includes('mlm-app:') || composeContent.includes('container_name: ante-mlm'),
112
+ hasBackendMlm: composeContent.includes('backend-mlm:') || composeContent.includes('container_name: ante-backend-mlm')
113
113
  };
114
114
  } catch {
115
- return { hasGateApp: false, hasGuardianApp: false, hasFacialWeb: false, hasPosApp: false, hasClientApp: false, hasBackendClient: false };
115
+ return { hasGateApp: false, hasGuardianApp: false, hasFacialWeb: false, hasPosApp: false, hasMlmApp: false, hasBackendMlm: false };
116
116
  }
117
117
  }
118
118
 
@@ -160,10 +160,10 @@ export async function setDomain(options) {
160
160
  console.log(); // Add spacing
161
161
  }
162
162
 
163
- let frontendUrl, apiUrl, gateAppUrl, guardianAppUrl, facialWebUrl, posAppUrl, clientAppUrl, backendClientUrl;
163
+ let frontendUrl, apiUrl, gateAppUrl, guardianAppUrl, facialWebUrl, posAppUrl, mlmAppUrl, backendMlmUrl;
164
164
 
165
165
  // Detect which apps are installed
166
- const { hasGateApp, hasGuardianApp, hasFacialWeb, hasPosApp, hasClientApp, hasBackendClient } = detectInstalledApps(composeFile);
166
+ const { hasGateApp, hasGuardianApp, hasFacialWeb, hasPosApp, hasMlmApp, hasBackendMlm } = detectInstalledApps(composeFile);
167
167
 
168
168
  if (options.interactive !== false) {
169
169
  // Show current values
@@ -173,8 +173,8 @@ export async function setDomain(options) {
173
173
  const currentGuardianAppUrl = getEnvValue(envPath, 'GUARDIAN_APP_URL');
174
174
  const currentFacialWebUrl = getEnvValue(envPath, 'FACIAL_WEB_URL');
175
175
  const currentPosAppUrl = getEnvValue(envPath, 'POS_APP_URL');
176
- const currentClientAppUrl = getEnvValue(envPath, 'CLIENT_APP_URL');
177
- const currentBackendClientUrl = getEnvValue(envPath, 'CLIENT_API_URL');
176
+ const currentClientAppUrl = getEnvValue(envPath, 'MLM_APP_URL');
177
+ const currentBackendClientUrl = getEnvValue(envPath, 'MLM_API_URL');
178
178
 
179
179
  if (currentFrontendUrl) {
180
180
  console.log(chalk.gray(`Current Frontend URL: ${currentFrontendUrl}`));
@@ -192,10 +192,10 @@ export async function setDomain(options) {
192
192
  console.log(chalk.gray(`Current POS App URL: ${currentPosAppUrl}`));
193
193
  }
194
194
  if (currentClientAppUrl) {
195
- console.log(chalk.gray(`Current Client App URL: ${currentClientAppUrl}`));
195
+ console.log(chalk.gray(`Current MLM App URL: ${currentClientAppUrl}`));
196
196
  }
197
197
  if (currentBackendClientUrl) {
198
- console.log(chalk.gray(`Current Backend-Client API URL: ${currentBackendClientUrl}`));
198
+ console.log(chalk.gray(`Current Backend-MLM API URL: ${currentBackendClientUrl}`));
199
199
  }
200
200
  if (currentApiUrl) {
201
201
  console.log(chalk.gray(`Current API URL: ${currentApiUrl}\n`));
@@ -264,11 +264,11 @@ export async function setDomain(options) {
264
264
  });
265
265
  }
266
266
 
267
- if (hasClientApp) {
267
+ if (hasMlmApp) {
268
268
  portPrompts.push({
269
269
  type: 'number',
270
- name: 'clientAppPort',
271
- message: 'Client App port:',
270
+ name: 'mlmAppPort',
271
+ message: 'MLM App port:',
272
272
  default: 9005
273
273
  });
274
274
  }
@@ -288,7 +288,7 @@ export async function setDomain(options) {
288
288
  if (hasGuardianApp) guardianAppUrl = buildURL(detectedIP, ports.guardianAppPort);
289
289
  if (hasFacialWeb) facialWebUrl = buildURL(detectedIP, ports.facialWebPort);
290
290
  if (hasPosApp) posAppUrl = buildURL(detectedIP, ports.posAppPort);
291
- if (hasClientApp) clientAppUrl = buildURL(detectedIP, ports.clientAppPort);
291
+ if (hasMlmApp) mlmAppUrl = buildURL(detectedIP, ports.mlmAppPort);
292
292
  } else if (configType.type === 'localhost') {
293
293
  const portPrompts = [
294
294
  {
@@ -335,11 +335,11 @@ export async function setDomain(options) {
335
335
  });
336
336
  }
337
337
 
338
- if (hasClientApp) {
338
+ if (hasMlmApp) {
339
339
  portPrompts.push({
340
340
  type: 'number',
341
- name: 'clientAppPort',
342
- message: 'Client App port:',
341
+ name: 'mlmAppPort',
342
+ message: 'MLM App port:',
343
343
  default: 9005
344
344
  });
345
345
  }
@@ -359,7 +359,7 @@ export async function setDomain(options) {
359
359
  if (hasGuardianApp) guardianAppUrl = buildURL('localhost', ports.guardianAppPort);
360
360
  if (hasFacialWeb) facialWebUrl = buildURL('localhost', ports.facialWebPort);
361
361
  if (hasPosApp) posAppUrl = buildURL('localhost', ports.posAppPort);
362
- if (hasClientApp) clientAppUrl = buildURL('localhost', ports.clientAppPort);
362
+ if (hasMlmApp) mlmAppUrl = buildURL('localhost', ports.mlmAppPort);
363
363
  } else if (configType.type === 'custom-ip') {
364
364
  const ipPrompts = [
365
365
  {
@@ -415,11 +415,11 @@ export async function setDomain(options) {
415
415
  });
416
416
  }
417
417
 
418
- if (hasClientApp) {
418
+ if (hasMlmApp) {
419
419
  ipPrompts.push({
420
420
  type: 'number',
421
- name: 'clientAppPort',
422
- message: 'Client App port:',
421
+ name: 'mlmAppPort',
422
+ message: 'MLM App port:',
423
423
  default: 9005
424
424
  });
425
425
  }
@@ -439,7 +439,7 @@ export async function setDomain(options) {
439
439
  if (hasGuardianApp) guardianAppUrl = buildURL(ipConfig.ip, ipConfig.guardianAppPort);
440
440
  if (hasFacialWeb) facialWebUrl = buildURL(ipConfig.ip, ipConfig.facialWebPort);
441
441
  if (hasPosApp) posAppUrl = buildURL(ipConfig.ip, ipConfig.posAppPort);
442
- if (hasClientApp) clientAppUrl = buildURL(ipConfig.ip, ipConfig.clientAppPort);
442
+ if (hasMlmApp) mlmAppUrl = buildURL(ipConfig.ip, ipConfig.mlmAppPort);
443
443
  } else {
444
444
  // Manual URL input (domain configuration)
445
445
 
@@ -482,8 +482,8 @@ export async function setDomain(options) {
482
482
  if (hasGuardianApp) guardianAppUrl = `https://${subdomain}-guardian.ante.ph`;
483
483
  if (hasFacialWeb) facialWebUrl = `https://${subdomain}-fr.ante.ph`;
484
484
  if (hasPosApp) posAppUrl = `https://${subdomain}-pos.ante.ph`;
485
- if (hasClientApp) clientAppUrl = `https://${subdomain}-client.ante.ph`;
486
- if (hasBackendClient) backendClientUrl = `https://${subdomain}-api-client.ante.ph`;
485
+ if (hasMlmApp) mlmAppUrl = `https://${subdomain}-mlm.ante.ph`;
486
+ if (hasBackendMlm) backendMlmUrl = `https://${subdomain}-api-mlm.ante.ph`;
487
487
 
488
488
  // Display generated domains for confirmation
489
489
  console.log(chalk.cyan('\n📋 Generated Domain Configuration:\n'));
@@ -493,8 +493,8 @@ export async function setDomain(options) {
493
493
  if (hasGuardianApp) console.log(chalk.gray(` Guardian App: ${guardianAppUrl}`));
494
494
  if (hasFacialWeb) console.log(chalk.gray(` Facial Web: ${facialWebUrl}`));
495
495
  if (hasPosApp) console.log(chalk.gray(` POS App: ${posAppUrl}`));
496
- if (hasClientApp) console.log(chalk.gray(` Client App: ${clientAppUrl}`));
497
- if (hasBackendClient) console.log(chalk.gray(` Backend-Client: ${backendClientUrl}`));
496
+ if (hasMlmApp) console.log(chalk.gray(` MLM App: ${mlmAppUrl}`));
497
+ if (hasBackendMlm) console.log(chalk.gray(` Backend-MLM: ${backendMlmUrl}`));
498
498
  console.log('');
499
499
 
500
500
  const confirmDomains = await inquirer.prompt([
@@ -562,21 +562,21 @@ export async function setDomain(options) {
562
562
  });
563
563
  }
564
564
 
565
- if (hasClientApp) {
565
+ if (hasMlmApp) {
566
566
  domainPrompts.push({
567
567
  type: 'input',
568
- name: 'clientAppUrl',
569
- message: 'Client App URL:\n Examples: https://client.ante.ph or http://143.198.91.153:9005\n Enter URL',
568
+ name: 'mlmAppUrl',
569
+ message: 'MLM App URL:\n Examples: https://client.ante.ph or http://143.198.91.153:9005\n Enter URL',
570
570
  default: currentClientAppUrl || 'http://localhost:9005',
571
571
  validate: validateUrl
572
572
  });
573
573
  }
574
574
 
575
- if (hasBackendClient) {
575
+ if (hasBackendMlm) {
576
576
  domainPrompts.push({
577
577
  type: 'input',
578
- name: 'backendClientUrl',
579
- message: 'Backend-Client API URL:\n Examples: https://staging-api-client.ante.ph or http://143.198.91.153:4001\n Enter URL',
578
+ name: 'backendMlmUrl',
579
+ message: 'Backend-MLM API URL:\n Examples: https://staging-api-mlm.ante.ph or http://143.198.91.153:4001\n Enter URL',
580
580
  default: currentBackendClientUrl || 'http://localhost:4001',
581
581
  validate: validateUrl
582
582
  });
@@ -599,8 +599,8 @@ export async function setDomain(options) {
599
599
  if (hasGuardianApp) guardianAppUrl = sanitizeUrl(answers.guardianAppUrl);
600
600
  if (hasFacialWeb) facialWebUrl = sanitizeUrl(answers.facialWebUrl);
601
601
  if (hasPosApp) posAppUrl = sanitizeUrl(answers.posAppUrl);
602
- if (hasClientApp) clientAppUrl = sanitizeUrl(answers.clientAppUrl);
603
- if (hasBackendClient) backendClientUrl = sanitizeUrl(answers.backendClientUrl);
602
+ if (hasMlmApp) mlmAppUrl = sanitizeUrl(answers.mlmAppUrl);
603
+ if (hasBackendMlm) backendMlmUrl = sanitizeUrl(answers.backendMlmUrl);
604
604
  }
605
605
  }
606
606
  } else {
@@ -675,23 +675,23 @@ export async function setDomain(options) {
675
675
  }
676
676
  }
677
677
 
678
- if (hasClientApp) {
679
- clientAppUrl = options.client ? sanitizeUrl(options.client) : getEnvValue(envPath, 'CLIENT_APP_URL');
680
- if (clientAppUrl) {
681
- const validation = validateUrl(clientAppUrl);
678
+ if (hasMlmApp) {
679
+ mlmAppUrl = options.client ? sanitizeUrl(options.client) : getEnvValue(envPath, 'MLM_APP_URL');
680
+ if (mlmAppUrl) {
681
+ const validation = validateUrl(mlmAppUrl);
682
682
  if (validation !== true) {
683
- console.log(chalk.red(`Error: Invalid Client App URL - ${validation}`));
683
+ console.log(chalk.red(`Error: Invalid MLM App URL - ${validation}`));
684
684
  process.exit(1);
685
685
  }
686
686
  }
687
687
  }
688
688
 
689
- if (hasBackendClient) {
690
- backendClientUrl = options.backendClient ? sanitizeUrl(options.backendClient) : getEnvValue(envPath, 'CLIENT_API_URL');
691
- if (backendClientUrl) {
692
- const validation = validateUrl(backendClientUrl);
689
+ if (hasBackendMlm) {
690
+ backendMlmUrl = options.backendClient ? sanitizeUrl(options.backendClient) : getEnvValue(envPath, 'MLM_API_URL');
691
+ if (backendMlmUrl) {
692
+ const validation = validateUrl(backendMlmUrl);
693
693
  if (validation !== true) {
694
- console.log(chalk.red(`Error: Invalid Backend-Client API URL - ${validation}`));
694
+ console.log(chalk.red(`Error: Invalid Backend-MLM API URL - ${validation}`));
695
695
  process.exit(1);
696
696
  }
697
697
  }
@@ -705,8 +705,8 @@ export async function setDomain(options) {
705
705
  if (hasGuardianApp && guardianAppUrl) console.log(chalk.gray(` Guardian App: ${guardianAppUrl}`));
706
706
  if (hasFacialWeb && facialWebUrl) console.log(chalk.gray(` Facial Web: ${facialWebUrl}`));
707
707
  if (hasPosApp && posAppUrl) console.log(chalk.gray(` POS App: ${posAppUrl}`));
708
- if (hasClientApp && clientAppUrl) console.log(chalk.gray(` Client App: ${clientAppUrl}`));
709
- if (hasBackendClient && backendClientUrl) console.log(chalk.gray(` Backend-Client: ${backendClientUrl}`));
708
+ if (hasMlmApp && mlmAppUrl) console.log(chalk.gray(` MLM App: ${mlmAppUrl}`));
709
+ if (hasBackendMlm && backendMlmUrl) console.log(chalk.gray(` Backend-MLM: ${backendMlmUrl}`));
710
710
  console.log('');
711
711
  }
712
712
 
@@ -735,12 +735,12 @@ export async function setDomain(options) {
735
735
  envUpdates.POS_APP_URL = posAppUrl;
736
736
  }
737
737
 
738
- if (hasClientApp && clientAppUrl) {
739
- envUpdates.CLIENT_APP_URL = clientAppUrl;
738
+ if (hasMlmApp && mlmAppUrl) {
739
+ envUpdates.MLM_APP_URL = mlmAppUrl;
740
740
  }
741
741
 
742
- if (hasBackendClient && backendClientUrl) {
743
- envUpdates.CLIENT_API_URL = backendClientUrl;
742
+ if (hasBackendMlm && backendMlmUrl) {
743
+ envUpdates.MLM_API_URL = backendMlmUrl;
744
744
  }
745
745
 
746
746
  updateEnvFile(envPath, envUpdates);
@@ -791,14 +791,14 @@ export async function setDomain(options) {
791
791
  nginxConfig.posAppPort = 8084;
792
792
  }
793
793
 
794
- if (hasClientApp && clientAppUrl) {
795
- nginxConfig.clientAppDomain = clientAppUrl;
796
- nginxConfig.clientAppPort = 9005;
794
+ if (hasMlmApp && mlmAppUrl) {
795
+ nginxConfig.mlmAppDomain = mlmAppUrl;
796
+ nginxConfig.mlmAppPort = 9005;
797
797
  }
798
798
 
799
- if (hasBackendClient && backendClientUrl) {
800
- nginxConfig.backendClientDomain = backendClientUrl;
801
- nginxConfig.backendClientPort = 4001;
799
+ if (hasBackendMlm && backendMlmUrl) {
800
+ nginxConfig.backendMlmDomain = backendMlmUrl;
801
+ nginxConfig.backendMlmPort = 4001;
802
802
  }
803
803
 
804
804
  await configureNginx(nginxConfig);
@@ -856,10 +856,12 @@ export async function setDomain(options) {
856
856
 
857
857
  // Execute SSL setup if enabled
858
858
  if (enableSsl) {
859
+ // Use default email if not provided
859
860
  if (!sslEmail) {
860
- console.log(chalk.yellow('\n⚠ SSL setup skipped: Email address required'));
861
- console.log(chalk.gray(' Run "ante ssl enable --email your@email.com" to enable SSL later\n'));
862
- } else {
861
+ sslEmail = 'geeritsolutions@gmail.com';
862
+ console.log(chalk.gray(`Using default email for SSL: ${sslEmail}\n`));
863
+ }
864
+ {
863
865
  try {
864
866
  console.log(chalk.bold('\n🔒 Setting up SSL/HTTPS...\n'));
865
867
 
@@ -899,16 +901,16 @@ export async function setDomain(options) {
899
901
  domains.push(posAppDomain);
900
902
  }
901
903
  }
902
- if (hasClientApp && clientAppUrl && clientAppUrl.startsWith('https://')) {
903
- const clientAppDomain = extractDomain(clientAppUrl);
904
- if (clientAppDomain !== 'localhost' && !clientAppDomain.match(/^\d+\.\d+\.\d+\.\d+$/) && !domains.includes(clientAppDomain)) {
905
- domains.push(clientAppDomain);
904
+ if (hasMlmApp && mlmAppUrl && mlmAppUrl.startsWith('https://')) {
905
+ const mlmAppDomain = extractDomain(mlmAppUrl);
906
+ if (mlmAppDomain !== 'localhost' && !mlmAppDomain.match(/^\d+\.\d+\.\d+\.\d+$/) && !domains.includes(mlmAppDomain)) {
907
+ domains.push(mlmAppDomain);
906
908
  }
907
909
  }
908
- if (hasBackendClient && backendClientUrl && backendClientUrl.startsWith('https://')) {
909
- const backendClientDomain = extractDomain(backendClientUrl);
910
- if (backendClientDomain !== 'localhost' && !backendClientDomain.match(/^\d+\.\d+\.\d+\.\d+$/) && !domains.includes(backendClientDomain)) {
911
- domains.push(backendClientDomain);
910
+ if (hasBackendMlm && backendMlmUrl && backendMlmUrl.startsWith('https://')) {
911
+ const backendMlmDomain = extractDomain(backendMlmUrl);
912
+ if (backendMlmDomain !== 'localhost' && !backendMlmDomain.match(/^\d+\.\d+\.\d+\.\d+$/) && !domains.includes(backendMlmDomain)) {
913
+ domains.push(backendMlmDomain);
912
914
  }
913
915
  }
914
916
 
@@ -953,14 +955,14 @@ export async function setDomain(options) {
953
955
  sslNginxConfig.posAppPort = 8084;
954
956
  }
955
957
 
956
- if (hasClientApp && clientAppUrl) {
957
- sslNginxConfig.clientAppDomain = clientAppUrl;
958
- sslNginxConfig.clientAppPort = 9005;
958
+ if (hasMlmApp && mlmAppUrl) {
959
+ sslNginxConfig.mlmAppDomain = mlmAppUrl;
960
+ sslNginxConfig.mlmAppPort = 9005;
959
961
  }
960
962
 
961
- if (hasBackendClient && backendClientUrl) {
962
- sslNginxConfig.backendClientDomain = backendClientUrl;
963
- sslNginxConfig.backendClientPort = 4001;
963
+ if (hasBackendMlm && backendMlmUrl) {
964
+ sslNginxConfig.backendMlmDomain = backendMlmUrl;
965
+ sslNginxConfig.backendMlmPort = 4001;
964
966
  }
965
967
 
966
968
  await updateNginxForSSL(sslNginxConfig);
@@ -1101,8 +1103,8 @@ export async function setDomain(options) {
1101
1103
  if (hasFacialWeb && facialWebUrl) {
1102
1104
  console.log(chalk.cyan('Facial Web: '), chalk.white(facialWebUrl));
1103
1105
  }
1104
- if (hasClientApp && clientAppUrl) {
1105
- console.log(chalk.cyan('Client App: '), chalk.white(clientAppUrl));
1106
+ if (hasMlmApp && mlmAppUrl) {
1107
+ console.log(chalk.cyan('MLM App: '), chalk.white(mlmAppUrl));
1106
1108
  }
1107
1109
  console.log(chalk.cyan('API: '), chalk.white(apiUrl));
1108
1110
  console.log(chalk.cyan('WebSocket: '), chalk.white(apiUrl));
@@ -1118,8 +1120,8 @@ export async function setDomain(options) {
1118
1120
  if (hasFacialWeb && facialWebUrl) {
1119
1121
  console.log(chalk.white(` Facial Web: ${facialWebUrl}`));
1120
1122
  }
1121
- if (hasClientApp && clientAppUrl) {
1122
- console.log(chalk.white(` Client App: ${clientAppUrl}`));
1123
+ if (hasMlmApp && mlmAppUrl) {
1124
+ console.log(chalk.white(` MLM App: ${mlmAppUrl}`));
1123
1125
  }
1124
1126
  console.log();
1125
1127
 
@@ -24,11 +24,11 @@ function detectInstalledApps(composeFile) {
24
24
  hasGuardianApp: composeContent.includes('guardian-app:') || composeContent.includes('container_name: ante-guardian-app'),
25
25
  hasFacialWeb: composeContent.includes('facial-web:') || composeContent.includes('container_name: ante-facial-web'),
26
26
  hasPosApp: composeContent.includes('pos-app:') || composeContent.includes('container_name: ante-pos'),
27
- hasClientApp: composeContent.includes('client-app:') || composeContent.includes('container_name: ante-client'),
28
- hasBackendClient: composeContent.includes('backend-client:') || composeContent.includes('container_name: ante-backend-client')
27
+ hasMlmApp: composeContent.includes('mlm-app:') || composeContent.includes('container_name: ante-mlm'),
28
+ hasBackendMlm: composeContent.includes('backend-mlm:') || composeContent.includes('container_name: ante-backend-mlm')
29
29
  };
30
30
  } catch {
31
- return { hasGateApp: false, hasGuardianApp: false, hasFacialWeb: false, hasPosApp: false, hasClientApp: false, hasBackendClient: false };
31
+ return { hasGateApp: false, hasGuardianApp: false, hasFacialWeb: false, hasPosApp: false, hasMlmApp: false, hasBackendMlm: false };
32
32
  }
33
33
  }
34
34
 
@@ -44,7 +44,7 @@ function detectMissingServices(composeFile) {
44
44
  guardianApp: !installed.hasGuardianApp,
45
45
  facialWeb: !installed.hasFacialWeb,
46
46
  posApp: !installed.hasPosApp,
47
- clientApp: !installed.hasClientApp
47
+ mlmApp: !installed.hasMlmApp
48
48
  };
49
49
  }
50
50
 
@@ -81,18 +81,18 @@ function updateDockerCompose(composeFile, envFile, newServices) {
81
81
  const newCompose = generateDockerCompose({
82
82
  frontendPort: parseInt(envConfig.FRONTEND_PORT) || 8080,
83
83
  backendPort: parseInt(envConfig.BACKEND_PORT) || 3001,
84
- backendClientPort: parseInt(envConfig.BACKEND_CLIENT_PORT) || 4001,
84
+ backendClientPort: parseInt(envConfig.BACKEND_MLM_PORT) || 4001,
85
85
  gateAppPort: parseInt(envConfig.GATE_APP_PORT) || 8081,
86
86
  guardianAppPort: parseInt(envConfig.GUARDIAN_APP_PORT) || 8082,
87
87
  facialWebPort: parseInt(envConfig.FACIAL_WEB_PORT) || 8083,
88
88
  posAppPort: parseInt(envConfig.POS_APP_PORT) || 8084,
89
- clientAppPort: parseInt(envConfig.CLIENT_APP_PORT) || 9005,
89
+ mlmAppPort: parseInt(envConfig.MLM_APP_PORT) || 9005,
90
90
  installMain: true,
91
91
  installGate: currentInstalled.hasGateApp || newServices.gateApp,
92
92
  installGuardian: currentInstalled.hasGuardianApp || newServices.guardianApp,
93
93
  installFacial: currentInstalled.hasFacialWeb || newServices.facialWeb,
94
94
  installPos: currentInstalled.hasPosApp || newServices.posApp,
95
- installClient: currentInstalled.hasClientApp || newServices.clientApp,
95
+ installMlm: currentInstalled.hasMlmApp || newServices.mlmApp,
96
96
  companyId: parseInt(envConfig.COMPANY_ID) || 1
97
97
  });
98
98
 
@@ -208,8 +208,8 @@ COMPANY_ID=1
208
208
  }
209
209
  }
210
210
 
211
- // Add client-app configuration if needed
212
- if (newServices.clientApp && !envContent.includes('CLIENT_APP_PORT')) {
211
+ // Add mlm-app configuration if needed
212
+ if (newServices.mlmApp && !envContent.includes('MLM_APP_PORT')) {
213
213
  if (!envContent.includes('# FRONTEND APP CONFIGURATION')) {
214
214
  envContent += `\n# ------------------------------------------------------------------------------
215
215
  # FRONTEND APP CONFIGURATION
@@ -219,35 +219,35 @@ COMPANY_ID=1
219
219
  }
220
220
 
221
221
  // Replace commented line or add new
222
- if (envContent.includes('# CLIENT_APP_PORT=')) {
223
- envContent = envContent.replace(/# CLIENT_APP_PORT=\d+/, 'CLIENT_APP_PORT=9005');
222
+ if (envContent.includes('# MLM_APP_PORT=')) {
223
+ envContent = envContent.replace(/# MLM_APP_PORT=\d+/, 'MLM_APP_PORT=9005');
224
224
  } else {
225
- envContent += `CLIENT_APP_PORT=9005\n`;
225
+ envContent += `MLM_APP_PORT=9005\n`;
226
226
  }
227
227
 
228
- if (envContent.includes('# CLIENT_APP_URL=')) {
229
- envContent = envContent.replace(/# CLIENT_APP_URL=.*/, 'CLIENT_APP_URL=http://localhost:9005');
228
+ if (envContent.includes('# MLM_APP_URL=')) {
229
+ envContent = envContent.replace(/# MLM_APP_URL=.*/, 'MLM_APP_URL=http://localhost:9005');
230
230
  } else {
231
- envContent += `CLIENT_APP_URL=http://localhost:9005\n`;
231
+ envContent += `MLM_APP_URL=http://localhost:9005\n`;
232
232
  }
233
233
 
234
- // Add backend-client port (always installed with client-app)
235
- if (envContent.includes('# BACKEND_CLIENT_PORT=')) {
236
- envContent = envContent.replace(/# BACKEND_CLIENT_PORT=\d+/, 'BACKEND_CLIENT_PORT=4001');
237
- } else if (!envContent.includes('BACKEND_CLIENT_PORT=')) {
238
- envContent += `BACKEND_CLIENT_PORT=4001\n`;
234
+ // Add backend-mlm port (always installed with mlm-app)
235
+ if (envContent.includes('# BACKEND_MLM_PORT=')) {
236
+ envContent = envContent.replace(/# BACKEND_MLM_PORT=\d+/, 'BACKEND_MLM_PORT=4001');
237
+ } else if (!envContent.includes('BACKEND_MLM_PORT=')) {
238
+ envContent += `BACKEND_MLM_PORT=4001\n`;
239
239
  }
240
240
 
241
241
  // Add client API URL
242
- if (envContent.includes('# CLIENT_API_URL=')) {
243
- envContent = envContent.replace(/# CLIENT_API_URL=.*/, 'CLIENT_API_URL=http://localhost:4001');
244
- } else if (!envContent.includes('CLIENT_API_URL=')) {
245
- envContent += `CLIENT_API_URL=http://localhost:4001\n`;
242
+ if (envContent.includes('# MLM_API_URL=')) {
243
+ envContent = envContent.replace(/# MLM_API_URL=.*/, 'MLM_API_URL=http://localhost:4001');
244
+ } else if (!envContent.includes('MLM_API_URL=')) {
245
+ envContent += `MLM_API_URL=http://localhost:4001\n`;
246
246
  }
247
247
  }
248
248
 
249
249
  // Add COMPANY_ID if missing and any new service is being added
250
- if ((newServices.gateApp || newServices.guardianApp || newServices.facialWeb || newServices.posApp || newServices.clientApp) && !envContent.includes('COMPANY_ID=')) {
250
+ if ((newServices.gateApp || newServices.guardianApp || newServices.facialWeb || newServices.posApp || newServices.mlmApp) && !envContent.includes('COMPANY_ID=')) {
251
251
  envContent += `COMPANY_ID=1\n`;
252
252
  }
253
253
 
@@ -346,18 +346,18 @@ function refreshDockerCompose(composeFile, envFile) {
346
346
  const newCompose = generateDockerCompose({
347
347
  frontendPort: parseInt(envConfig.FRONTEND_PORT) || 8080,
348
348
  backendPort: parseInt(envConfig.BACKEND_PORT) || 3001,
349
- backendClientPort: parseInt(envConfig.BACKEND_CLIENT_PORT) || 4001,
349
+ backendClientPort: parseInt(envConfig.BACKEND_MLM_PORT) || 4001,
350
350
  gateAppPort: parseInt(envConfig.GATE_APP_PORT) || 8081,
351
351
  guardianAppPort: parseInt(envConfig.GUARDIAN_APP_PORT) || 8082,
352
352
  facialWebPort: parseInt(envConfig.FACIAL_WEB_PORT) || 8083,
353
353
  posAppPort: parseInt(envConfig.POS_APP_PORT) || 8084,
354
- clientAppPort: parseInt(envConfig.CLIENT_APP_PORT) || 9005,
354
+ mlmAppPort: parseInt(envConfig.MLM_APP_PORT) || 9005,
355
355
  installMain: true,
356
356
  installGate: currentInstalled.hasGateApp,
357
357
  installGuardian: currentInstalled.hasGuardianApp,
358
358
  installFacial: currentInstalled.hasFacialWeb,
359
359
  installPos: currentInstalled.hasPosApp,
360
- installClient: currentInstalled.hasClientApp,
360
+ installMlm: currentInstalled.hasMlmApp,
361
361
  companyId: parseInt(envConfig.COMPANY_ID) || 1
362
362
  });
363
363
 
@@ -453,10 +453,10 @@ export async function update(options) {
453
453
 
454
454
  // Detect missing services that could be installed
455
455
  const missingServices = detectMissingServices(composeFile);
456
- const hasNewServices = missingServices.gateApp || missingServices.guardianApp || missingServices.facialWeb || missingServices.posApp || missingServices.clientApp;
456
+ const hasNewServices = missingServices.gateApp || missingServices.guardianApp || missingServices.facialWeb || missingServices.posApp || missingServices.mlmApp;
457
457
 
458
458
  // Track which services to install (will be set to missingServices if any found)
459
- let servicesToInstall = { gateApp: false, guardianApp: false, facialWeb: false, posApp: false, clientApp: false };
459
+ let servicesToInstall = { gateApp: false, guardianApp: false, facialWeb: false, posApp: false, mlmApp: false };
460
460
 
461
461
  // Calculate total steps dynamically
462
462
  let totalSteps = 6; // Base steps: check services, pull, stop, start, backend health, migrations
@@ -550,7 +550,7 @@ export async function update(options) {
550
550
  if (missingServices.guardianApp) availableServices.push('Guardian App');
551
551
  if (missingServices.facialWeb) availableServices.push('Facial Web');
552
552
  if (missingServices.posApp) availableServices.push('POS App');
553
- if (missingServices.clientApp) availableServices.push('Client App');
553
+ if (missingServices.mlmApp) availableServices.push('MLM App');
554
554
 
555
555
  task.title = formatStepTitle(stepCheckServices, totalSteps, `Found new services: ${availableServices.join(', ')}`);
556
556
  ctx.missingServices = missingServices;
@@ -565,7 +565,7 @@ export async function update(options) {
565
565
  if (servicesToInstall.guardianApp) servicesAdded.push('Guardian App');
566
566
  if (servicesToInstall.facialWeb) servicesAdded.push('Facial Web');
567
567
  if (servicesToInstall.posApp) servicesAdded.push('POS App');
568
- if (servicesToInstall.clientApp) servicesAdded.push('Client App');
568
+ if (servicesToInstall.mlmApp) servicesAdded.push('MLM App');
569
569
 
570
570
  // Update docker-compose.yml with new services
571
571
  updateDockerCompose(composeFile, envFile, servicesToInstall);
@@ -7,17 +7,17 @@ export function generateDockerCompose(options = {}) {
7
7
  const {
8
8
  frontendPort = 8080,
9
9
  backendPort = 3001,
10
- backendClientPort = 4001,
10
+ backendMlmPort = 4001,
11
11
  gateAppPort = 8081,
12
12
  guardianAppPort = 8082,
13
13
  facialWebPort = 8083,
14
14
  posAppPort = 8084,
15
- clientAppPort = 9005,
15
+ mlmAppPort = 9005,
16
16
  installGate = false,
17
17
  installGuardian = false,
18
18
  installFacial = false,
19
19
  installPos = false,
20
- installClient = false,
20
+ installMlm = false,
21
21
  companyId = 1
22
22
  } = options;
23
23
 
@@ -315,18 +315,18 @@ ${installGate ? `
315
315
  options:
316
316
  max-size: "10m"
317
317
  max-file: "3"
318
- ` : ''}${installClient ? `
319
- # ANTE Backend Client (Client Portal API)
320
- backend-client:
321
- image: ghcr.io/gtplusnet/ante-self-hosted-backend-client:latest
322
- container_name: ante-backend-client
318
+ ` : ''}${installMlm ? `
319
+ # ANTE Backend MLM (MLM Portal API)
320
+ backend-mlm:
321
+ image: ghcr.io/gtplusnet/ante-self-hosted-backend-mlm:latest
322
+ container_name: ante-backend-mlm
323
323
  restart: unless-stopped
324
324
  depends_on:
325
325
  backend:
326
326
  condition: service_healthy
327
327
  environment:
328
328
  NODE_ENV: production
329
- CLIENT_BACKEND_PORT: 4001
329
+ MLM_BACKEND_PORT: 4001
330
330
  DATABASE_URL: postgresql://ante:\${DB_PASSWORD}@postgres:5432/ante_db?schema=public&connection_limit=10
331
331
  DIRECT_URL: postgresql://ante:\${DB_PASSWORD}@postgres:5432/ante_db?schema=public
332
332
  REDIS_HOST: redis
@@ -338,7 +338,7 @@ ${installGate ? `
338
338
  ENCRYPTION_KEY: \${ENCRYPTION_KEY}
339
339
  TZ: \${TZ:-Asia/Manila}
340
340
  ports:
341
- - "${backendClientPort}:4001"
341
+ - "${backendMlmPort}:4001"
342
342
  networks:
343
343
  - ante-network
344
344
  healthcheck:
@@ -353,21 +353,21 @@ ${installGate ? `
353
353
  max-size: "10m"
354
354
  max-file: "3"
355
355
 
356
- # ANTE Client App (Frontend)
357
- client-app:
358
- image: ghcr.io/gtplusnet/ante-self-hosted-ante-client:latest
359
- container_name: ante-client
356
+ # ANTE MLM App (Frontend)
357
+ mlm-app:
358
+ image: ghcr.io/gtplusnet/ante-self-hosted-ante-mlm:latest
359
+ container_name: ante-mlm
360
360
  restart: unless-stopped
361
361
  depends_on:
362
- backend-client:
362
+ backend-mlm:
363
363
  condition: service_healthy
364
364
  environment:
365
- - API_URL=\${CLIENT_API_URL:-http://localhost:${backendClientPort}}
366
- - VITE_API_URL=\${CLIENT_API_URL:-http://localhost:${backendClientPort}}
367
- - VITE_APP_NAME=ANTE Client Portal
365
+ - API_URL=\${MLM_API_URL:-http://localhost:${backendMlmPort}}
366
+ - VITE_API_URL=\${MLM_API_URL:-http://localhost:${backendMlmPort}}
367
+ - VITE_APP_NAME=ANTE MLM Portal
368
368
  - VITE_APP_VERSION=\${VERSION:-1.0.0}
369
369
  ports:
370
- - "${clientAppPort}:9005"
370
+ - "${mlmAppPort}:9005"
371
371
  networks:
372
372
  - ante-network
373
373
  healthcheck:
@@ -11,24 +11,24 @@ export function generateEnv(credentials, options = {}) {
11
11
  socketUrl = 'http://localhost:3001', // WebSocket uses same port as backend
12
12
  frontendPort = 8080,
13
13
  backendPort = 3001,
14
- backendClientPort = 4001,
14
+ backendMlmPort = 4001,
15
15
  gateAppPort = 8081,
16
16
  guardianAppPort = 8082,
17
17
  facialWebPort = 8083,
18
18
  posAppPort = 8084,
19
- clientAppPort = 9005,
19
+ mlmAppPort = 9005,
20
20
  gateAppUrl = 'http://localhost:8081',
21
21
  guardianAppUrl = 'http://localhost:8082',
22
22
  facialWebUrl = 'http://localhost:8083',
23
23
  posAppUrl = 'http://localhost:8084',
24
- clientAppUrl = 'http://localhost:9005',
25
- clientApiUrl = 'http://localhost:4001',
24
+ mlmAppUrl = 'http://localhost:9005',
25
+ mlmApiUrl = 'http://localhost:4001',
26
26
  companyId = 1,
27
27
  installGate = false,
28
28
  installGuardian = false,
29
29
  installFacial = false,
30
30
  installPos = false,
31
- installClient = false,
31
+ installMlm = false,
32
32
  smtpHost = '',
33
33
  smtpPort = 587,
34
34
  smtpUsername = '',
@@ -74,15 +74,15 @@ SOCKET_URL=${socketUrl}
74
74
  # ------------------------------------------------------------------------------
75
75
  FRONTEND_PORT=${frontendPort}
76
76
  BACKEND_PORT=${backendPort}
77
- ${installClient ? `BACKEND_CLIENT_PORT=${backendClientPort}` : '# BACKEND_CLIENT_PORT=4001'}
77
+ ${installMlm ? `BACKEND_MLM_PORT=${backendMlmPort}` : '# BACKEND_MLM_PORT=4001'}
78
78
  ${installGate ? `GATE_APP_PORT=${gateAppPort}` : '# GATE_APP_PORT=8081'}
79
79
  ${installGuardian ? `GUARDIAN_APP_PORT=${guardianAppPort}` : '# GUARDIAN_APP_PORT=8082'}
80
80
  ${installFacial ? `FACIAL_WEB_PORT=${facialWebPort}` : '# FACIAL_WEB_PORT=8083'}
81
81
  ${installPos ? `POS_APP_PORT=${posAppPort}` : '# POS_APP_PORT=8084'}
82
- ${installClient ? `CLIENT_APP_PORT=${clientAppPort}` : '# CLIENT_APP_PORT=9005'}
82
+ ${installMlm ? `MLM_APP_PORT=${mlmAppPort}` : '# MLM_APP_PORT=9005'}
83
83
  # Note: WebSocket runs on the same port as backend (BACKEND_PORT)
84
84
 
85
- ${(installGate || installGuardian || installFacial || installPos || installClient) ? `# ------------------------------------------------------------------------------
85
+ ${(installGate || installGuardian || installFacial || installPos || installMlm) ? `# ------------------------------------------------------------------------------
86
86
  # FRONTEND APP CONFIGURATION
87
87
  # ------------------------------------------------------------------------------
88
88
  COMPANY_ID=${companyId}
@@ -90,8 +90,8 @@ ${installGate ? `GATE_APP_URL=${gateAppUrl}` : '# GATE_APP_URL=http://localhost:
90
90
  ${installGuardian ? `GUARDIAN_APP_URL=${guardianAppUrl}` : '# GUARDIAN_APP_URL=http://localhost:8082'}
91
91
  ${installFacial ? `FACIAL_WEB_URL=${facialWebUrl}` : '# FACIAL_WEB_URL=http://localhost:8083'}
92
92
  ${installPos ? `POS_APP_URL=${posAppUrl}` : '# POS_APP_URL=http://localhost:8084'}
93
- ${installClient ? `CLIENT_APP_URL=${clientAppUrl}` : '# CLIENT_APP_URL=http://localhost:9005'}
94
- ${installClient ? `CLIENT_API_URL=${clientApiUrl}` : '# CLIENT_API_URL=http://localhost:4001'}
93
+ ${installMlm ? `MLM_APP_URL=${mlmAppUrl}` : '# MLM_APP_URL=http://localhost:9005'}
94
+ ${installMlm ? `MLM_API_URL=${mlmApiUrl}` : '# MLM_API_URL=http://localhost:4001'}
95
95
 
96
96
  ` : ''}# ------------------------------------------------------------------------------
97
97
  # EMAIL CONFIGURATION
@@ -52,16 +52,16 @@ export async function installNginx(spinner) {
52
52
  * @param {string} [config.guardianAppDomain] - Guardian app domain (optional)
53
53
  * @param {string} [config.facialAppDomain] - Facial web app domain (optional)
54
54
  * @param {string} [config.posAppDomain] - POS app domain (optional)
55
- * @param {string} [config.clientAppDomain] - Client app domain (optional)
56
- * @param {string} [config.backendClientDomain] - Backend client API domain (optional)
55
+ * @param {string} [config.mlmAppDomain] - MLM app domain (optional)
56
+ * @param {string} [config.backendMlmDomain] - Backend MLM API domain (optional)
57
57
  * @param {number} config.frontendPort - Frontend Docker port (default: 8080)
58
58
  * @param {number} config.apiPort - API Docker port (default: 3001)
59
59
  * @param {number} [config.gateAppPort] - Gate app Docker port (default: 8081)
60
60
  * @param {number} [config.guardianAppPort] - Guardian app Docker port (default: 8082)
61
61
  * @param {number} [config.facialWebPort] - Facial web app Docker port (default: 8083)
62
62
  * @param {number} [config.posAppPort] - POS app Docker port (default: 8084)
63
- * @param {number} [config.clientAppPort] - Client app Docker port (default: 9005)
64
- * @param {number} [config.backendClientPort] - Backend client API Docker port (default: 4001)
63
+ * @param {number} [config.mlmAppPort] - MLM app Docker port (default: 9005)
64
+ * @param {number} [config.backendMlmPort] - Backend MLM API Docker port (default: 4001)
65
65
  * @param {boolean} config.ssl - Enable SSL configuration with Let's Encrypt (default: false)
66
66
  * @param {boolean} config.cloudflareSsl - Enable Cloudflare SSL mode with self-signed certs (default: false)
67
67
  * @returns {string} NGINX configuration content
@@ -74,16 +74,16 @@ export function generateNginxConfig(config) {
74
74
  guardianAppDomain,
75
75
  facialAppDomain,
76
76
  posAppDomain,
77
- clientAppDomain,
78
- backendClientDomain,
77
+ mlmAppDomain,
78
+ backendMlmDomain,
79
79
  frontendPort = 8080,
80
80
  apiPort = 3001,
81
81
  gateAppPort = 8081,
82
82
  guardianAppPort = 8082,
83
83
  facialWebPort = 8083,
84
84
  posAppPort = 8084,
85
- clientAppPort = 9005,
86
- backendClientPort = 4001,
85
+ mlmAppPort = 9005,
86
+ backendMlmPort = 4001,
87
87
  ssl = false,
88
88
  cloudflareSsl = false
89
89
  } = config;
@@ -95,8 +95,8 @@ export function generateNginxConfig(config) {
95
95
  const guardianAppHost = guardianAppDomain ? guardianAppDomain.replace(/^https?:\/\//, '').replace(/:\d+$/, '') : null;
96
96
  const facialAppHost = facialAppDomain ? facialAppDomain.replace(/^https?:\/\//, '').replace(/:\d+$/, '') : null;
97
97
  const posAppHost = posAppDomain ? posAppDomain.replace(/^https?:\/\//, '').replace(/:\d+$/, '') : null;
98
- const clientAppHost = clientAppDomain ? clientAppDomain.replace(/^https?:\/\//, '').replace(/:\d+$/, '') : null;
99
- const backendClientHost = backendClientDomain ? backendClientDomain.replace(/^https?:\/\//, '').replace(/:\d+$/, '') : null;
98
+ const mlmAppHost = mlmAppDomain ? mlmAppDomain.replace(/^https?:\/\//, '').replace(/:\d+$/, '') : null;
99
+ const backendMlmHost = backendMlmDomain ? backendMlmDomain.replace(/^https?:\/\//, '').replace(/:\d+$/, '') : null;
100
100
 
101
101
  // Cloudflare SSL mode - uses self-signed certs for Cloudflare "Full" mode
102
102
  if (cloudflareSsl) {
@@ -107,16 +107,16 @@ export function generateNginxConfig(config) {
107
107
  guardianAppHost,
108
108
  facialAppHost,
109
109
  posAppHost,
110
- clientAppHost,
111
- backendClientHost,
110
+ mlmAppHost,
111
+ backendMlmHost,
112
112
  frontendPort,
113
113
  apiPort,
114
114
  gateAppPort,
115
115
  guardianAppPort,
116
116
  facialWebPort,
117
117
  posAppPort,
118
- clientAppPort,
119
- backendClientPort
118
+ mlmAppPort,
119
+ backendMlmPort
120
120
  });
121
121
  }
122
122
 
@@ -129,16 +129,16 @@ export function generateNginxConfig(config) {
129
129
  guardianAppHost,
130
130
  facialAppHost,
131
131
  posAppHost,
132
- clientAppHost,
133
- backendClientHost,
132
+ mlmAppHost,
133
+ backendMlmHost,
134
134
  frontendPort,
135
135
  apiPort,
136
136
  gateAppPort,
137
137
  guardianAppPort,
138
138
  facialWebPort,
139
139
  posAppPort,
140
- clientAppPort,
141
- backendClientPort
140
+ mlmAppPort,
141
+ backendMlmPort
142
142
  });
143
143
  }
144
144
 
@@ -331,12 +331,12 @@ server {
331
331
  proxy_read_timeout 60s;
332
332
  }
333
333
  }
334
- ` : ''}${clientAppHost ? `
335
- # ANTE Client App Configuration
334
+ ` : ''}${mlmAppHost ? `
335
+ # ANTE MLM App Configuration
336
336
  server {
337
337
  listen 80;
338
338
  listen [::]:80;
339
- server_name ${clientAppHost};
339
+ server_name ${mlmAppHost};
340
340
 
341
341
  # Increase buffer sizes for large headers
342
342
  client_header_buffer_size 16k;
@@ -346,7 +346,7 @@ server {
346
346
  client_max_body_size 100M;
347
347
 
348
348
  location / {
349
- proxy_pass http://localhost:${clientAppPort};
349
+ proxy_pass http://localhost:${mlmAppPort};
350
350
  proxy_http_version 1.1;
351
351
  proxy_set_header Upgrade $http_upgrade;
352
352
  proxy_set_header Connection 'upgrade';
@@ -362,12 +362,12 @@ server {
362
362
  proxy_read_timeout 60s;
363
363
  }
364
364
  }
365
- ` : ''}${backendClientHost ? `
366
- # ANTE Backend Client API Configuration
365
+ ` : ''}${backendMlmHost ? `
366
+ # ANTE Backend MLM API Configuration
367
367
  server {
368
368
  listen 80;
369
369
  listen [::]:80;
370
- server_name ${backendClientHost};
370
+ server_name ${backendMlmHost};
371
371
 
372
372
  # Increase buffer sizes for large headers
373
373
  client_header_buffer_size 16k;
@@ -377,7 +377,7 @@ server {
377
377
  client_max_body_size 100M;
378
378
 
379
379
  location / {
380
- proxy_pass http://localhost:${backendClientPort};
380
+ proxy_pass http://localhost:${backendMlmPort};
381
381
  proxy_http_version 1.1;
382
382
  proxy_set_header Upgrade $http_upgrade;
383
383
  proxy_set_header Connection 'upgrade';
@@ -411,16 +411,16 @@ function generateCloudflareNginxConfig(config) {
411
411
  guardianAppHost,
412
412
  facialAppHost,
413
413
  posAppHost,
414
- clientAppHost,
415
- backendClientHost,
414
+ mlmAppHost,
415
+ backendMlmHost,
416
416
  frontendPort,
417
417
  apiPort,
418
418
  gateAppPort = 8081,
419
419
  guardianAppPort = 8082,
420
420
  facialWebPort = 8083,
421
421
  posAppPort = 8084,
422
- clientAppPort = 9005,
423
- backendClientPort = 4001
422
+ mlmAppPort = 9005,
423
+ backendMlmPort = 4001
424
424
  } = config;
425
425
 
426
426
  // SSL certificate paths for Cloudflare self-signed certs
@@ -652,14 +652,14 @@ server {
652
652
  proxy_read_timeout 60s;
653
653
  }
654
654
  }
655
- ` : ''}${clientAppHost ? `
656
- # ANTE Client App Configuration (Cloudflare SSL)
655
+ ` : ''}${mlmAppHost ? `
656
+ # ANTE MLM App Configuration (Cloudflare SSL)
657
657
  server {
658
658
  listen 80;
659
659
  listen 443 ssl;
660
660
  listen [::]:80;
661
661
  listen [::]:443 ssl;
662
- server_name ${clientAppHost};
662
+ server_name ${mlmAppHost};
663
663
 
664
664
  # SSL Certificate (self-signed for Cloudflare Full mode)
665
665
  ssl_certificate ${sslCert};
@@ -673,7 +673,7 @@ server {
673
673
  client_max_body_size 100M;
674
674
 
675
675
  location / {
676
- proxy_pass http://localhost:${clientAppPort};
676
+ proxy_pass http://localhost:${mlmAppPort};
677
677
  proxy_http_version 1.1;
678
678
  proxy_set_header Upgrade $http_upgrade;
679
679
  proxy_set_header Connection 'upgrade';
@@ -689,14 +689,14 @@ server {
689
689
  proxy_read_timeout 60s;
690
690
  }
691
691
  }
692
- ` : ''}${backendClientHost ? `
693
- # ANTE Backend Client API Configuration (Cloudflare SSL)
692
+ ` : ''}${backendMlmHost ? `
693
+ # ANTE Backend MLM API Configuration (Cloudflare SSL)
694
694
  server {
695
695
  listen 80;
696
696
  listen 443 ssl;
697
697
  listen [::]:80;
698
698
  listen [::]:443 ssl;
699
- server_name ${backendClientHost};
699
+ server_name ${backendMlmHost};
700
700
 
701
701
  # SSL Certificate (self-signed for Cloudflare Full mode)
702
702
  ssl_certificate ${sslCert};
@@ -710,7 +710,7 @@ server {
710
710
  client_max_body_size 100M;
711
711
 
712
712
  location / {
713
- proxy_pass http://localhost:${backendClientPort};
713
+ proxy_pass http://localhost:${backendMlmPort};
714
714
  proxy_http_version 1.1;
715
715
  proxy_set_header Upgrade $http_upgrade;
716
716
  proxy_set_header Connection 'upgrade';
@@ -772,16 +772,16 @@ export async function generateCloudflareCert() {
772
772
  * @param {string} [config.guardianAppHost] - Guardian app hostname (optional)
773
773
  * @param {string} [config.facialAppHost] - Facial web app hostname (optional)
774
774
  * @param {string} [config.posAppHost] - POS app hostname (optional)
775
- * @param {string} [config.clientAppHost] - Client app hostname (optional)
776
- * @param {string} [config.backendClientHost] - Backend client API hostname (optional)
775
+ * @param {string} [config.mlmAppHost] - MLM app hostname (optional)
776
+ * @param {string} [config.backendMlmHost] - Backend MLM API hostname (optional)
777
777
  * @param {number} config.frontendPort - Frontend port
778
778
  * @param {number} config.apiPort - API port
779
779
  * @param {number} [config.gateAppPort] - Gate app port (default: 8081)
780
780
  * @param {number} [config.guardianAppPort] - Guardian app port (default: 8082)
781
781
  * @param {number} [config.facialWebPort] - Facial web app port (default: 8083)
782
782
  * @param {number} [config.posAppPort] - POS app port (default: 8084)
783
- * @param {number} [config.clientAppPort] - Client app port (default: 9005)
784
- * @param {number} [config.backendClientPort] - Backend client API port (default: 4001)
783
+ * @param {number} [config.mlmAppPort] - MLM app port (default: 9005)
784
+ * @param {number} [config.backendMlmPort] - Backend MLM API port (default: 4001)
785
785
  * @returns {string} NGINX configuration with SSL
786
786
  */
787
787
  function generateSslNginxConfig(config) {
@@ -792,16 +792,16 @@ function generateSslNginxConfig(config) {
792
792
  guardianAppHost,
793
793
  facialAppHost,
794
794
  posAppHost,
795
- clientAppHost,
796
- backendClientHost,
795
+ mlmAppHost,
796
+ backendMlmHost,
797
797
  frontendPort,
798
798
  apiPort,
799
799
  gateAppPort = 8081,
800
800
  guardianAppPort = 8082,
801
801
  facialWebPort = 8083,
802
802
  posAppPort = 8084,
803
- clientAppPort = 9005,
804
- backendClientPort = 4001
803
+ mlmAppPort = 9005,
804
+ backendMlmPort = 4001
805
805
  } = config;
806
806
 
807
807
  return `# ANTE Frontend Configuration (HTTPS)
@@ -1159,17 +1159,17 @@ server {
1159
1159
  server_name ${posAppHost};
1160
1160
  return 301 https://$server_name$request_uri;
1161
1161
  }
1162
- ` : ''}${clientAppHost ? `
1163
- # ANTE Client App Configuration (HTTPS)
1162
+ ` : ''}${mlmAppHost ? `
1163
+ # ANTE MLM App Configuration (HTTPS)
1164
1164
  server {
1165
1165
  listen 443 ssl;
1166
1166
  listen [::]:443 ssl;
1167
1167
  http2 on;
1168
- server_name ${clientAppHost};
1168
+ server_name ${mlmAppHost};
1169
1169
 
1170
1170
  # SSL Certificate paths
1171
- ssl_certificate /etc/letsencrypt/live/${clientAppHost}/fullchain.pem;
1172
- ssl_certificate_key /etc/letsencrypt/live/${clientAppHost}/privkey.pem;
1171
+ ssl_certificate /etc/letsencrypt/live/${mlmAppHost}/fullchain.pem;
1172
+ ssl_certificate_key /etc/letsencrypt/live/${mlmAppHost}/privkey.pem;
1173
1173
 
1174
1174
  # SSL Configuration
1175
1175
  ssl_protocols TLSv1.2 TLSv1.3;
@@ -1192,7 +1192,7 @@ server {
1192
1192
  client_max_body_size 100M;
1193
1193
 
1194
1194
  location / {
1195
- proxy_pass http://localhost:${clientAppPort};
1195
+ proxy_pass http://localhost:${mlmAppPort};
1196
1196
  proxy_http_version 1.1;
1197
1197
  proxy_set_header Upgrade $http_upgrade;
1198
1198
  proxy_set_header Connection 'upgrade';
@@ -1209,24 +1209,24 @@ server {
1209
1209
  }
1210
1210
  }
1211
1211
 
1212
- # HTTP to HTTPS redirect for ${clientAppHost}
1212
+ # HTTP to HTTPS redirect for ${mlmAppHost}
1213
1213
  server {
1214
1214
  listen 80;
1215
1215
  listen [::]:80;
1216
- server_name ${clientAppHost};
1216
+ server_name ${mlmAppHost};
1217
1217
  return 301 https://$server_name$request_uri;
1218
1218
  }
1219
- ` : ''}${backendClientHost ? `
1220
- # ANTE Backend Client API Configuration (HTTPS)
1219
+ ` : ''}${backendMlmHost ? `
1220
+ # ANTE Backend MLM API Configuration (HTTPS)
1221
1221
  server {
1222
1222
  listen 443 ssl;
1223
1223
  listen [::]:443 ssl;
1224
1224
  http2 on;
1225
- server_name ${backendClientHost};
1225
+ server_name ${backendMlmHost};
1226
1226
 
1227
1227
  # SSL Certificate paths
1228
- ssl_certificate /etc/letsencrypt/live/${backendClientHost}/fullchain.pem;
1229
- ssl_certificate_key /etc/letsencrypt/live/${backendClientHost}/privkey.pem;
1228
+ ssl_certificate /etc/letsencrypt/live/${backendMlmHost}/fullchain.pem;
1229
+ ssl_certificate_key /etc/letsencrypt/live/${backendMlmHost}/privkey.pem;
1230
1230
 
1231
1231
  # SSL Configuration
1232
1232
  ssl_protocols TLSv1.2 TLSv1.3;
@@ -1249,7 +1249,7 @@ server {
1249
1249
  client_max_body_size 100M;
1250
1250
 
1251
1251
  location / {
1252
- proxy_pass http://localhost:${backendClientPort};
1252
+ proxy_pass http://localhost:${backendMlmPort};
1253
1253
  proxy_http_version 1.1;
1254
1254
  proxy_set_header Upgrade $http_upgrade;
1255
1255
  proxy_set_header Connection 'upgrade';
@@ -1266,11 +1266,11 @@ server {
1266
1266
  }
1267
1267
  }
1268
1268
 
1269
- # HTTP to HTTPS redirect for ${backendClientHost}
1269
+ # HTTP to HTTPS redirect for ${backendMlmHost}
1270
1270
  server {
1271
1271
  listen 80;
1272
1272
  listen [::]:80;
1273
- server_name ${backendClientHost};
1273
+ server_name ${backendMlmHost};
1274
1274
  return 301 https://$server_name$request_uri;
1275
1275
  }
1276
1276
  ` : ''}`;
@@ -1367,8 +1367,8 @@ export async function configureNginx(config) {
1367
1367
  if (config.posAppDomain) {
1368
1368
  console.log(chalk.gray(` POS App: ${config.posAppDomain} → localhost:${config.posAppPort || 8084}`));
1369
1369
  }
1370
- if (config.clientAppDomain) {
1371
- console.log(chalk.gray(` Client App: ${config.clientAppDomain} → localhost:${config.clientAppPort || 9005}`));
1370
+ if (config.mlmAppDomain) {
1371
+ console.log(chalk.gray(` Client App: ${config.mlmAppDomain} → localhost:${config.mlmAppPort || 9005}`));
1372
1372
  }
1373
1373
  console.log(chalk.gray(` API: ${config.apiDomain} → localhost:${config.apiPort || 3001}`));
1374
1374
 
package/src/utils/ssl.js CHANGED
@@ -147,13 +147,15 @@ export async function updateNginxForSSL(config) {
147
147
  facialAppDomain,
148
148
  posAppDomain,
149
149
  clientAppDomain,
150
+ backendClientDomain,
150
151
  frontendPort = 8080,
151
152
  apiPort = 3001,
152
153
  gateAppPort = 8081,
153
154
  guardianAppPort = 8082,
154
155
  facialWebPort = 8083,
155
156
  posAppPort = 8084,
156
- clientAppPort = 9005
157
+ clientAppPort = 9005,
158
+ backendClientPort = 4001
157
159
  } = config;
158
160
  const spinner = ora('Updating NGINX configuration for HTTPS...').start();
159
161
 
@@ -181,6 +183,7 @@ export async function updateNginxForSSL(config) {
181
183
  facialAppDomain,
182
184
  posAppDomain,
183
185
  clientAppDomain,
186
+ backendClientDomain,
184
187
  frontendPort,
185
188
  apiPort,
186
189
  gateAppPort,
@@ -188,6 +191,7 @@ export async function updateNginxForSSL(config) {
188
191
  facialWebPort,
189
192
  posAppPort,
190
193
  clientAppPort,
194
+ backendClientPort,
191
195
  ssl: true
192
196
  });
193
197