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.