agentsclimarketplace

Maintainx reference architecture

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/maintainx-pack/skills/maintainx-reference-architecture

'Production-grade architecture patterns for MaintainX integrations.From its SKILL.md

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill maintainx-reference-architecture

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

10.1 KB, ~2.2k tokens by cl100k_base, as published. Nobody here has run it

MaintainX Reference Architecture

Overview

Production-grade architecture patterns for building scalable, maintainable integrations between MaintainX and enterprise systems (ERP, SCADA, data warehouses).

Prerequisites

  • Understanding of distributed systems
  • Cloud platform experience (GCP, AWS, or Azure)
  • MaintainX API familiarity

Instructions

Step 1: Event-Driven Sync Architecture

The recommended architecture for most MaintainX integrations. Uses webhooks for real-time updates and scheduled jobs for reconciliation.

MaintainX API ──webhook──→ Cloud Run ──→ Pub/Sub ──→ Cloud Functions
                                              │
                                              ├──→ BigQuery (analytics)
                                              ├──→ ERP System (SAP, Oracle)
                                              └──→ Notification Service
// src/architecture/event-driven.ts
import express from 'express';
import { PubSub } from '@google-cloud/pubsub';

const app = express();
const pubsub = new PubSub();
const topic = pubsub.topic('maintainx-events');

// Webhook receiver publishes to Pub/Sub
app.post('/webhooks/maintainx', async (req, res) => {
  const { event, data } = req.body;

  await topic.publishMessage({
    data: Buffer.from(JSON.stringify({ event, data })),
    attributes: { event, resourceId: String(data.id) },
  });

  res.status(200).json({ status: 'queued' });
});

// Subscriber processes events asynchronously
const subscription = pubsub.subscription('maintainx-events-sub');
subscription.on('message', async (message) => {
  const { event, data } = JSON.parse(message.data.toString());

  switch (event) {
    case 'workorder.completed':
      await syncToERP(data);
      await updateAnalytics(data);
      break;
    case 'workorder.created':
      if (data.priority === 'HIGH') {
        await sendUrgentNotification(data);
      }
      break;
  }

  message.ack();
});

Step 2: Bi-Directional Sync Gateway

For integrating MaintainX with ERP systems (SAP, Oracle) where changes flow both ways.

ERP (SAP/Oracle) ←──→ Sync Gateway ←──→ MaintainX API
                          │
                    Conflict Resolution
                    + Audit Trail
                    + Sync State DB
// src/architecture/sync-gateway.ts

interface SyncRecord {
  externalId: string;     // ERP system ID
  maintainxId: number;    // MaintainX ID
  lastSyncAt: string;
  syncDirection: 'inbound' | 'outbound' | 'bidirectional';
  hash: string;           // Content hash for change detection
}

class SyncGateway {
  constructor(
    private maintainx: MaintainXClient,
    private erp: ERPClient,
    private db: SyncStateDB,
  ) {}

  // MaintainX → ERP
  async syncToERP(workOrder: any) {
    const existing = await this.db.findByMaintainxId(workOrder.id);

    if (existing && this.hash(workOrder) === existing.hash) {
      return; // No change, skip
    }

    const erpRecord = this.mapToERP(workOrder);
    if (existing) {
      await this.erp.update(existing.externalId, erpRecord);
    } else {
      const created = await this.erp.create(erpRecord);
      await this.db.create({
        externalId: created.id,
        maintainxId: workOrder.id,
        lastSyncAt: new Date().toISOString(),
        syncDirection: 'outbound',
        hash: this.hash(workOrder),
      });
    }
  }

  // ERP → MaintainX
  async syncFromERP(erpRecord: any) {
    const existing = await this.db.findByExternalId(erpRecord.id);
    const woData = this.mapFromERP(erpRecord);

    if (existing) {
      await this.maintainx.updateWorkOrder(existing.maintainxId, woData);
    } else {
      const created = await this.maintainx.createWorkOrder(woData);
      await this.db.create({
        externalId: erpRecord.id,
        maintainxId: created.id,
        lastSyncAt: new Date().toISOString(),
        syncDirection: 'inbound',
        hash: this.hash(created),
      });
    }
  }

  private mapToERP(wo: any) {
    return {
      title: wo.title,
      status: this.mapStatus(wo.status),
      priority: wo.priority,
      completedAt: wo.completedAt,
    };
  }

  private mapFromERP(erp: any) {
    return {
      title: erp.description,
      priority: erp.urgency === 'HIGH' ? 'HIGH' : 'MEDIUM',
    };
  }

  private mapStatus(status: string) {
    const map: Record<string, string> = {
      OPEN: 'PLANNED',
      IN_PROGRESS: 'ACTIVE',
      COMPLETED: 'FINISHED',
      CLOSED: 'ARCHIVED',
    };
    return map[status] || 'UNKNOWN';
  }

  private hash(obj: any): string {
    return require('crypto').createHash('md5')
      .update(JSON.stringify(obj)).digest('hex');
  }
}

Step 3: Analytics Data Pipeline

MaintainX API ──scheduled──→ Cloud Functions ──→ BigQuery
                                                    │
                                              Looker / Metabase
                                                    │
                                              KPI Dashboards:
                                              - MTTR (Mean Time to Repair)
                                              - PM Compliance %
                                              - Work Order Backlog
                                              - Asset Downtime
// src/architecture/analytics-pipeline.ts

interface MaintenanceKPIs {
  mttr: number;           // Mean Time to Repair (hours)
  pmCompliance: number;   // Preventive Maintenance compliance %
  backlog: number;        // Open work orders count
  completionRate: number; // Orders completed / orders created
}

async function calculateKPIs(client: MaintainXClient): Promise<MaintenanceKPIs> {
  const completed = await paginate(
    (cursor) => client.getWorkOrders({ status: 'COMPLETED', limit: 100, cursor }),
    'workOrders',
  );

  const open = await paginate(
    (cursor) => client.getWorkOrders({ status: 'OPEN', limit: 100, cursor }),
    'workOrders',
  );

  // MTTR: Average time from OPEN to COMPLETED
  const repairTimes = completed
    .filter((wo: any) => wo.createdAt && wo.completedAt)
    .map((wo: any) => {
      const created = new Date(wo.createdAt).getTime();
      const completed = new Date(wo.completedAt).getTime();
      return (completed - created) / 3600000; // hours
    });

  const mttr = repairTimes.length > 0
    ? repairTimes.reduce((a: number, b: number) => a + b, 0) / repairTimes.length
    : 0;

  // PM Compliance
  const pmOrders = completed.filter((wo: any) =>
    wo.categories?.includes('PREVENTIVE'),
  );
  const allPM = [...pmOrders, ...open.filter((wo: any) =>
    wo.categories?.includes('PREVENTIVE'),
  )];
  const pmCompliance = allPM.length > 0 ? (pmOrders.length / allPM.length) * 100 : 100;

  return {
    mttr: Math.round(mttr * 10) / 10,
    pmCompliance: Math.round(pmCompliance),
    backlog: open.length,
    completionRate: completed.length / (completed.length + open.length) * 100,
  };
}

Step 4: Multi-Site Architecture

Site A (Plant)           Site B (Warehouse)        Site C (Office)
  └── Local Agent           └── Local Agent            └── Local Agent
        │                         │                          │
        └─────────── Central Hub (Cloud Run) ────────────────┘
                          │
                    MaintainX API
                    (Org-level access)
// Central hub routing requests by site
const siteConfigs = {
  'plant-austin': { orgId: 'org-1', apiKey: process.env.MX_KEY_PLANT },
  'warehouse-dallas': { orgId: 'org-2', apiKey: process.env.MX_KEY_WAREHOUSE },
  'office-houston': { orgId: 'org-3', apiKey: process.env.MX_KEY_OFFICE },
};

function getClientForSite(siteId: string): MaintainXClient {
  const config = siteConfigs[siteId as keyof typeof siteConfigs];
  if (!config) throw new Error(`Unknown site: ${siteId}`);
  return new MaintainXClient(config.apiKey, config.orgId);
}

Output

  • Event-driven architecture with Pub/Sub for decoupled processing
  • Bi-directional sync gateway with conflict resolution and audit trail
  • Analytics pipeline calculating maintenance KPIs (MTTR, PM compliance)
  • Multi-site architecture with per-site API key isolation

Error Handling

PatternFailure ModeMitigation
Event-drivenPub/Sub delivery failureDead letter queue, retry policy
Bi-directional syncConflict on same recordLast-write-wins or manual resolution
Analytics pipelineIncomplete data fetchRetry with backfill, validate counts
Multi-siteOne site API key expiredIndependent health checks per site

Resources

Next Steps

For multi-environment setup, see maintainx-multi-env-setup.

Examples

SCADA integration (pulling sensor data into MaintainX work orders):

// Auto-create work order when equipment sensor exceeds threshold
async function handleSensorAlert(sensorId: string, value: number, threshold: number) {
  const asset = await findAssetBySensorId(sensorId);

  await client.createWorkOrder({
    title: `Sensor Alert: ${asset.name} - ${sensorId} exceeded threshold`,
    description: `Value: ${value} (threshold: ${threshold}). Auto-generated from SCADA.`,
    priority: value > threshold * 1.5 ? 'HIGH' : 'MEDIUM',
    assetId: asset.maintainxId,
    categories: ['CORRECTIVE'],
  });
}

What ships with it: 1 file

16.2 KB alongside SKILL.md

references/

Gives 0 of the 12 instructions most architecture codebase skills give in ~2.2k tokens

Counted across 858 of the 1,304 authors here whose files we hold, read 2026-09-06

  • Apply the deletion test to identify shallow modulesin 32 of 858, across 31 files
  • Read domain glossary and ADRs before exploringin 22 of 858, across 19 files
  • Use Tailwind and Mermaid via CDN for reportsin 21 of 858, across 18 files
  • Document architecture decision recordsin 20 of 858, across 12 files
  • Offer to record ADRs for rejected candidatesin 17 of 858, across 14 files
  • Limit primary navigation to four to seven itemsin 17 of 858, across 7 files
  • Write HTML report to the system temp directoryin 17 of 858, across 14 files
  • Read product marketing context before asking questionsin 16 of 858, across 6 files
  • Use Mermaid graph TD for visual sitemapsin 15 of 858, across 5 files
  • Ensure every page has at least one internal linkin 15 of 858, across 5 files
  • Use ASCII tree format for page hierarchy draftsin 15 of 858, across 5 files
  • Enforce lowercase URLs with hyphensin 15 of 858, across 5 files

Said here and by no other author read

  • Use webhooks for real-time event-driven updates
  • Implement scheduled jobs for data reconciliation
  • Publish webhook events to a message queue
  • Use a sync gateway for bi-directional data flow
  • Maintain an audit trail for all sync operations
  • Use content hashes to detect record changes

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.