Dataverse

Legacy (read-only, narrow scope) — Dataverse (PowerCRM on Microsoft Dynamics 365) was RENEWA’s previous CRM. HubSpot Integration is the primary CRM today (Deal = Project). The Dataverse client remains live only for two read paths: bootstrapping document-obtaining collections from a PowerCRM project URL, and feeding PDF form data fields. There is no bi-directional sync and no building/project/contact import pipeline.

Architecture

ComponentPath
API clientbackend/src/lib/dataverse-client.ts (Power Apps URL parsing, OAuth client-credentials, project data retrieval)
Collection bootstrapbackend/src/services/collection-service.ts (createFromCrm, sanitization via sanitizeDataverseData)
PDF exportbackend/src/services/pdf-export-service.ts (Dataverse field schemas + project data for filled PDFs)
Import tracking (historical)dataverse_imports table — still in schema.ts, no runtime writers remain

Live Usage

  1. Document-obtaining collections from a CRM URL: an operator pastes a PowerCRM project URL (crmUrl) into the collection creation wizard (frontend/src/components/document-obtaining/CreateCollectionWizard.tsx). The backend parses the URL (parseDataverseUrl), fetches project, customer (contact or account) and representation data from the Dataverse Web API, sanitizes it, and pre-fills the collection. Responses are cached in Redis (CACHE_KEYS.dataverseProject) for reuse.
  2. PDF data fields: the admin PDF template builder can map form fields to Dataverse field schemas per environment (“Browse Dataverse Fields” in the admin UI); pdf-export-service.ts fetches schemas and project data to generate filled PDFs.

Configuration

SecretPurpose
DATAVERSE_API_URLDataverse Web API endpoint
DATAVERSE_CLIENT_ID / DATAVERSE_CLIENT_SECRETOAuth 2.0 client-credentials flow
DATAVERSE_TENANT_IDAzure tenant

Secrets live in Infisical (EU). The CRM-URL flows fail with a clear error when credentials are not configured (requireDataverseCredentials).

Polymorphic Lookup Quirks

Dataverse navigation properties are inconsistent: polymorphic lookups (PropertyOwner, InvoiceReceivingEntity) use the _shadow_contact / _shadow_account suffix, while non-polymorphic lookups (Representation) use just _shadow (e.g. pragdev_RepresentationId_shadow).

Historical Notes

  • “Dataverse-era” collections predate the HubSpot model and lack a quoteId; entity resolution for them converges on the project (see I#1802 discussion).
  • The earlier description of a full import pipeline (buildings/projects/contacts/companies into R1 tables, triggered from the Admin Dashboard and logged to dataverse_imports) no longer matches the code: dataverse_imports has no runtime writers, and CRM entity mirroring is HubSpot’s job.
  • The legacy JIRA seed import (db/seeds/scripts/jira-import.ts) no longer exists — the seeds/ directory was retired in favour of backend/src/db/mocks/.