Retire lp_profiles + LP Tracker; repoint Dashboard committed to the grid (v0.1.0:78)
The fundraising grid + email capture is the canonical system of record. lp_profiles was a superseded single-fund model with no reachable create/edit path, and the LP Tracker page was already orphaned (no nav entry + a redirect bouncing it to the grid). - Remove /api/lp-profiles* endpoints + handlers, the unused lp-breakdown report, the contact-dossier LP section, the demo-seed LP block, and (frontend) the LPTrackerPage component + its lp-tracker->fundraising-grid redirect. - Dashboard "Total Committed" now sums fundraising_investors.total_invested (graveyarded investors excluded) instead of the orphaned lp_profiles table, which read ~$0. "Total Funded" dropped: the grid tracks commitments, not a funded amount, and the frontend never rendered it. - Leave the empty lp_profiles table/index, the contact-delete soft-delete cascade, and the --reset-all-data clear in place (never-hard-delete). - Tests: add test_dashboard_report.py; update test_soft_delete_reads.py. 21/21 green.
This commit is contained in:
@@ -11,7 +11,7 @@ payload. The fix added `deleted_at IS NULL` to every get-by-id + nested sub-sele
|
||||
This boots the REAL server, hand-builds active + soft-deleted rows across the five
|
||||
soft-deletable tables, and drives the live HTTP read paths with a real token. It
|
||||
asserts: get-by-id 404s a soft-deleted contact/org, and nested sub-selects
|
||||
(org->contacts/opportunities, contact->communications/opportunities/lp_profile)
|
||||
(org->contacts/opportunities, contact->communications/opportunities)
|
||||
omit soft-deleted children while keeping the live ones. Synthetic only (guardrail #9).
|
||||
|
||||
Run: cd backend && python3 test_soft_delete_reads.py
|
||||
@@ -70,7 +70,7 @@ def seed():
|
||||
# organizations: one live, one soft-deleted
|
||||
c.execute("INSERT INTO organizations (id,name) VALUES ('orgA','Harbor & Vine')")
|
||||
c.execute("INSERT INTO organizations (id,name,deleted_at) VALUES ('orgX','Deleted Org',?)", (DEL,))
|
||||
# contacts under orgA: one live (with children), one soft-deleted, one live w/ deleted lp
|
||||
# contacts under orgA: one live (with children), one soft-deleted, one extra live (for org aggregates)
|
||||
c.execute("INSERT INTO contacts (id,first_name,last_name,organization_id) VALUES ('cLive','Ada','Live','orgA')")
|
||||
c.execute("INSERT INTO contacts (id,first_name,last_name,organization_id,deleted_at) VALUES ('cDead','Boris','Gone','orgA',?)", (DEL,))
|
||||
c.execute("INSERT INTO contacts (id,first_name,last_name,organization_id) VALUES ('cLp','Cora','Lp','orgA')")
|
||||
@@ -83,9 +83,6 @@ def seed():
|
||||
# communications on cLive
|
||||
c.execute("INSERT INTO communications (id,contact_id,communication_date,created_by,subject) VALUES ('cmLive','cLive','2026-05-01','u1','Live note')")
|
||||
c.execute("INSERT INTO communications (id,contact_id,communication_date,created_by,subject,deleted_at) VALUES ('cmDead','cLive','2026-05-02','u1','Dead note',?)", (DEL,))
|
||||
# lp_profiles: live one on cLive, soft-deleted one on cLp
|
||||
c.execute("INSERT INTO lp_profiles (id,contact_id,fund_name) VALUES ('lpLive','cLive','Fund III')")
|
||||
c.execute("INSERT INTO lp_profiles (id,contact_id,fund_name,deleted_at) VALUES ('lpDead','cLp','Fund III',?)", (DEL,))
|
||||
c.commit()
|
||||
c.close()
|
||||
|
||||
@@ -115,11 +112,6 @@ def main():
|
||||
opp_ids = {x["id"] for x in d.get("opportunities", [])}
|
||||
check("cmLive" in comm_ids and "cmDead" not in comm_ids, f"communications: live only (got {comm_ids})")
|
||||
check("opLive" in opp_ids and "opDead" not in opp_ids, f"opportunities: live only (got {opp_ids})")
|
||||
check(bool(d.get("lp_profile")) and d["lp_profile"].get("id") == "lpLive", "live lp_profile present on contact")
|
||||
|
||||
# soft-deleted lp_profile must read back as None (nested single-row sub-select)
|
||||
_, lpc = _get(port, "/api/contacts/cLp", token)
|
||||
check((lpc or {}).get("data", {}).get("lp_profile") is None, "soft-deleted lp_profile reads back as None")
|
||||
|
||||
# ── organization detail nested sub-selects exclude soft-deleted children ──
|
||||
print("\n[organization detail nested sub-selects]")
|
||||
|
||||
Reference in New Issue
Block a user