Add temporary admin contacts-census diagnostic (v0.1.0:105)

A throwaway, admin-only diagnostic for the deferred contacts <-> fundraising_contacts
consolidation: GET /api/admin/contacts-census + a Settings -> Admin "Run census" button
report the A/B/C populations (linked / contacts-only / pill-only) plus the
communications/opportunities repointing surface. Counts only, no PII -- mirrors
backend/scripts/contacts_census.sql so the numbers can be read off the box without a
shell. All pieces are tagged TEMPORARY; delete the endpoint + route + button after the
census is captured. No schema change. 45/45 tests, render-smoke green.
This commit is contained in:
Keysat
2026-06-20 21:26:06 -05:00
parent 9ffd4a1c6a
commit 6e760b19ee
7 changed files with 84 additions and 6 deletions
+35
View File
@@ -2359,6 +2359,8 @@ class CRMHandler(BaseHTTPRequestHandler):
return self.handle_get_digest_policy(user)
if path == '/api/admin/soft-deleted':
return self.handle_list_soft_deleted(user)
if path == '/api/admin/contacts-census': # TEMPORARY — remove after the consolidation census
return self.handle_contacts_census(user)
if path == '/api/fundraising/relational-summary':
return self.handle_get_fundraising_relational_summary(user)
if path == '/api/fundraising/automations':
@@ -4868,6 +4870,39 @@ class CRMHandler(BaseHTTPRequestHandler):
finally:
conn.close()
# ─── TEMPORARY (v0.1.0:105) — DELETE AFTER the contacts<->fundraising_contacts census ──
# A throwaway admin diagnostic for the deferred consolidation (ROADMAP backlog): mirrors
# backend/scripts/contacts_census.sql so the A/B/C populations can be read from the box
# without shell access. Counts only — no names/PII. Remove this handler + its route + the
# Settings "Contacts census" button once the numbers are captured.
def handle_contacts_census(self, user):
if not require_admin(user):
return self.send_error_json("Admin required", 403)
conn = get_db()
try:
def n(sql):
return conn.execute(sql).fetchone()[0]
no_pill = ("NOT EXISTS (SELECT 1 FROM fundraising_contacts fc WHERE fc.contact_id = c.id)")
return self.send_json({"data": {
"total_live_contacts": n("SELECT COUNT(*) FROM contacts WHERE deleted_at IS NULL"),
"A_linked": n("SELECT COUNT(*) FROM contacts c WHERE c.deleted_at IS NULL "
"AND EXISTS (SELECT 1 FROM fundraising_contacts fc WHERE fc.contact_id = c.id)"),
"B_contacts_only": n(f"SELECT COUNT(*) FROM contacts c WHERE c.deleted_at IS NULL AND {no_pill}"),
"B_investor": n(f"SELECT COUNT(*) FROM contacts c WHERE c.deleted_at IS NULL AND c.contact_type='investor' AND {no_pill}"),
"B_prospect": n(f"SELECT COUNT(*) FROM contacts c WHERE c.deleted_at IS NULL AND c.contact_type='prospect' AND {no_pill}"),
"B_with_live_communication": n(f"SELECT COUNT(*) FROM contacts c WHERE c.deleted_at IS NULL AND {no_pill} "
"AND EXISTS (SELECT 1 FROM communications cm WHERE cm.contact_id=c.id AND cm.deleted_at IS NULL)"),
"B_with_live_opportunity": n(f"SELECT COUNT(*) FROM contacts c WHERE c.deleted_at IS NULL AND {no_pill} "
"AND EXISTS (SELECT 1 FROM opportunities o WHERE o.contact_id=c.id AND o.deleted_at IS NULL)"),
"C_pill_only": n("SELECT COUNT(*) FROM fundraising_contacts WHERE contact_id IS NULL"),
"dangling_pills": n("SELECT COUNT(*) FROM fundraising_contacts fc WHERE fc.contact_id IS NOT NULL "
"AND NOT EXISTS (SELECT 1 FROM contacts c WHERE c.id=fc.contact_id AND c.deleted_at IS NULL)"),
"total_grid_pills": n("SELECT COUNT(*) FROM fundraising_contacts"),
"total_grid_rows": n("SELECT COUNT(*) FROM fundraising_investors"),
}})
finally:
conn.close()
def handle_decide_activity_proposal(self, user, proposal_id, decision, body):
if not require_admin(user):
return self.send_error_json("Admin required", 403)