| name | maintainx-reference-architecture |
| description | Production-grade architecture patterns for MaintainX integrations.
Use when designing system architecture, planning integrations,
or building enterprise-scale MaintainX solutions.
Trigger with phrases like "maintainx architecture", "maintainx design",
"maintainx system design", "maintainx enterprise", "maintainx patterns".
|
| allowed-tools | Read, Write, Edit |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
MaintainX Reference Architecture
Overview
Production-grade architecture patterns for building scalable, maintainable MaintainX integrations.
Prerequisites
- Understanding of distributed systems
- Cloud platform experience
- MaintainX API familiarity
Architecture Patterns
Pattern 1: Event-Driven Integration
┌─────────────────────────────────────────────────────────────────┐
│ MaintainX Platform │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Work Orders │ │ Assets │ │ Locations │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └─────────────────┼─────────────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Webhooks │ │
│ └──────┬──────┘ │
└───────────────────────────┼─────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────────┐
│ Your Integration Layer │
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ Webhook Handler│───▶│ Event Queue │───▶│ Event Processor│ │
│ │ (Express) │ │ (Redis/SQS) │ │ (Workers) │ │
│ └────────────────┘ └────────────────┘ └───────┬────────┘ │
│ │ │
│ ┌────────────────┐ ┌────────────────┐ ┌──────▼────────┐ │
│ │ API Gateway │───▶│ MaintainX Client│───▶│ Data Store │ │
│ │ (REST/GraphQL) │ (Cached) │ │ (PostgreSQL) │ │
│ └────────────────┘ └────────────────┘ └───────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────────┐
│ External Systems │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ ERP │ │ SCADA │ │ BI/Reports│ │ Slack │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└───────────────────────────────────────────────────────────────────┘
Pattern 2: Sync Gateway Architecture
interface SyncGatewayConfig {
pollInterval: number;
batchSize: number;
retryPolicy: RetryPolicy;
}
class MaintainXSyncGateway {
private client: MaintainXClient;
private cache: CacheManager;
private eventEmitter: EventEmitter;
private syncState: Map<string, Date>;
constructor(config: SyncGatewayConfig) {
this.client = new CachedMaintainXClient(new MaintainXClient());
this.cache = new CacheManager(process.env.REDIS_URL!);
this.eventEmitter = new EventEmitter();
this.syncState = new Map();
}
async (): <> {
: = {
: { : , : , : },
: { : , : , : },
};
.(result.);
.(result.);
result;
}
(: ): <> {
lastSync = ..() || ();
changes = ..({
: lastSync.(),
: ,
});
( wo changes.) {
local = ..(wo.);
(!local) {
..(wo);
stats.++;
..(, wo);
} ( (wo.) > (local.)) {
..(wo);
stats.++;
..(, wo);
}
}
..(, ());
}
(: ): <> {
pendingChanges = ..();
( change pendingChanges) {
{
(change.) {
:
..(change.);
stats.++;
;
:
stats.++;
;
}
..(change.);
} (error) {
.(, error);
}
}
}
(: , : ): {
..(event, handler);
}
}
Pattern 3: Multi-Tenant Architecture
interface Tenant {
id: string;
name: string;
maintainxApiKey: string;
maintainxOrgId?: string;
config: TenantConfig;
}
class MultiTenantMaintainXService {
private tenantClients: Map<string, MaintainXClient> = new Map();
private tenantStore: TenantStore;
async getClientForTenant(tenantId: string): Promise<MaintainXClient> {
if (this.tenantClients.has(tenantId)) {
return this.tenantClients.get(tenantId)!;
}
const tenant = await this.tenantStore.getTenant(tenantId);
if (!tenant) {
throw new Error(`Tenant not found`);
}
client = ({
: tenant.,
: tenant.,
});
..(tenantId, client);
client;
}
(
: ,
?:
): <[]> {
client = .(tenantId);
response = client.(params);
response.;
}
(): <<, >> {
counts = <, >();
tenants = ..();
.(
tenants.( (tenant) => {
client = .(tenant.);
response = client.({ : });
counts.(tenant., response..);
})
);
counts;
}
}
Pattern 4: CQRS with Event Sourcing
interface CreateWorkOrderCommand {
type: 'CreateWorkOrder';
payload: {
title: string;
description?: string;
priority: string;
assetId?: string;
};
metadata: {
userId: string;
timestamp: Date;
};
}
class CommandHandler {
private client: MaintainXClient;
private eventStore: EventStore;
async handle(command: CreateWorkOrderCommand): Promise<void> {
const workOrder = await this.client.createWorkOrder(command.payload);
await this.eventStore.append({
streamId: `workorder-${workOrder.id}`,
type: 'WorkOrderCreated',
: workOrder,
: command.,
});
..(, workOrder);
}
}
{
: ;
: ;
: ;
: ;
?: ;
?: ;
: ;
}
{
: ;
(: ): <> {
..({
: event..,
: event..,
: event..,
: event..,
: event..?.,
: event..?.,
: (event..),
});
}
(): <[]> {
..({ : });
}
}
Pattern 5: Microservices Integration
┌─────────────────────────────────────────────────────────────────────┐
│ API Gateway │
│ (Kong / AWS API GW) │
└─────────────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────┼─────────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
│ Work Order Service │ │ Asset Service │ │ Notification Svc │
│ │ │ │ │ │
│ ┌────────────────┐ │ │ ┌────────────────┐ │ │ ┌───────────────┐│
│ │MaintainX Client│ │ │ │MaintainX Client│ │ │ │ Slack/Email ││
│ └────────────────┘ │ │ └────────────────┘ │ │ └───────────────┘│
│ ┌────────────────┐ │ │ ┌────────────────┐ │ │ ┌───────────────┐│
│ │ PostgreSQL │ │ │ │ PostgreSQL │ │ │ │ Redis ││
│ └────────────────┘ │ │ └────────────────┘ │ │ └───────────────┘│
└─────────┬──────────┘ └─────────┬──────────┘ └─────────┬────────┘
│ │ │
└───────────────────────┼───────────────────────┘
│
┌───────▼───────┐
│ Message Bus │
│ (Kafka/RabbitMQ)│
└───────────────┘
Implementation Guidelines
Separation of Concerns
class WorkOrderDomain {
canTransitionTo(currentStatus: string, newStatus: string): boolean {
}
}
class WorkOrderService {
async completeWorkOrder(id: string, completionData: any): Promise<void> {
}
}
class MaintainXRepository {
async save(workOrder: WorkOrderEntity): Promise<void> {
}
}
Error Boundaries
class MaintainXIntegrationError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly retryable: boolean = false
) {
super(message);
this.name = 'MaintainXIntegrationError';
}
}
async function withErrorBoundary<T>(
operation: () => Promise<T>,
context: string
): Promise<T> {
try {
return await operation();
} catch (error: any) {
const status = error.response?.status;
if (status === 429) {
throw new MaintainXIntegrationError(
'Rate limited',
'RATE_LIMITED',
true
);
}
if (status >= 500) {
(
,
,
);
}
(
,
,
);
}
}
Output
- Event-driven architecture pattern
- Sync gateway for bi-directional sync
- Multi-tenant architecture
- CQRS with event sourcing
- Microservices integration
Architecture Decision Records
| Decision | Choice | Rationale |
|---|
| API caching | Redis | Fast, supports TTL, cluster mode |
| Message queue | Redis/SQS | Simple, reliable, scales well |
| Database | PostgreSQL | ACID, JSON support, mature |
| Event store | PostgreSQL | Simplicity over dedicated event store |
Resources
Next Steps
For multi-environment setup, see maintainx-multi-env-setup.