Documentation Index
Fetch the complete documentation index at: https://docs.wellapp.ai/llms.txt
Use this file to discover all available pages before exploring further.
A workspace_connector is an activation record that binds a generic Connector definition to a specific workspace, creating a live, credentialed integration instance. It is the unit of auth lifecycle management: it carries the per-workspace OAuth credentials (access token, refresh token, DCR client ID) inside an optional JSONB config column, tracks the lifecycle status of the integration, and optionally links to the Person who owns or administers the connection. Every sync run, connector mapping, and sync diagnostic in the pipeline is scoped to a workspace_connector. It serves as the FK target for junction tables ({entity}_workspace_connectors, workspace_connector_sync_targets, workspace_connector_sync_logs) and is the sourceWorkspaceConnector provenance pointer on ingested entities.
| Naming | Value |
|---|
| Object | Workspace Connector |
Resource type (JSON:API type) | workspace_connector |
| Collection / records root | workspace_connectors |
| REST base | /v1/workspace-connectors |
| Entity class | WorkspaceConnector |
API operations
| Operation | Method & path | Status |
|---|
| List | GET /v1/workspace-connectors | ✅ Implemented |
| Retrieve | GET /v1/workspace-connectors/{id} | ✅ Implemented |
| Create | POST /v1/workspace-connectors | 🟡 Planned |
| Update | PATCH /v1/workspace-connectors/{id} | 🟡 Planned |
| Delete | DELETE /v1/workspace-connectors/{id} | 🟡 Planned |
Data model
Attributes
| Field | Type | Required | Constraints | Allowed values | Description |
|---|
| workspace_connector_id | string, UUID | ✅ Yes | unique, gen on onCreate via randomUUID() | — | Public-facing stable identifier for this connector instance. Used as the external reference in all API responses and OAuth state parameters. Generated at row creation; never changes. |
| status | string (StatusEnum) | ✅ Yes | native PG enum status_enum | enabled, disabled, to_configure, processing, error, need_reconnect, suspended | Current lifecycle state of the connector instance. enabled means tokens are valid and sync can run. need_reconnect indicates token expiry or revocation requiring user re-auth. processing is set during an active sync run. error indicates a non-recoverable failure. suspended indicates a billing- or admin-triggered pause. to_configure is the initial state before OAuth is completed. |
| config | jsonb, object | ⚪ No | nullable JSONB; never exposed in plaintext API responses without scrubbing | — | Per-workspace encrypted credential store. For MCP OAuth connectors holds: client_id (DCR-registered or pre-configured), client_secret, dcr_access_token, access_token, refresh_token, token_expires_at (ISO-8601 string), pkce_code_verifier (ephemeral, cleared after exchange), pkce_state (ephemeral). Also stores provider-specific runtime metadata (e.g. tenant name, scopes) written back by McpOAuthService after token exchange. For API-key connectors, stores api_key. For WSSE connectors, stores auth_wsse.username and auth_wsse.secret. |
| created_at | timestamp with time zone, 🔒 system | ✅ Yes | set once on onCreate; never updated | — | Row creation timestamp. Set by MikroORM lifecycle hook on insert. Immutable after creation. |
| updated_at | timestamp with time zone, 🔒 system | ⚪ No | set on onCreate and updated on every onUpdate | — | Last-modified timestamp. Updated by MikroORM lifecycle hook on every persist. Null only if the row has never been updated after insert (edge case). |
| deleted_at | timestamp with time zone | ⚪ No | nullable; soft-delete pattern — null means active | — | Soft-delete timestamp. When set, the connector instance is considered disconnected. All downstream queries filter deleted_at IS NULL to exclude soft-deleted connectors. A soft-deleted row preserves audit trail and is the trigger for token revocation on the provider side. |
Relationships
| Name | Type | Required | Description |
|---|
| connector | to-one (Connector) | ✅ Yes | The canonical connector definition this instance activates. Carries provider type, category/service IDs, authorization flow, transport type, auth_config (OAuth metadata URL, MCP server URL), and supported target models. A single Connector can have many workspace_connector activations across different workspaces. |
| workspace | to-one (Workspace) | ✅ Yes | The workspace that owns and operates this connector instance. Acts as the tenant boundary: every sync run, entity ingested, and sync target scoped to this workspace_connector is isolated within this workspace. |
| person | to-one (People) | ⚪ No | The person (workspace member) who owns or administered the connection. Optional — connectors created programmatically (e.g. via API key or admin seeding) may have no person owner. Indexed via idx_workspace_connectors_person. |
| filter (virtual) | to-one (ConnectorFilter) | ⚪ No | Virtual property — NOT a persisted FK column. Populated at query time by WorkspaceConnectorRepository. Resolves to either a custom ConnectorFilter for this workspace, or the template filter for the connector. Controls what data is ingested (e.g. date range, account scope). Not stored on the workspace_connectors table itself. |
| syncTargets (WorkspaceConnectorSyncTarget) — inverse reference | to-many (WorkspaceConnectorSyncTarget) | ⚪ No | Inverse reference — NOT declared as @OneToMany on WorkspaceConnector. WorkspaceConnectorSyncTarget declares @ManyToOne(() => WorkspaceConnector). Junction rows defining which target workspaces this connector ingests data into (added in Migration20260527140000). Each row links this connector to a target_workspace_pk. Partial unique index idx_wcst_unique_active prevents duplicate active targets. Backfilled with a 1:1 self-pointing row for all pre-existing connectors. |
| connectorMappings (ConnectorMapping) — inverse reference | to-many (ConnectorMapping) | ⚪ No | Inverse reference — NOT declared as @OneToMany on WorkspaceConnector. ConnectorMapping declares @ManyToOne({ entity: () => WorkspaceConnector, fieldName: 'workspace_connector_pk' }). The JSONata sync mapping configurations generated by the structured-jury pipeline for each target model (company, invoice, transaction, etc.). One mapping row per (workspace_connector, target_model). Holds the compiled JSONata expression, last_persist_count, and needs_regeneration flag. |
| syncDiagnostics (ConnectorSyncDiagnostic) — inverse reference | to-many (ConnectorSyncDiagnostic) | ⚪ No | Inverse reference — NOT declared as @OneToMany on WorkspaceConnector. ConnectorSyncDiagnostic declares @ManyToOne({ entity: () => WorkspaceConnector, fieldName: 'workspace_connector_pk' }). Diagnostic and observability rows emitted by the sync pipeline — jury runs, schema drift, mapping failures, regression reverts. Each row references this workspace_connector as the sync context. |
| syncLogs (WorkspaceConnectorSyncLog) — inverse reference | to-many (WorkspaceConnectorSyncLog) | ⚪ No | Inverse reference — NOT declared as @OneToMany on WorkspaceConnector. WorkspaceConnectorSyncLog declares @ManyToOne(() => WorkspaceConnector, { deleteRule: 'cascade' }). Sync execution log rows emitted per sync run. CASCADE-delete: all log rows are deleted when the parent workspace_connector row is hard-deleted. |
| documentWorkspaceConnectors (DocumentWorkspaceConnector) — inverse reference | to-many (DocumentWorkspaceConnector) | ⚪ No | Inverse reference — NOT declared as @OneToMany on WorkspaceConnector. Junction table tracking which documents were ingested by this connector, with direction discrimination (input vs output). Equivalent to the company/people/account/invoice/transaction junction tables; DocumentWorkspaceConnector declares @ManyToOne(() => WorkspaceConnector). |
System-computed
workspace_connector_id is generated via randomUUID() on the MikroORM onCreate hook — equivalent to gen_random_uuid() in Postgres.
created_at is set once on onCreate and is immutable. updated_at is refreshed on every onUpdate lifecycle call.
deleted_at follows the platform-wide soft-delete convention: null = active, non-null = soft-deleted. Downstream queries and Hasura RLS always filter deleted_at IS NULL.
config is a free-form JSONB column typed as Record<string, any> in the ORM. At runtime it is cast to McpOAuthWorkspaceConfig by McpOAuthService. The known sub-fields are: client_id, client_secret, dcr_access_token, access_token, refresh_token, token_expires_at, pkce_code_verifier (ephemeral — cleared after PKCE exchange), pkce_state (ephemeral — cleared after callback), plus provider-specific keys written back after token exchange (e.g. tenant info).
filter is a virtual (non-persisted) property. WorkspaceConnectorRepository resolves it at query time by finding either a workspace-scoped ConnectorFilter or the connector template filter. It does not correspond to any column on the workspace_connectors table.
- The internal
pk is an auto-increment integer used exclusively for FK joins. All public-facing references use workspace_connector_id (UUID).
- OAuth state tracking for PKCE flows:
McpOAuthService.getAuthorizationUrl() writes pkce_code_verifier and pkce_state into config before redirect; McpOAuthService.exchangeCodeForTokens() clears them and writes access_token, refresh_token, token_expires_at in their place.
- DCR (Dynamic Client Registration):
McpOAuthService.ensureClientRegistered() checks config.client_id before writing a new DCR client. Each workspace_connector gets its own OAuth client registered with the provider — DCR is per-workspace-connector, not per-connector-template.
- Token refresh buffer:
McpOAuthService refreshes when token_expires_at is within 5 minutes of expiry (enforced as an architectural constant).
- The junction tables
{entity}_workspace_connectors (company, people, account, invoice, transaction, document) reference workspace_connector_pk via FK — they track which connector ingested each entity row, with direction discrimination (input vs output).
workspace_connector_sync_targets was backfilled via Migration20260527140000 with a 1:1 self-pointing row for every active pre-existing connector to preserve legacy single-workspace ingestion semantics.
- Composite
idx_workspace_connectors_workspace_deleted on (workspace_pk, deleted_at) supports the hot-path workspace-scoped connector list query. Additional indexes on connector_pk, person_pk, and status support secondary traversals.
- The
WorkspaceConnectorSyncLog relationship carries deleteRule: 'cascade' on the child side — hard-deleting a workspace_connector row cascades to remove all associated sync log rows.
Example
{
"type": "workspace_connector",
"id": "a3c7e2b1-84f0-4d1e-9c3a-0f2b6d8e1a7c",
"attributes": {
"workspace_connector_id": "a3c7e2b1-84f0-4d1e-9c3a-0f2b6d8e1a7c",
"status": "enabled",
"config": {
"client_id": "well_dcr_abc123",
"dcr_access_token": "ey...",
"access_token": "ey...",
"refresh_token": "rt_xyz789",
"token_expires_at": "2026-06-02T18:00:00.000Z"
},
"created_at": "2026-02-14T10:23:00.000Z",
"updated_at": "2026-06-01T08:42:11.000Z",
"deleted_at": null
},
"relationships": {
"connector": {
"data": { "type": "connector", "id": "b8f1d3a2-5c20-4e6b-8d4a-1e9c7f3b2d01" }
},
"workspace": {
"data": { "type": "workspace", "id": "9f3e1c7a-2d44-4b8e-a1f5-0c6b3e9d7e42" }
},
"person": {
"data": { "type": "people", "id": "d4a2c8f0-1b35-4c7d-90e2-5f8a6b3c1d20" }
}
}
}
Source: apps/api/src/database/entities/WorkspaceConnector.ts · domain: ingestion · tier: Platform