MA

maintainx-upgrade-migration

Audit and upgrade tool for MaintainX API version migrations.

Install

mkdir -p .claude/skills/maintainx-upgrade-migration && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/8140" && unzip -o skill.zip -d .claude/skills/maintainx-upgrade-migration && rm skill.zip

Installs to .claude/skills/maintainx-upgrade-migration

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Migrate MaintainX API versions and handle breaking changes.
59 charsno explicit “when” trigger
Advanced

Key capabilities

  • Audit existing MaintainX API usage across the codebase
  • Implement a version compatibility layer for API transitions
  • Apply feature flags for incremental per-endpoint migration
  • Execute migration tests to verify v1 and v2 equivalence
  • Perform automated rollbacks to previous API versions

How it works

The skill audits API usage, then provides a compatibility layer that transforms requests and responses between API versions. It uses feature flags to enable gradual, per-endpoint migration.

Inputs & outputs

You give it
Source code containing MaintainX API calls
You get back
Audit report and version-compatible API client

When to use maintainx-upgrade-migration

  • Upgrading MaintainX API version
  • Handling deprecated API endpoints
  • Auditing current MaintainX API call locations
  • Applying breaking change patches

About this skill

MaintainX Upgrade & Migration

Current State

!npm list 2>/dev/null | head -20

Overview

Handle MaintainX API version upgrades, deprecations, and breaking changes with a safe, incremental migration strategy.

Prerequisites

  • Existing MaintainX integration
  • Test environment with separate API key
  • Version control (git) for all integration code

Instructions

Step 1: Audit Current API Usage

// scripts/audit-api-usage.ts
// Scan your codebase for all MaintainX API calls

import { readFileSync, readdirSync, statSync } from 'fs';
import { join } from 'path';

function findApiCalls(dir: string): Array<{ file: string; line: number; endpoint: string }> {
  const results: Array<{ file: string; line: number; endpoint: string }> = [];

  function scan(d: string) {
    for (const entry of readdirSync(d)) {
      const full = join(d, entry);
      if (statSync(full).isDirectory()) {
        if (!entry.startsWith('.') && entry !== 'node_modules') scan(full);
      } else if (full.endsWith('.ts') || full.endsWith('.js')) {
        const content = readFileSync(full, 'utf-8');
        const lines = content.split('\n');
        for (let i = 0; i < lines.length; i++) {
          // Match API endpoint patterns
          const match = lines[i].match(/'"`[^'"`]*)/);
          if (match) {
            results.push({ file: full, line: i + 1, endpoint: match[1] });
          }
        }
      }
    }
  }

  scan(dir);
  return results;
}

const calls = findApiCalls('./src');
console.log('=== MaintainX API Usage Audit ===');
console.log(`Found ${calls.length} API calls:\n`);

// Group by endpoint
const grouped = new Map<string, typeof calls>();
for (const call of calls) {
  const base = call.endpoint.split('?')[0].replace(/\/\d+/, '/:id');
  const existing = grouped.get(base) || [];
  existing.push(call);
  grouped.set(base, existing);
}

for (const [endpoint, usages] of grouped) {
  console.log(`${endpoint} (${usages.length} calls):`);
  for (const u of usages) {
    console.log(`  ${u.file}:${u.line}`);
  }
}

Step 2: Version Compatibility Layer

// src/migration/compat.ts

type ApiVersion = 'v1' | 'v2';

interface VersionAdapter {
  baseUrl: string;
  transformRequest(endpoint: string, data: any): { endpoint: string; data: any };
  transformResponse(endpoint: string, data: any): any;
}

const adapters: Record<ApiVersion, VersionAdapter> = {
  v1: {
    baseUrl: 'https://api.getmaintainx.com/v1',
    transformRequest: (endpoint, data) => ({ endpoint, data }),
    transformResponse: (endpoint, data) => data,
  },
  v2: {
    baseUrl: 'https://api.getmaintainx.com/v2',
    transformRequest: (endpoint, data) => {
      // Handle breaking changes in v2
      if (endpoint.startsWith('/workorders') && data) {
        // Example: v2 renamed 'assignees' to 'assignedTo'
        if (data.assignees) {
          data.assignedTo = data.assignees;
          delete data.assignees;
        }
      }
      return { endpoint, data };
    },
    transformResponse: (endpoint, data) => {
      // Normalize v2 response to v1 shape
      if (data.assignedTo) {
        data.assignees = data.assignedTo;
      }
      return data;
    },
  },
};

class VersionedClient {
  private adapter: VersionAdapter;

  constructor(version: ApiVersion = 'v1') {
    this.adapter = adapters[version];
  }

  async request(method: string, endpoint: string, data?: any) {
    const { endpoint: ep, data: d } = this.adapter.transformRequest(endpoint, data);
    const response = await fetch(`${this.adapter.baseUrl}${ep}`, {
      method,
      headers: {
        Authorization: `Bearer ${process.env.MAINTAINX_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: d ? JSON.stringify(d) : undefined,
    });
    const result = await response.json();
    return this.adapter.transformResponse(ep, result);
  }
}

Step 3: Feature Flag Migration

// src/migration/feature-flags.ts

const MIGRATION_FLAGS: Record<string, boolean> = {
  USE_V2_WORKORDERS: false,   // Set to true when ready to switch
  USE_V2_ASSETS: false,
  USE_V2_PAGINATION: false,   // v2 might use offset instead of cursor
};

function getApiVersion(endpoint: string): ApiVersion {
  if (endpoint.startsWith('/workorders') && MIGRATION_FLAGS.USE_V2_WORKORDERS) return 'v2';
  if (endpoint.startsWith('/assets') && MIGRATION_FLAGS.USE_V2_ASSETS) return 'v2';
  return 'v1';
}

// Gradually roll out v2 per-endpoint
async function migratedRequest(method: string, endpoint: string, data?: any) {
  const version = getApiVersion(endpoint);
  const client = new VersionedClient(version);
  return client.request(method, endpoint, data);
}

Step 4: Migration Tests

// tests/migration.test.ts
import { describe, it, expect } from 'vitest';

describe('API Version Migration', () => {
  it('v1 and v2 return equivalent work order data', async () => {
    const v1Client = new VersionedClient('v1');
    const v2Client = new VersionedClient('v2');

    const v1Result = await v1Client.request('GET', '/workorders?limit=5');
    const v2Result = await v2Client.request('GET', '/workorders?limit=5');

    // After adapter normalization, shapes should match
    expect(v1Result.workOrders.length).toBe(v2Result.workOrders.length);
    expect(v1Result.workOrders[0]).toHaveProperty('id');
    expect(v1Result.workOrders[0]).toHaveProperty('title');
    expect(v1Result.workOrders[0]).toHaveProperty('status');
  });

  it('compatibility adapter transforms assignees correctly', () => {
    const adapter = adapters.v2;
    const { data } = adapter.transformRequest('/workorders', {
      title: 'Test',
      assignees: [{ type: 'USER', id: 1 }],
    });
    expect(data.assignedTo).toBeDefined();
    expect(data.assignees).toBeUndefined();
  });
});

Step 5: Rollback Procedure

#!/bin/bash
# rollback-api-version.sh
# Revert to v1 API if v2 migration causes issues

echo "=== MaintainX API Version Rollback ==="
echo "1. Set all feature flags to false:"
echo '   MIGRATION_FLAGS.USE_V2_WORKORDERS = false'
echo '   MIGRATION_FLAGS.USE_V2_ASSETS = false'
echo ""
echo "2. Redeploy with v1 configuration:"
echo "   git revert HEAD --no-edit && git push"
echo ""
echo "3. Verify v1 endpoints are working:"
echo '   curl -s https://api.getmaintainx.com/v1/workorders?limit=1 \'
echo '     -H "Authorization: Bearer $MAINTAINX_API_KEY" | jq .status'
echo ""
echo "4. Monitor error rates for 30 minutes"
echo "5. Document issues for v2 retry"

Output

  • API usage audit report listing all endpoints and call sites
  • Version compatibility layer with request/response adapters
  • Feature flag system for incremental per-endpoint migration
  • Migration tests verifying v1/v2 equivalence
  • Rollback procedure for safe revert

Error Handling

IssueCauseSolution
404 on v2 endpointEndpoint path changedUpdate adapter mappings
Field missing in v2 responseBreaking schema changeAdd field mapping in transformResponse
Mixed v1/v2 data in DBPartial migration stateRun reconciliation to normalize
Feature flag stuckConfig not reloadedRestart service or use dynamic config

Resources

Next Steps

For CI/CD integration, see maintainx-ci-integration.

Examples

Dual-write during migration (write to both v1 and v2):

async function dualWrite(endpoint: string, data: any) {
  const v1 = new VersionedClient('v1');
  const v2 = new VersionedClient('v2');

  const v1Result = await v1.request('POST', endpoint, data);

  try {
    await v2.request('POST', endpoint, data);
  } catch (err) {
    console.warn('v2 write failed (non-blocking):', err);
    // Log for investigation, don't fail the operation
  }

  return v1Result; // v1 is source of truth during migration
}

When not to use it

  • When version control is not in use
  • When a separate test environment is unavailable

Prerequisites

Existing MaintainX integrationTest environment with separate API keyVersion control (git)

Limitations

  • 404 errors if adapter mappings are outdated
  • Partial migration state leading to mixed data
  • Feature flag configuration not reloading dynamically

How it compares

This method allows for incremental migration and safe rollbacks compared to a full-scale, risky update of all API calls at once.

Compared to similar skills

maintainx-upgrade-migration side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
maintainx-upgrade-migration (this skill)026dCautionAdvanced
zustand1132moNo flagsIntermediate
dependency-upgrade265moReviewIntermediate
turborepo612moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

More by jeremylongshore

View all by jeremylongshore

analyzing-logs

jeremylongshore

Analyze application logs to detect performance issues, identify error patterns, and improve stability by extracting key insights.

14123

ollama-setup

jeremylongshore

Configure auto-configure Ollama when user needs local LLM deployment, free AI alternatives, or wants to eliminate hosted API costs. Trigger phrases: "install ollama", "local AI", "free LLM", "self-hosted AI", "replace OpenAI", "no API costs". Use when appropriate context detected. Trigger with relevant phrases based on skill purpose.

1167

backtesting-trading-strategies

jeremylongshore

Backtest crypto and traditional trading strategies against historical data. Calculates performance metrics (Sharpe, Sortino, max drawdown), generates equity curves, and optimizes strategy parameters. Use when user wants to test a trading strategy, validate signals, or compare approaches. Trigger with phrases like "backtest strategy", "test trading strategy", "historical performance", "simulate trades", "optimize parameters", or "validate signals".

1071

generating-database-seed-data

jeremylongshore

Process this skill enables AI assistant to generate realistic test data and database seed scripts for development and testing environments. it uses faker libraries to create realistic data, maintains relational integrity, and allows configurable data volumes. u... Use when working with databases or data models. Trigger with phrases like 'database', 'query', or 'schema'.

1033

cursor-codebase-indexing

jeremylongshore

Execute set up and optimize Cursor codebase indexing. Triggers on "cursor index setup", "codebase indexing", "index codebase", "cursor semantic search". Use when working with cursor codebase indexing functionality. Trigger with phrases like "cursor codebase indexing", "cursor indexing", "cursor".

885

testing-mobile-apps

jeremylongshore

Execute mobile app testing on iOS and Android devices/simulators. Use when performing specialized testing. Trigger with phrases like "test mobile app", "run iOS tests", or "validate Android functionality".

810

You might also like

zustand

lobehub

Zustand state management guide. Use when working with store code (src/store/**), implementing actions, managing state, or creating slices. Triggers on Zustand store development, state management questions, or action implementation.

113434

dependency-upgrade

wshobson

Manage major dependency version upgrades with compatibility analysis, staged rollout, and comprehensive testing. Use when upgrading framework versions, updating major dependencies, or managing breaking changes in libraries.

26240

turborepo

vercel

Turborepo monorepo build system guidance. Triggers on: turbo.json, task pipelines, dependsOn, caching, remote cache, the "turbo" CLI, --filter, --affected, CI optimization, environment variables, internal packages, monorepo structure/best practices, and boundaries. Use when user: configures tasks/workflows/pipelines, creates packages, sets up monorepo, shares code between apps, runs changed/affected packages, debugs cache, or has apps/packages directories.

61191

vitest

antfu

Vitest fast unit testing framework powered by Vite with Jest-compatible API. Use when writing tests, mocking, configuring coverage, or working with test filtering and fixtures.

41183

typescript-review

metabase

Review TypeScript and JavaScript code changes for compliance with Metabase coding standards, style violations, and code quality issues. Use when reviewing pull requests or diffs containing TypeScript/JavaScript code.

39178

threejs-skills

sickn33

Three.js skills for creating 3D elements and interactive experiences

61152

Search skills

Search the agent skills registry