Skip to content
maintainx-local-dev-loop logo

MaintainX Local Dev Loop

maintainx-local-dev-loop

Set up a local development loop for MaintainX integration development. Use when configuring dev environment, testing API calls locally, or setting up a sandbox workflow for MaintainX. Trigger with phrases like "maintainx dev setup", "maintainx local", "maintainx development environment", "maintai...

SKILL.md

Full skill instructions

MaintainX Local Dev Loop

Overview

Set up an efficient local development workflow for building and testing MaintainX integrations.

Prerequisites

  • Completed maintainx-install-auth setup
  • Node.js 18+ installed
  • Docker (optional, for local testing)
  • VS Code or preferred IDE

Instructions

Step 1: Project Structure

# Create project structure
mkdir -p maintainx-integration/​{src/​{api,models,utils},tests,scripts}
cd maintainx-integration

# Initialize project
npm init -y
npm install axios dotenv typescript ts-node @types/​node
npm install -D jest @types/​jest ts-jest nodemon
maintainx-integration/
├── src/
│   ├── api/
│   │   └── client.ts         # MaintainX API client
│   ├── models/
│   │   ├── work-order.ts     # Work order types
│   │   ├── asset.ts          # Asset types
│   │   └── location.ts       # Location types
│   ├── utils/
│   │   ├── pagination.ts     # Cursor pagination helper
│   │   └── retry.ts          # Retry logic
│   └── index.ts              # Main entry point
├── tests/
│   ├── api.test.ts           # API integration tests
│   └── mocks/                # Mock responses
├── scripts/
│   └── seed-data.ts          # Seed test data
├── .env.development          # Dev environment vars
├── .env.test                 # Test environment vars
├── tsconfig.json
├── jest.config.js
└── package.json

Step 2: Environment Configuration

# .env.development
MAINTAINX_API_KEY=your-dev-api-key
MAINTAINX_BASE_URL=https://api.getmaintainx.com/v1
LOG_LEVEL=debug
NODE_ENV=development
# .env.test
MAINTAINX_API_KEY=your-test-api-key
MAINTAINX_BASE_URL=https://api.getmaintainx.com/v1
LOG_LEVEL=error
NODE_ENV=test
// src/​config.ts
import dotenv from 'dotenv';
import path from 'path';

const envFile = process.env.NODE_ENV === 'test'
  ? '.env.test'
  : '.env.development';

dotenv.config({ path: path.resolve(process.cwd(), envFile) });

export const config = {
  maintainx: {
    apiKey: process.env.MAINTAINX_API_KEY!,
    baseUrl: process.env.MAINTAINX_BASE_URL || 'https://api.getmaintainx.com/v1',
  },
  logLevel: process.env.LOG_LEVEL || 'info',
  isDevelopment: process.env.NODE_ENV === 'development',
  isTest: process.env.NODE_ENV === 'test',
};

Step 3: TypeScript Configuration

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ES2022"],
    "outDir": "./​dist",
    "rootDir": "./​src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/​**/​*"],
  "exclude": ["node_modules", "dist", "tests"]
}

Step 4: Dev Scripts Configuration

// package.json (scripts section)
{
  "scripts": {
    "dev": "nodemon --exec ts-node src/​index.ts",
    "build": "tsc",
    "test": "NODE_ENV=test jest",
    "test:watch": "NODE_ENV=test jest --watch",
    "test:integration": "NODE_ENV=test jest --testPathPattern=integration",
    "lint": "eslint src/​**/​*.ts",
    "seed": "ts-node scripts/​seed-data.ts",
    "repl": "ts-node",
    "api:test": "ts-node scripts/​api-test.ts"
  }
}

Step 5: Interactive REPL for Testing

// scripts/​repl.ts
import repl from 'repl';
import { MaintainXClient } from '../​src/​api/​client';

const client = new MaintainXClient();

const r = repl.start('maintainx> ');

// Add client to context
r.context.client = client;
r.context.help = () => {
  console.log(`
Available commands:
  client.getWorkOrders()     - List work orders
  client.getWorkOrder(id)    - Get single work order
  client.createWorkOrder({}) - Create work order
  client.getAssets()         - List assets
  client.getLocations()      - List locations
  client.getUsers()          - List users

Example:
  await client.getWorkOrders({ limit: 5 })
`);
};

console.log('MaintainX REPL started. Type help() for commands.');

Step 6: Mock Server for Offline Development

// tests/​mocks/​server.ts
import express from 'express';

const app = express();
app.use(express.json());

// Mock work orders
const mockWorkOrders = [
  {
    id: 'wo_mock_001',
    title: 'Mock Work Order 1',
    status: 'OPEN',
    priority: 'MEDIUM',
    createdAt: new Date().toISOString(),
  },
  {
    id: 'wo_mock_002',
    title: 'Mock Work Order 2',
    status: 'IN_PROGRESS',
    priority: 'HIGH',
    createdAt: new Date().toISOString(),
  },
];

app.get('/​v1/​workorders', (req, res) => {
  const limit = parseInt(req.query.limit as string) || 10;
  res.json({
    workOrders: mockWorkOrders.slice(0, limit),
    nextCursor: null,
  });
});

app.get('/​v1/​workorders/:id', (req, res) => {
  const wo = mockWorkOrders.find(w => w.id === req.params.id);
  if (wo) {
    res.json(wo);
  } else {
    res.status(404).json({ error: 'Work order not found' });
  }
});

app.post('/​v1/​workorders', (req, res) => {
  const newWo = {
    id: `wo_mock_${Date.now()}`,
    ...req.body,
    status: 'OPEN',
    createdAt: new Date().toISOString(),
  };
  mockWorkOrders.push(newWo);
  res.status(201).json(newWo);
});

// Start server
const PORT = process.env.MOCK_PORT || 3001;
app.listen(PORT, () => {
  console.log(`Mock MaintainX server running on port ${PORT}`);
});

export { app };

Step 7: Nodemon Configuration

// nodemon.json
{
  "watch": ["src"],
  "ext": "ts,json",
  "ignore": ["src/​**/​*.test.ts"],
  "exec": "ts-node src/​index.ts"
}

Step 8: Jest Configuration

// jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/​tests'],
  testMatch: ['**/​*.test.ts'],
  collectCoverageFrom: ['src/​**/​*.ts'],
  coverageDirectory: 'coverage',
  setupFilesAfterEnv: ['<rootDir>/​tests/​setup.ts'],
  testTimeout: 10000,
};
// tests/​setup.ts
import dotenv from 'dotenv';
dotenv.config({ path: '.env.test' });

// Global test setup
beforeAll(() => {
  console.log('Test environment initialized');
});

afterAll(() => {
  console.log('Test cleanup complete');
});

Step 9: Sample Integration Test

// tests/​api.test.ts
import { MaintainXClient } from '../​src/​api/​client';

describe('MaintainX API', () => {
  let client: MaintainXClient;

  beforeAll(() => {
    client = new MaintainXClient();
  });

  describe('Work Orders', () => {
    it('should list work orders', async () => {
      const response = await client.getWorkOrders({ limit: 5 });
      expect(response.data).toHaveProperty('workOrders');
      expect(Array.isArray(response.data.workOrders)).toBe(true);
    });

    it('should create a work order', async () => {
      const response = await client.createWorkOrder({
        title: 'Test Work Order - Jest',
        description: 'Created during automated testing',
        priority: 'LOW',
      });
      expect(response.data).toHaveProperty('id');
      expect(response.data.title).toBe('Test Work Order - Jest');
    });
  });

  describe('Assets', () => {
    it('should list assets', async () => {
      const response = await client.getAssets({ limit: 5 });
      expect(response.data).toHaveProperty('assets');
    });
  });
});

Output

  • Fully configured development environment
  • TypeScript project with hot reload
  • Mock server for offline testing
  • Jest test suite configured
  • Interactive REPL for exploration

Workflow Commands

# Start development with hot reload
npm run dev

# Run tests
npm test

# Watch mode for tests
npm run test:watch

# Interactive REPL
npm run repl

# Seed test data
npm run seed

# Start mock server (separate terminal)
npx ts-node tests/​mocks/​server.ts

Resources

Next Steps

For SDK patterns and best practices, see maintainx-sdk-patterns.