Automated CRM Audit

Status: Production. Read-only.

Purpose

Assesses a HubSpot portal across seven operational domains and produces severity-classified findings, each carrying the count behind it and the population it was measured against. It reads the portal through the API and writes nothing back.

Cadence

A full run once a week, including the duplicate-detection pass, which is the expensive one. A light run every day for the figures that move. Each run is stored as a snapshot, so a number is compared against the same number a week earlier rather than recalculated and hoped about.

Audit modules

Seven modules, each producing independent findings:

PortalUsersCRM structureData qualityWorkflowsMarketingReporting

How duplicates are counted

Two passes. An exact pass over normalised values, and a near-match pass comparing names that requires the email domains to corroborate the match. The near-match pass is approximate by design and deterministic in practice: the same records produce the same pairs on every run. When the comparison budget is reached it reports the scan as truncated rather than quietly returning a smaller number.

What it will not claim

Where a figure cannot be measured in a period, the audit records why instead of emitting a zero. A duplicate count older than the rest of the report is labelled as such. A metric whose calculation has changed is presented as a fresh baseline rather than trended across the change.

Required HubSpot scopes

All read-only. The audit creates, updates and deletes nothing:

✓ settings.users.read✓ automation✓ forms✓ marketing-email✓ reports✓ cms.pages✓ crm.objects.contacts.read✓ crm.objects.companies.read✓ crm.objects.deals.read✓ crm.objects.owners.read✓ crm.lists.read✓ crm.schemas.contacts.read✓ crm.schemas.companies.read✓ crm.schemas.deals.read

Determinism

No part of the audit calls a language model. The service dependency set is better-sqlite3, express, googleapis and mysql2. The same portal state produces the same findings.

Technology

Node.js 20HubSpot API v3/v4Read-only scopesSQLite snapshots