4 * @description Debug endpoints for troubleshooting MeshCentral integration and tenant configuration.
5 * Provides comprehensive diagnostic information about tenants, mesh groups, devices, and backend agents.
7 * @requires middleware/auth
8 * @requires services/db
9 * @requires services/meshcentral-db
10 * @author RMM-PSA Development Team
11 * @copyright 2026 RMM-PSA Platform
12 * @license Proprietary
16 * @apiDefine Debug Debugging
17 * Diagnostic endpoints for troubleshooting integrations
20const express = require('express');
21const router = express.Router();
22const authenticateToken = require('../middleware/auth');
23const { meshPool } = require('../services/meshcentral-db');
26 * @api {get} /api/debug/meshcentral MeshCentral configuration debug
27 * @apiName GetMeshCentralDebug
29 * @apiDescription Comprehensive diagnostic endpoint for troubleshooting MeshCentral integration.
30 * Returns tenant-mesh group mappings, all mesh groups, all devices, backend agent mappings,
31 * and connectivity status. Useful for debugging device sync issues and tenant isolation problems.
32 * @apiSuccess {string} timestamp Request timestamp (ISO 8601)
33 * @apiSuccess {object} user Request user context
34 * @apiSuccess {number} user.id User ID
35 * @apiSuccess {number} user.tenantId Tenant ID
36 * @apiSuccess {object} currentTenant Current tenant details
37 * @apiSuccess {number} currentTenant.tenant_id Tenant ID
38 * @apiSuccess {string} currentTenant.name Tenant name
39 * @apiSuccess {string} currentTenant.meshcentral_group_id Assigned mesh group ID
40 * @apiSuccess {object[]} allTenants All tenants with mesh group assignments
41 * @apiSuccess {number} allTenants.tenant_id Tenant ID
42 * @apiSuccess {string} allTenants.name Tenant name
43 * @apiSuccess {string} allTenants.meshcentral_group_id Mesh group ID (if assigned)
44 * @apiSuccess {boolean} allTenants.hasMeshGroup Whether tenant has mesh group
45 * @apiSuccess {Object[]} meshGroups All mesh groups from MeshCentral
46 * @apiSuccess {string} meshGroups.mesh_id Mesh group ID from MeshCentral
47 * @apiSuccess {string} meshGroups.mesh_name Mesh group name
48 * @apiSuccess {string} meshGroups.description Mesh group description
49 * @apiSuccess {Object[]} allDevices All devices from MeshCentral
50 * @apiSuccess {string} allDevices.node_id MeshCentral node ID
51 * @apiSuccess {string} allDevices.hostname Device hostname
52 * @apiSuccess {string} allDevices.mesh_id Mesh group ID
53 * @apiSuccess {String} allDevices.os Operating system description
54 * @apiSuccess {Number} allDevices.conn_status Connection status bitmask
55 * @apiSuccess {Boolean} allDevices.online Online status (derived from conn_status)
56 * @apiSuccess {Object[]} currentTenantDevices Devices for current tenant's mesh group
57 * @apiSuccess {Object[]} backendAgents Recent backend RMM agents (limit 20)
58 * @apiSuccess {Number} backendAgents.agent_id Backend agent ID
59 * @apiSuccess {String} backendAgents.agent_uuid Agent UUID
60 * @apiSuccess {String} backendAgents.hostname Agent hostname
61 * @apiSuccess {String} backendAgents.meshcentral_nodeid Linked MeshCentral node ID
62 * @apiSuccess {Number} backendAgents.tenant_id Tenant ID
63 * @apiSuccess {String} backendAgents.status Agent status
64 * @apiSuccess {Object} summary Debug summary statistics
65 * @apiSuccess {Number} summary.totalTenants Total tenant count
66 * @apiSuccess {Number} summary.tenantsWithMeshGroup Tenants with mesh groups
67 * @apiSuccess {Number} summary.totalMeshGroups Total mesh groups in MeshCentral
68 * @apiSuccess {Number} summary.totalDevicesInMeshCentral Total devices in MeshCentral
69 * @apiSuccess {Number} summary.devicesForCurrentTenant Devices for current tenant
70 * @apiSuccess {Number} summary.totalBackendAgents Backend agents in database
72 * @apiError {String} error Error message
73 * @apiError {String} stack Error stack trace
75 * @apiExample {curl} Example:
76 * curl -X GET http://localhost:3000/api/debug/meshcentral \\\
77 * -H "Authorization: Bearer YOUR_TOKEN"
79 * @apiSuccessExample {json} Success-Response:
82 * "timestamp": "2026-03-12T10:45:00.000Z",
89 * "name": "Acme Corp",
90 * "meshcentral_group_id": "mesh//abc123xyz"
96 * "meshcentral_group_id": "mesh//msp001",
97 * "hasMeshGroup": true
102 * "mesh_id": "mesh//abc123xyz",
103 * "mesh_name": "Acme Corp Devices",
104 * "description": "All devices for Acme"
109 * "node_id": "node//server01",
110 * "hostname": "SERVER01",
111 * "mesh_id": "mesh//abc123xyz",
112 * "os": "Windows Server 2022",
118 * "totalTenants": 15,
119 * "tenantsWithMeshGroup": 12,
120 * "totalMeshGroups": 12,
121 * "totalDevicesInMeshCentral": 145,
122 * "devicesForCurrentTenant": 22,
123 * "totalBackendAgents": 20
127router.get('/meshcentral', authenticateToken, async (req, res) => {
128 const pool = require('../services/db');
132 timestamp: new Date().toISOString(),
135 tenantId: req.user.tenantId
139 // 1. Get current tenant info
140 const currentTenant = await pool.query(
141 'SELECT tenant_id, name, meshcentral_group_id FROM tenants WHERE tenant_id = $1',
145 debug.currentTenant = currentTenant.rows[0] || null;
147 // 2. Get all tenants and their mesh groups
148 const allTenants = await pool.query(
149 'SELECT tenant_id, name, meshcentral_group_id FROM tenants ORDER BY name'
152 debug.allTenants = allTenants.rows.map(t => ({
154 hasMeshGroup: !!t.meshcentral_group_id
157 // 3. Get all mesh groups from MeshCentral
159 const meshGroups = await meshPool.query(`
161 (doc->>'_id') as mesh_id,
162 (doc->>'name') as mesh_name,
163 (doc->>'desc') as description
165 WHERE (doc->>'type') = 'mesh'
166 ORDER BY (doc->>'name')
169 debug.meshGroups = meshGroups.rows;
171 debug.meshGroups = { error: err.message };
174 // 4. Get all devices from MeshCentral
176 const allDevices = await meshPool.query(`
178 (doc->>'_id') as node_id,
179 (doc->>'name') as hostname,
180 (doc->>'meshid') as mesh_id,
181 (doc->'agent'->>'osdesc') as os,
182 (doc->>'conn')::int as conn_status
184 WHERE (doc->>'type') = 'node'
185 ORDER BY (doc->>'name')
188 debug.allDevices = allDevices.rows.map(d => ({
190 online: (d.conn_status & 1) > 0 || (d.conn_status & 16) > 0
193 debug.allDevices = { error: err.message };
196 // 5. Get devices for current tenant's mesh group
197 if (debug.currentTenant?.meshcentral_group_id) {
199 const tenantDevices = await meshPool.query(`
201 (doc->>'_id') as node_id,
202 (doc->>'name') as hostname,
203 (doc->>'meshid') as mesh_id,
204 (doc->>'conn')::int as conn_status
206 WHERE (doc->>'type') = 'node'
207 AND (doc->>'meshid') = $1
208 ORDER BY (doc->>'name')
209 `, [debug.currentTenant.meshcentral_group_id]);
211 debug.currentTenantDevices = tenantDevices.rows.map(d => ({
213 online: (d.conn_status & 1) > 0 || (d.conn_status & 16) > 0
216 debug.currentTenantDevices = { error: err.message };
219 debug.currentTenantDevices = { error: 'No mesh group assigned to tenant' };
222 // 6. Get backend agents
223 const backendAgents = await pool.query(
224 'SELECT agent_id, agent_uuid, hostname, meshcentral_nodeid, tenant_id, status FROM agents ORDER BY agent_id DESC LIMIT 20'
227 debug.backendAgents = backendAgents.rows;
231 totalTenants: debug.allTenants.length,
232 tenantsWithMeshGroup: debug.allTenants.filter(t => t.hasMeshGroup).length,
233 totalMeshGroups: Array.isArray(debug.meshGroups) ? debug.meshGroups.length : 0,
234 totalDevicesInMeshCentral: Array.isArray(debug.allDevices) ? debug.allDevices.length : 0,
235 devicesForCurrentTenant: Array.isArray(debug.currentTenantDevices) ? debug.currentTenantDevices.length : 0,
236 totalBackendAgents: debug.backendAgents.length
241 console.error('Debug endpoint error:', err);
242 res.status(500).json({ error: err.message, stack: err.stack });
246module.exports = router;