# Aruba Central API Node for n8n: Development & Troubleshooting Guide

You're working on an n8n integration node for Aruba Central API. This comprehensive guide will help you continue development, implement new features, and troubleshoot issues with the codebase.

## Project Structure

The project follows a domain-driven design with the following structure:

```         
.
├── ArubaCentral.node.ts
├── api
│   ├── aiops
│   │   ├── aiops.operations.ts
│   │   ├── aiops.types.ts
│   │   ├── connectivity
│   │   │   ├── connectivity.common.ts
│   │   │   ├── connectivity.descriptions.ts
│   │   │   ├── connectivity.methods.ts
│   │   │   ├── connectivity.operations.ts
│   │   │   ├── getGlobalConnectivity.descriptions.ts
│   │   │   ├── getGlobalConnectivity.methods.ts
│   │   │   ├── getGroupConnectivity.descriptions.ts
│   │   │   ├── getGroupConnectivity.methods.ts
│   │   │   ├── getSiteConnectivity.descriptions.ts
│   │   │   └── getSiteConnectivity.methods.ts
│   │   ├── insight
│   │   │   ├── insight.common.ts
│   │   │   ├── insight.descriptions.ts
│   │   │   ├── insight.operations.ts
│   │   │   ├── insights.methods.ts
│   │   │   ├── listApInsights.descriptions.ts
│   │   │   ├── listApInsights.methods.ts
│   │   │   ├── listClientInsights.descriptions.ts
│   │   │   ├── listClientInsights.methods.ts
│   │   │   ├── listGlobalInsights.descriptions.ts
│   │   │   ├── listGlobalInsights.methods.ts
│   │   │   ├── listSiteInsights.descriptions.ts
│   │   │   └── listSiteInsights.methods.ts
│   │   └── insights
│   ├── configuration
│   │   ├── ap
│   │   │   ├── ap.common.ts
│   │   │   ├── apCli.methods.ts
│   │   │   ├── apConfiguration.types.ts
│   │   │   ├── apSettings.methods.ts
│   │   │   ├── apSettings.types.ts
│   │   │   ├── apSpecialized.methods.ts
│   │   │   ├── armConfig.methods.ts
│   │   │   ├── dirtyDiff.methods.ts
│   │   │   ├── dot11aRadio.methods.ts
│   │   │   ├── dot11gRadio.methods.ts
│   │   │   ├── getApCli.descriptions.ts
│   │   │   ├── getApSettings.descriptions.ts
│   │   │   ├── iapVariables.methods.ts
│   │   │   ├── replaceApCli.descriptions.ts
│   │   │   ├── replaceApSettings.descriptions.ts
│   │   │   ├── setApHostname.descriptions.ts
│   │   │   ├── setApSsids.descriptions.ts
│   │   │   ├── sshCredentials.methods.ts
│   │   │   └── systemConfig.methods.ts
│   │   ├── configuration.operations.ts
│   │   └── devices
│   │       ├── devices.common.ts
│   │       ├── devices.types.ts
│   │       ├── getDeviceGroup.descriptions.ts
│   │       ├── group.methods.ts
│   │       └── moveDevicesToGroup.descriptions.ts
│   ├── descriptions.ts
│   ├── firmware
│   │   ├── compliance
│   │   │   ├── clearFirmwareComplianceVersion.methods.ts
│   │   │   ├── compliance.common.ts
│   │   │   ├── compliance.methods.ts
│   │   │   ├── getFirmwareComplianceVersion.descriptions.ts
│   │   │   ├── getFirmwareComplianceVersion.methods.ts
│   │   │   ├── setFirmwareComplianceVersion.descriptions.ts
│   │   │   └── setFirmwareComplianceVersion.methods.ts
│   │   ├── devices
│   │   │   ├── devices.common.ts
│   │   │   ├── devices.methods.ts
│   │   │   ├── getFirmwareDeviceDetails.descriptions.ts
│   │   │   ├── getFirmwareDeviceDetails.methods.ts
│   │   │   ├── getFirmwareDevicesList.descriptions.ts
│   │   │   └── getFirmwareDevicesList.methods.ts
│   │   ├── firmware.common.ts
│   │   ├── firmware.operations.ts
│   │   ├── firmware.types.ts
│   │   ├── status
│   │   │   ├── getFirmwareStatus.descriptions.ts
│   │   │   ├── getFirmwareStatus.methods.ts
│   │   │   ├── status.common.ts
│   │   │   └── status.methods.ts
│   │   ├── upgrades
│   │   │   ├── cancelFirmwareUpgrade.descriptions.ts
│   │   │   ├── cancelFirmwareUpgrade.methods.ts
│   │   │   ├── upgradeFirmware.descriptions.ts
│   │   │   ├── upgradeFirmware.methods.ts
│   │   │   ├── upgrades.common.ts
│   │   │   └── upgrades.methods.ts
│   │   └── versions
│   │       ├── getFirmwareVersion.descriptions.ts
│   │       ├── getFirmwareVersion.methods.ts
│   │       ├── getFirmwareVersions.descriptions.ts
│   │       ├── getFirmwareVersions.methods.ts
│   │       ├── versions.common.ts
│   │       └── versions.methods.ts
│   ├── inventory
│   │   ├── devices
│   │   │   ├── addDevice.descriptions.ts
│   │   │   ├── addDevice.methods.ts
│   │   │   ├── archiveDevices.descriptions.ts
│   │   │   ├── archiveDevices.methods.ts
│   │   │   ├── deleteDevice.descriptions.ts
│   │   │   ├── deleteDevice.methods.ts
│   │   │   ├── devices.common.ts
│   │   │   ├── devices.methods.ts
│   │   │   ├── getArchivedDevices.descriptions.ts
│   │   │   ├── getArchivedDevices.methods.ts
│   │   │   ├── getDeviceStats.descriptions.ts
│   │   │   ├── getDeviceStats.methods.ts
│   │   │   ├── getDevices.descriptions.ts
│   │   │   ├── getDevices.methods.ts
│   │   │   ├── unarchiveDevices.descriptions.ts
│   │   │   ├── unarchiveDevices.methods.ts
│   │   │   ├── verifyDevice.descriptions.ts
│   │   │   └── verifyDevice.methods.ts
│   │   ├── inventory.operations.ts
│   │   └── inventory.types.ts
│   ├── monitoring
│   │   ├── ap
│   │   │   ├── ap.descriptions.ts
│   │   │   ├── ap.methods.ts
│   │   │   ├── ap.types.ts
│   │   │   └── operations
│   │   │       ├── deleteAP.descriptions.ts
│   │   │       ├── deleteAP.methods.ts
│   │   │       ├── getAPBandwidthUsage.descriptions.ts
│   │   │       ├── getAPBandwidthUsage.methods.ts
│   │   │       ├── getAPDetails.descriptions.ts
│   │   │       ├── getAPDetails.methods.ts
│   │   │       ├── getAPRFSummary.descriptions.ts
│   │   │       ├── getAPRFSummary.methods.ts
│   │   │       ├── getAPs.descriptions.ts
│   │   │       ├── getAPs.methods.ts
│   │   │       ├── getBSSIDs.descriptions.ts
│   │   │       ├── getBSSIDs.methods.ts
│   │   │       ├── getTopNAPs.descriptions.ts
│   │   │       └── getTopNAPs.methods.ts
│   │   ├── client
│   │   │   ├── client.descriptions.ts
│   │   │   ├── client.methods.ts
│   │   │   ├── client.types.ts
│   │   │   └── operations
│   │   │       ├── getClientBandwidthUsage.descriptions.ts
│   │   │       ├── getClientBandwidthUsage.methods.ts
│   │   │       ├── getClientDetails.descriptions.ts
│   │   │       ├── getClientDetails.methods.ts
│   │   │       ├── getClientMobilityTrail.descriptions.ts
│   │   │       ├── getClientMobilityTrail.methods.ts
│   │   │       ├── getClientsCount.descriptions.ts
│   │   │       ├── getClientsCount.methods.ts
│   │   │       ├── getTopNClients.descriptions.ts
│   │   │       ├── getTopNClients.methods.ts
│   │   │       ├── getUnifiedClients.descriptions.ts
│   │   │       ├── getUnifiedClients.methods.ts
│   │   │       ├── getWiredClientDetails.descriptions.ts
│   │   │       ├── getWiredClientDetails.methods.ts
│   │   │       ├── getWiredClients.descriptions.ts
│   │   │       ├── getWiredClients.methods.ts
│   │   │       ├── getWirelessClientDetails.descriptions.ts
│   │   │       ├── getWirelessClientDetails.methods.ts
│   │   │       ├── getWirelessClients.descriptions.ts
│   │   │       └── getWirelessClients.methods.ts
│   │   ├── events
│   │   │   ├── events.descriptions.ts
│   │   │   ├── events.methods.ts
│   │   │   ├── events.types.ts
│   │   │   └── operations
│   │   │       ├── getEvents.descriptions.ts
│   │   │       └── getEvents.methods.ts
│   │   ├── gateway
│   │   │   ├── gateway.descriptions.ts
│   │   │   ├── gateway.methods.ts
│   │   │   ├── gateway.types.ts
│   │   │   └── operations
│   │   │       ├── deleteGateway.descriptions.ts
│   │   │       ├── deleteGateway.methods.ts
│   │   │       ├── getClients.descriptions.ts
│   │   │       ├── getClients.methods.ts
│   │   │       ├── getDetail.descriptions.ts
│   │   │       ├── getDetail.methods.ts
│   │   │       ├── getDistribution.descriptions.ts
│   │   │       ├── getDistribution.methods.ts
│   │   │       ├── getErrors.descriptions.ts
│   │   │       ├── getErrors.methods.ts
│   │   │       ├── getGateway.descriptions.ts
│   │   │       ├── getGateway.methods.ts
│   │   │       ├── getGateways.descriptions.ts
│   │   │       ├── getGateways.methods.ts
│   │   │       ├── getInfo.descriptions.ts
│   │   │       ├── getInfo.methods.ts
│   │   │       ├── getPools.descriptions.ts
│   │   │       ├── getPools.methods.ts
│   │   │       ├── getPorts.descriptions.ts
│   │   │       ├── getPorts.methods.ts
│   │   │       ├── getStats.descriptions.ts
│   │   │       ├── getStats.methods.ts
│   │   │       ├── getTunnels.descriptions.ts
│   │   │       ├── getTunnels.methods.ts
│   │   │       ├── getUsage.descriptions.ts
│   │   │       └── getUsage.methods.ts
│   │   ├── label
│   │   │   ├── label.descriptions.ts
│   │   │   ├── label.methods.ts
│   │   │   ├── label.types.ts
│   │   │   └── operations
│   │   │       ├── deleteDevices.descriptions.ts
│   │   │       ├── deleteDevices.methods.ts
│   │   │       ├── deleteLabel.descriptions.ts
│   │   │       ├── deleteLabel.methods.ts
│   │   │       ├── getCategories.descriptions.ts
│   │   │       ├── getCategories.methods.ts
│   │   │       ├── getLabel.descriptions.ts
│   │   │       ├── getLabel.methods.ts
│   │   │       ├── getLabels.descriptions.ts
│   │   │       ├── getLabels.methods.ts
│   │   │       ├── patchLabel.descriptions.ts
│   │   │       ├── patchLabel.methods.ts
│   │   │       ├── postDevices.descriptions.ts
│   │   │       ├── postDevices.methods.ts
│   │   │       ├── postLabel.descriptions.ts
│   │   │       └── postLabel.methods.ts
│   │   ├── mobilitycontroller
│   │   │   ├── mobilitycontroller.descriptions.ts
│   │   │   ├── mobilitycontroller.methods.ts
│   │   │   ├── mobilitycontroller.types.ts
│   │   │   └── operations
│   │   │       ├── deleteSerial.descriptions.ts
│   │   │       ├── deleteSerial.methods.ts
│   │   │       ├── getInfo.descriptions.ts
│   │   │       ├── getInfo.methods.ts
│   │   │       ├── getMcs.descriptions.ts
│   │   │       ├── getMcs.methods.ts
│   │   │       ├── getMobility_controllers.descriptions.ts
│   │   │       ├── getMobility_controllers.methods.ts
│   │   │       ├── getPorts.descriptions.ts
│   │   │       ├── getPorts.methods.ts
│   │   │       ├── getSerial.descriptions.ts
│   │   │       ├── getSerial.methods.ts
│   │   │       ├── getUsage.descriptions.ts
│   │   │       └── getUsage.methods.ts
│   │   ├── monitoring.descriptions.ts
│   │   ├── monitoring.methods.ts
│   │   ├── monitoring.resources.ts
│   │   ├── network
│   │   │   ├── network.descriptions.ts
│   │   │   ├── network.methods.ts
│   │   │   ├── network.types.ts
│   │   │   └── operations
│   │   │       ├── getBandwidth_usage.descriptions.ts
│   │   │       ├── getBandwidth_usage.methods.ts
│   │   │       ├── getNetwork_name.descriptions.ts
│   │   │       ├── getNetwork_name.methods.ts
│   │   │       ├── getNetworks.descriptions.ts
│   │   │       └── getNetworks.methods.ts
│   │   ├── site
│   │   │   ├── operations
│   │   │   │   ├── associateSiteToDevice.descriptions.ts
│   │   │   │   ├── associateSiteToDevice.methods.ts
│   │   │   │   ├── associateSiteToDevices.descriptions.ts
│   │   │   │   ├── associateSiteToDevices.methods.ts
│   │   │   │   ├── createSite.descriptions.ts
│   │   │   │   ├── createSite.methods.ts
│   │   │   │   ├── deleteSite.descriptions.ts
│   │   │   │   ├── deleteSite.methods.ts
│   │   │   │   ├── getSiteDetails.descriptions.ts
│   │   │   │   ├── getSiteDetails.methods.ts
│   │   │   │   ├── getSites.descriptions.ts
│   │   │   │   ├── getSites.methods.ts
│   │   │   │   ├── unassociateSiteFromDevice.descriptions.ts
│   │   │   │   ├── unassociateSiteFromDevice.methods.ts
│   │   │   │   ├── unassociateSiteFromDevices.descriptions.ts
│   │   │   │   ├── unassociateSiteFromDevices.methods.ts
│   │   │   │   ├── updateSite.descriptions.ts
│   │   │   │   └── updateSite.methods.ts
│   │   │   ├── site.descriptions.ts
│   │   │   ├── site.methods.ts
│   │   │   └── site.types.ts
│   │   ├── swarm
│   │   │   ├── operations
│   │   │   │   ├── getSwarm.descriptions.ts
│   │   │   │   ├── getSwarm.methods.ts
│   │   │   │   ├── getSwarms.descriptions.ts
│   │   │   │   ├── getSwarms.methods.ts
│   │   │   │   ├── getTopn.descriptions.ts
│   │   │   │   └── getTopn.methods.ts
│   │   │   ├── swarm.descriptions.ts
│   │   │   ├── swarm.methods.ts
│   │   │   └── swarm.types.ts
│   │   ├── switch
│   │   │   ├── operations
│   │   │   │   ├── deleteStack.descriptions.ts
│   │   │   │   ├── deleteStack.methods.ts
│   │   │   │   ├── deleteSwitch.descriptions.ts
│   │   │   │   ├── deleteSwitch.methods.ts
│   │   │   │   ├── getDetail.descriptions.ts
│   │   │   │   ├── getDetail.methods.ts
│   │   │   │   ├── getErrors.descriptions.ts
│   │   │   │   ├── getErrors.methods.ts
│   │   │   │   ├── getInfo.descriptions.ts
│   │   │   │   ├── getInfo.methods.ts
│   │   │   │   ├── getNeighbors.descriptions.ts
│   │   │   │   ├── getNeighbors.methods.ts
│   │   │   │   ├── getPorts.descriptions.ts
│   │   │   │   ├── getPorts.methods.ts
│   │   │   │   ├── getStack.descriptions.ts
│   │   │   │   ├── getStack.methods.ts
│   │   │   │   ├── getStacks.descriptions.ts
│   │   │   │   ├── getStacks.methods.ts
│   │   │   │   ├── getSwitch.descriptions.ts
│   │   │   │   ├── getSwitch.methods.ts
│   │   │   │   ├── getSwitches.descriptions.ts
│   │   │   │   ├── getSwitches.methods.ts
│   │   │   │   ├── getTopn.descriptions.ts
│   │   │   │   ├── getTopn.methods.ts
│   │   │   │   ├── getUsage.descriptions.ts
│   │   │   │   ├── getUsage.methods.ts
│   │   │   │   ├── getVlan.descriptions.ts
│   │   │   │   └── getVlan.methods.ts
│   │   │   ├── switch.descriptions.ts
│   │   │   ├── switch.methods.ts
│   │   │   └── switch.types.ts
│   │   └── vpn
│   │       ├── operations
│   │       │   ├── getInfo.descriptions.ts
│   │       │   ├── getInfo.methods.ts
│   │       │   ├── postUsage.descriptions.ts
│   │       │   └── postUsage.methods.ts
│   │       ├── vpn.descriptions.ts
│   │       ├── vpn.methods.ts
│   │       └── vpn.types.ts
│   ├── operations.ts
│   └── topology
│       ├── topology
│       │   ├── getApNeighbors.descriptions.ts
│       │   ├── getApNeighbors.methods.ts
│       │   ├── getDeviceDetails.descriptions.ts
│       │   ├── getDeviceDetails.methods.ts
│       │   ├── getEdgeDetails.descriptions.ts
│       │   ├── getEdgeDetails.methods.ts
│       │   ├── getEdgeDetailsV2.descriptions.ts
│       │   ├── getEdgeDetailsV2.methods.ts
│       │   ├── getSiteTopology.descriptions.ts
│       │   ├── getSiteTopology.methods.ts
│       │   ├── getSiteVlans.descriptions.ts
│       │   ├── getSiteVlans.methods.ts
│       │   ├── getTunnelDetails.descriptions.ts
│       │   ├── getTunnelDetails.methods.ts
│       │   ├── getUnreachableDevices.descriptions.ts
│       │   ├── getUnreachableDevices.methods.ts
│       │   ├── getUplinkDetails.descriptions.ts
│       │   ├── getUplinkDetails.methods.ts
│       │   ├── topology.common.ts
│       │   ├── topology.methods.ts
│       │   └── topology.operations.ts
│       ├── topology.operations.ts
│       └── topology.types.ts
├── arubaCentral.svg
├── credentials
│   └── ArubaCentralOAuth2Api.credentials.ts
├── docs
│   └── Instructions.md
├── helpers
│   ├── apiRequest.ts
│   ├── deduplicate.ts
│   ├── errorHandler.ts
│   ├── executeOperation.ts
│   ├── formatter.ts
│   ├── logger.ts
│   ├── pagination.ts
│   ├── responseFormatter.ts
│   └── validation.ts
├── shared
│   ├── interfaces.ts
│   └── utilities.ts
└── tests
    └── monitoring
        ├── ap.test.ts
        └── client.test.ts
```


Each domain directory (e.g., api/monitoring/) follows this structure:
```
.
├── resource/                 # e.g., ap, client, switch
│   ├── resource.common.ts    # Shared utilities for the resource
│   ├── resource.descriptions.ts   # Resource Description File
│   ├── resource.methods.ts   # API method implementations
│   ├── resource.types.ts     # Resource-specific types
│   └── operations/           # Individual operation implementations
│       ├── operation.methods.ts
│       └── operation.descriptions.ts
```

## Architecture & Design Pattern

The node follows a domain-driven design pattern that separates:

1. **Domain Logic**: Each API domain (monitoring, firmware, etc.) has its own directory in `api/`
2. **Resource Implementation**: Each resource within a domain has its own directory with dedicated files
3. **Operation Handlers**: Individual operations are implemented in separate files for clarity
4. **UI Descriptions**: Individual resource definitions are implemented in separate files for clarity
5. **Shared Components**: Common utilities and types are organized in `shared/` and `helpers/`

### Operation Flow

1. User selects Domain → Resource → Operation in n8n UI
2. `ArubaCentral.node.ts` routes to appropriate domain handler
3. Domain handler delegates to resource implementation
4. Resource implementation executes specific operation
5. Response is formatted and returned to n8n

## Adding New API Operations

Now, let's define a clear pattern for the entire integration that follows your desired structure:
1. Operation Level Files

For each operation like getSites, we need just two files:

Operation Method File (operations/getSites.methods.ts):

```typescript

import { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { apiRequest } from '../../../../helpers/apiRequest';
import { logger } from '../../../../helpers/logger';
import { handleApiError } from '../../../../helpers/errorHandler';

/**
 * Get a list of sites from Aruba Central
 * 
 * @param this The n8n execution context
 * @returns Formatted list of sites
 */
export async function getSites(this: IExecuteFunctions): Promise<INodeExecutionData[]> {
  try {
    // Implementation here
  } catch (error) {
    return handleApiError.call(this, error, 'Failed to get sites');
  }
}
```

Operation Description File (operations/getSites.descriptions.ts):

```typescript

import { INodeProperties } from 'n8n-workflow';

/**
 * UI parameters for the getSites operation
 */
export const getSitesDescription: INodeProperties[] = [
  {
    displayName: 'Return All',
    name: 'returnAll',
    type: 'boolean',
    displayOptions: {
      show: {
        resource: ['site'],
        domain: ['monitoring'],
        operation: ['getSites'],
      },
    },
    default: false,
    description: 'Whether to return all results or only up to a given limit',
  },
  // More parameters...
];
```

2. Resource Level Files

For each resource like site, we need three files:

Resource Method File (site/site.methods.ts):

```typescript
import { IExecuteFunctions } from 'n8n-workflow';
import { getSites } from './operations/getSites.methods';
import { createSite } from './operations/createSite.methods';
// Import other operations

/**
 * All operations available for the Site resource
 */
export const siteOperations = {
  getSites,
  createSite,
  // Other operations
};

/**
 * Check if a site operation exists
 */
export function hasSiteOperation(operation: string): boolean {
  return !!siteOperations[operation as keyof typeof siteOperations];
}
```

Resource Description File (site/site.descriptions.ts):

```typescript

import { INodeProperties } from 'n8n-workflow';
import { getSitesDescription } from './operations/getSites.descriptions';
import { createSiteDescription } from './operations/createSite.descriptions';
// Import other descriptions

// Define the operation selector
export const siteOperationSelector: INodeProperties = {
  displayName: 'Operation',
  name: 'operation',
  type: 'options',
  // Define options for the dropdown
  options: [
    {
      name: 'Get Sites',
      value: 'getSites',
      description: 'Get a list of sites',
      action: 'Get sites',
    },
    // Other operations
  ],
  default: 'getSites',
};

// Build the descriptions array carefully to avoid duplication
export const siteDescriptions: INodeProperties[] = [siteOperationSelector];

// Add each operation's descriptions only once
function addDescriptionArray(array: INodeProperties[] | undefined) {
  if (!Array.isArray(array) || array.length === 0) return;
  
  array.forEach(item => {
    const exists = siteDescriptions.some(existing => 
      existing.name === item.name && 
      existing.type === item.type &&
      JSON.stringify(existing.displayOptions) === JSON.stringify(item.displayOptions)
    );
    
    if (!exists) {
      siteDescriptions.push(item);
    }
  });
}

// Add all operation descriptions
addDescriptionArray(getSitesDescription);
addDescriptionArray(createSiteDescription);
// Add other descriptions
```

Resource Type File (site/site.types.ts):

```typescript
// Define types for the resource
export interface Site {
  site_id: string;
  site_name: string;
  // Other properties
}

export interface SiteListResponse {
  sites: Site[];
  count: number;
}

// Other type definitions
```

3. Domain Level Files

For each domain like monitoring, we need three files:

Domain Methods File (monitoring/monitoring.methods.ts):

```typescript

import { siteOperations } from './site/site.methods';
import { apOperations } from './ap/ap.methods';
import { clientOperations } from './client/client.methods';

/**
 * All operations in the monitoring domain
 */
export const monitoringOperations = {
  site: siteOperations,
  ap: apOperations,
  client: clientOperations,
};

/**
 * Check if an operation exists in the monitoring domain
 */
export function hasOperation(resource: string, operation: string): boolean {
  return !!monitoringOperations[resource]?.[operation];
}
```

Domain Description File (monitoring/monitoring.descriptions.ts):

```typescript
import { INodeProperties } from 'n8n-workflow';
import { siteDescriptions } from './site/site.descriptions';
import { apDescriptions } from './ap/ap.descriptions';
import { clientDescriptions } from './client/client.descriptions';

// Resource selection for the monitoring domain
export const monitoringResourceSelector: INodeProperties = {
  displayName: 'Resource',
  name: 'resource',
  type: 'options',
  options: [
    { name: 'Site', value: 'site' },
    { name: 'Access Point', value: 'ap' },
    { name: 'Client', value: 'client' },
  ],
  default: 'site',
};

// Build the descriptions array carefully to avoid duplication
export const monitoringDescriptions: INodeProperties[] = [monitoringResourceSelector];

// Add each resource's descriptions
function addDescriptionArray(array: INodeProperties[] | undefined) {
  if (!Array.isArray(array) || array.length === 0) return;
  
  array.forEach(item => {
    const exists = monitoringDescriptions.some(existing => 
      existing.name === item.name && 
      existing.type === item.type &&
      JSON.stringify(existing.displayOptions) === JSON.stringify(item.displayOptions)
    );
    
    if (!exists) {
      monitoringDescriptions.push(item);
    }
  });
}

// Add each resource's descriptions
addDescriptionArray(siteDescriptions);
addDescriptionArray(apDescriptions);
addDescriptionArray(clientDescriptions);
```

4. Root API Files

At the root of the API, we need:

Description File (api/descriptions.ts):

```typescript
import { INodeProperties } from 'n8n-workflow';
import { monitoringDescriptions } from './monitoring/monitoring.descriptions';
// Import other domains

// Domain selection
export const domainSelector: INodeProperties = {
  displayName: 'Domain',
  name: 'domain',
  type: 'options',
  options: [
    { name: 'Monitoring', value: 'monitoring' },
    // Other domains
  ],
  default: 'monitoring',
};

// Build the descriptions array carefully to avoid duplication
export const allDescriptions: INodeProperties[] = [domainSelector];

// Add each domain's descriptions
function addDescriptionArray(array: INodeProperties[] | undefined) {
  if (!Array.isArray(array) || array.length === 0) return;
  
  array.forEach(item => {
    const exists = allDescriptions.some(existing => 
      existing.name === item.name && 
      existing.type === item.type &&
      JSON.stringify(existing.displayOptions) === JSON.stringify(item.displayOptions)
    );
    
    if (!exists) {
      allDescriptions.push(item);
    }
  });
}

// Add domains
addDescriptionArray(monitoringDescriptions);
// Add other domains
```

5. Helper Functions

Create a deduplicate.ts helper to reuse our deduplication logic:

```typescript
// helpers/deduplicate.ts
import { INodeProperties } from 'n8n-workflow';

/**
 * Adds descriptions to a target array, avoiding duplicates
 * 
 * @param target The target array to add descriptions to
 * @param source The source array of descriptions to add
 */
export function addDescriptions(target: INodeProperties[], source: INodeProperties[] | undefined): void {
  if (!Array.isArray(source) || source.length === 0) return;
  
  source.forEach(item => {
    const exists = target.some(existing => 
      existing.name === item.name && 
      existing.type === item.type &&
      JSON.stringify(existing.displayOptions) === JSON.stringify(item.displayOptions)
    );
    
    if (!exists) {
      target.push(item);
    }
  });
}
```

## Troubleshooting

### Common Issues

1. **Type Errors**
   - Check interfaces in resource's `.types.ts` file
   - Verify type imports are correct
   - Ensure API response matches type definitions

2. **Authentication Issues**
   - Check credentials implementation in `credentials/`
   - Verify token refresh logic
   - Monitor API request headers

3. **Operation Not Found**
   - Verify operation is exported in resource's `.common.ts`
   - Check domain operation registration
   - Confirm UI description is properly registered

4. **Response Formatting Errors**
   - Check response type matches expected format
   - Verify formatResponse helper is handling the type
   - Log raw response for debugging

### Debugging Tips

1. Use domain-specific logging:
```typescript
import { logger } from '../../../helpers/logger';

logger.debug('monitoring:ap:getStatus', { params, response });
```

2. Test operations in isolation:
```typescript
// tests/monitoring/ap/getStatus.test.ts
describe('AP Status Operation', () => {
  it('should retrieve device status', async () => {
    const result = await getStatus.call(mockExecuteFunctions);
    expect(result).toBeDefined();
  });
});
```

3. Validate API responses against types:
```typescript
import { StatusResponse } from './ap.types';

const validateResponse = (data: unknown): data is StatusResponse => {
  // Implementation
};
```

## OAuth2 Authentication

Authentication is handled centrally through:
- `credentials/ArubaCentralOAuth2Api.credentials.ts` - Credential definition
- `helpers/apiRequest.ts` - Request handling with auth

## Best Practices

1. **Domain Organization**
   - Keep related operations in same resource directory
   - Use common.ts for shared resource code
   - Maintain clear separation between domains

2. **Type Safety**
   - Define interfaces for all API responses
   - Use type guards for validation
   - Keep types synchronized with API spec

3. **Error Handling**
   - Use domain-specific error types
   - Implement consistent error formatting
   - Provide clear error messages

4. **Documentation**
   - Document complex operations
   - Keep API references updated
   - Include examples in descriptions

5. **Testing**
   - Write tests for each operation
   - Test error conditions
   - Validate response formatting

## Development Workflow

1. **Planning**
   - Identify domain and resource
   - Review API documentation
   - Plan type structures

2. **Implementation**
   - Create operation files
   - Implement method logic
   - Add UI descriptions

3. **Integration**
   - Register with resource
   - Update domain operations
   - Test end-to-end flow

4. **Documentation**
   - Update operation docs
   - Add usage examples
   - Document error cases

5. **Testing**
   - Unit test operation
   - Integration test with API
   - Verify UI functionality

## API Documentation References

For more details on available endpoints and parameters, refer to:
- API documentation in vector store
- Domain-specific documentation in `docs/api/`
- Operation descriptions in code

## Next Steps

Your task is to: {{ task }}

Fix Current Issues

    - Standardize error handling across all operations using the handleApiError helper
    - Enhance response formatting to handle all possible response structures
    - Improve parameter validation before making API requests

Documentation

    - Add JSDoc comments to all functions
    - Create usage examples for common operations
    - Document error cases and handling


Remember to:
1. Follow the domain-driven structure
2. Implement proper error handling
3. Add comprehensive types
4. Include operation documentation
5. Write tests for new functionality