Skip to content

CRM & Data Integration — App Connect

Language: Java (JDK 25)
Framework: Spring Boot 4.0.6
Integration Engine: Apache Camel 4.20
Source: ~/IdeaProjects/NHDS/app-connect

Purpose

App Connect is the integration gateway between Nexivo and external business systems — CRMs, practice management platforms, ITSM tools, and any system with a REST API. It abstracts authentication, credential management, and route execution behind a unified API, allowing new integrations to be added without code changes.


Supported Integrations

Platform Category Auth Notes
HubSpot CRM OAuth2 / API Key Contacts, deals, tickets
Dentally Practice Management API Key / Token Appointments, patients
ServiceNow ITSM MCP (Model Context Protocol) Incidents, service requests
Salesforce CRM OAuth2 Contacts, cases
Any REST API Generic Basic / API Key / OAuth2 / Token Via OpenAPI spec upload

New integrations are registered by uploading an OpenAPI spec — no code deployment required.


Architecture

graph TB
    AD[Agent Desktop] -->|REST| AC[App Connect Service]
    AC -->|Camel Routes\nYAML-DSL| HubSpot
    AC -->|Camel Routes\nYAML-DSL| Dentally
    AC -->|MCP| ServiceNow
    AC -->|Camel Routes\nYAML-DSL| Other[Any REST API]

    subgraph AC[App Connect Service]
        API[REST API\nControllers]
        CM[Camel Route\nManager]
        AF[Auth Filters\nBasic / ApiKey / OAuth2 / Token]
        KK[Keycloak OAuth2\nClient Provisioning]
        DB[(PostgreSQL)]
        Cache[(Redis)]
    end

Core Concepts

App

An App is a master template for an integration (e.g. "HubSpot"). It defines: - Base URL (uri) - Default authentication config - OpenAPI spec for the external system - Available resources and queries - Optional MCP config (for MCP-based integrations like ServiceNow)

App Connector

An App Connector is a per-tenant instance of an App. Each tenant has their own connector with their own credentials and URI override. Multiple tenants can connect to the same App independently.

Resource & Resource Query

A Resource maps to an entity in the external system (e.g. contacts, appointments). A Resource Query is a specific operation on that resource (e.g. search-by-phone, create-appointment), defined as a Camel YAML route.


Data Model

apps — Integration templates

Field Description
uuid Unique app identifier
name, description Display metadata
url Default base URL
auth_config JSONB — default auth (overridable per connector)
openapi_spec OpenAPI 3.0 schema for the external system
mcp_config JSONB — MCP server config (ServiceNow, etc.)

app_connectors — Per-tenant instances

Field Description
id UUID primary key
app_id FK → apps
tenant_id Multi-tenant isolation
uri Connector-specific base URL
auth_config JSONB — overrides app-level auth
status PENDING, ACTIVE, ERROR
client_id, client_secret Keycloak OAuth2 credentials (auto-provisioned)

resources — External entities

Field Description
alias Kebab-case identifier (e.g. contacts)
schema JSONB — OpenAPI schema for this resource
config Resource-level configuration

resource_queries — Operations on resources

Field Description
alias Kebab-case identifier (e.g. search-by-phone)
config Camel YAML route definition for this query

mcp_servers — MCP integration instances

Field Description
tenant_id Multi-tenant isolation
server_url, token_url MCP server endpoints
access_token, refresh_token OAuth2 tokens
allowed_tools JSONB — tool whitelist
agent_id Associated AI agent

Authentication

App Connect supports four authentication strategies, applied per connector:

Type Class Mechanism
Basic Auth BasicAuthFilter Authorization: Basic <base64(user:pass)>
API Key ApiKeysAuthFilter Custom header (e.g. X-API-KEY)
OAuth2 OAuth2Filter Full OAuth2 flow with auto token refresh
Token TokenAuthFilter Static bearer token, custom header, or query param

Auth config is stored as JSONB in app_connectors.auth_config. On connector creation, an OAuth2 client is automatically provisioned in Keycloak (AppConnectorCreatedListener).


Query Execution Flow

sequenceDiagram
    participant Desktop as Agent Desktop
    participant AC as App Connect
    participant Camel as Camel Route
    participant Ext as External System

    Desktop->>AC: GET /app-connectors/{id}/resources/{alias}?q={queryAlias}&param=value
    AC->>Camel: ensure route loaded (direct:{resourceAlias}-query-{queryAlias})
    AC->>Camel: ProducerTemplate.request(routeId, params)
    Camel->>Camel: AuthUtils.resolveHeaders(authConfig)
    Camel->>Ext: HTTP call with auth headers + params
    Ext-->>Camel: Response
    Camel-->>AC: Transformed response
    AC-->>Desktop: JSON result

Camel routes are defined as YAML DSL in resource_queries.config. They are loaded dynamically at startup and reloaded on connector changes (ConnectorRoutesChangedEvent).


REST API

App Connectors

Method Path Purpose
GET /app-connectors List all connectors for tenant
POST /app-connectors Create connector (multipart: config, openapi-spec, logo)
GET /app-connectors/{id} Get connector details
PUT /app-connectors/{id} Update connector config
DELETE /app-connectors/{id} Delete connector
PUT /app-connectors/{id}/openapi Upload / update OpenAPI spec
POST /app-connectors/{id}/resources-refresh Reload Camel routes

Resource Queries

Method Path Purpose
GET /app-connectors/{id}/resources List resources
GET /app-connectors/{id}/resources/{alias} Execute default query
GET /app-connectors/{id}/resources/{alias}?q={queryAlias} Execute specific query
GET /app-connectors/{id}/resources/{alias}/schema Get OpenAPI schema for resource
GET /app-connectors/{id}/resources/{alias}/queries List available queries

MCP Servers

Method Path Purpose
POST /mcp-servers Register MCP server
GET /mcp-servers List MCP servers for tenant
DELETE /mcp-servers/{id} Delete MCP server
GET /mcp-servers/discover?serverUrl=... OAuth discovery
POST /mcp-servers/register-client Dynamic OAuth client registration

Adding a New Integration

  1. Upload the external system's OpenAPI spec via POST /apps or PUT /app-connectors/{id}/openapi
  2. Define resources (entities) and resource queries (operations) with Camel YAML route configs
  3. Configure authentication (Basic / API Key / OAuth2 / Token)
  4. Create a per-tenant connector via POST /app-connectors
  5. Query the integration via GET /app-connectors/{id}/resources/{alias}?q={queryAlias}

No code changes or redeployment required for new integrations.


Multi-Tenancy

  • tenant_id column on all connector and MCP server records
  • X-Tenant-ID request header resolved by HttpHeaderTenantResolver
  • TenantContextHolder enforces tenant scoping on all queries
  • Each tenant's OAuth2 credentials are isolated in their own Keycloak organisation

External Dependencies

Dependency Purpose
PostgreSQL Connector config, resources, queries, MCP servers
Redis Caching
Apache Camel Dynamic route execution for external API calls
Keycloak OAuth2 client provisioning per connector
Tool Management Service Syncs OpenAPI specs for AI tool registration
OpenTelemetry / Prometheus Observability