How to connect a QMS
Use this guide when the program’s controlled SOPs live in a QMS and Review should check work against the
version in force. You start with a program and a read-only integration user in the QMS; you end with a
connection in status connected, SOPs of source_kind = connector under Review › SOPs, and one
sop_versions row per version the QMS holds. Creating the connection needs program.connections.manage;
syncing needs program.connections.sync. The provider id is veeva_qualitydocs, category documents,
write policy read_only, default API version v26.2.
The connector is designed until the R1 gates pass. Until the partner’s sandbox and integration user
arrive it talks to the fake server api/scripts/fake_vault.py (port 8191), whose SOPs and versions are
labelled “Illustrative”. The QMS stays the SOP record; Trovensa never approves or edits a connector SOP.
Prerequisites
- A read-only integration user in the QMS whose profile covers the effective SOPs of the mapped document types and nothing else, plus its API credentials.
- The document type (and, if used, subtype and classification) that identifies SOPs in that QMS, and the lifecycle labels the QMS uses (they are configured per tenant and per lifecycle).
Create the connection
Setup › Connections › Add connection, provider QMS/SOP connector (veeva_qualitydocs). Enter the
tenant’s API host, keep api_version at v26.2 unless the partner says otherwise, set
scope_rules.document_types to the SOP type, and map the lifecycle labels to Trovensa’s states (draft,
in_review, effective, superseded, obsolete; anything else becomes unmapped). The record appears as
pending with poll_interval_seconds = 900.
Store the integration user’s credentials
Configure credentials stores the user name and password or API token under
<org_id>/connections/<connection_id>/<key>; the database holds references only. Every request carries the
client id header trovensa-review-connector-client-vault so the tenant’s usage log names Trovensa.
Run the health check
Check health authenticates, verifies the returned tenant id, validates each field of the per-connection
query template (SELECT id, name__v, document_number__v, major_version_number__v, minor_version_number__v, status__v, version_modified_date__v FROM ALLVERSIONS documents WHERE type__v = '<SOP type>'), checks that ALLVERSIONS is available and that every lifecycle label is mapped, and writes
the result to connection.health. Gaps are listed before the first sync; this check is the exit gate of the
connector’s release.
Run the first sync
Sync now runs the delta poll (version_modified_date__v > watermark). Each SOP becomes a sops row with
source_kind = connector, document_number, owner_text and applicability tags from the type, subtype
and classification; each version becomes a sop_versions row with major.minor, lifecycle_state,
effective_at (from the effective-date field, else first observation with effective_on_observed = true),
superseded_at, rendition_hash and external_version_label. The connection reads
connected; afterwards the worker polls every 15 minutes (poll_qms) and reconciles
nightly over ALLVERSIONS (reconcile_qms), throttled by the burst-limit and response-delay headers.
Check the versions page
Open Review › SOPs, choose an SOP and its Versions tab (GET .../review/sops/{sop_id}/versions,
needs review.sops.read). Only versions in state effective can bind checks; each shows
its requirement-set status (none until an extraction run proposes one) and, where the effective date was
inferred, the note “inferred from first observation”.
What happens when a new version becomes effective
The poll sees the new version, the worker enqueues review_extract_requirements and then review_sop_impact,
and holders of review.sops.manage receive a sop_changed notification. A system thread summarises the
change; QA accepts the proposed requirement set with a signature
(how-to) and approves the proposed re-check batch.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Health check lists an unmapped label | the QMS uses a lifecycle label the map does not name | add the mapping; versions in unmapped states stay ineligible and appear in health |
| A version shows no effective date | the tenant has no effective-date field on that type | the connector records first observation with effective_on_observed = true; bind checks manually with a reason when the work predates it |
POST .../review/sops/{sop_id}/approve answers 409 sop_external | the SOP comes from the connector | expected: the QMS is authoritative; accept the requirement set instead |
Sync stalls with rate_limited | burst limit reached | the worker honours X-VaultAPI-ResponseDelay and resumes; nothing to fix |
Related
- About SOP binding.
- Connectors for the version semantics and budgets.