-- Grid → Pipeline adoption — a durable link from a fundraising-grid investor to its -- Pipeline opportunity row. -- -- ADDITIVE + REVERSIBLE (CLAUDE.md guardrail #3): adds one nullable column + index. -- Until now the grid's "Create Opportunity" button fired a one-shot POST with no -- back-reference, so a grid investor could spawn unlimited duplicate opportunities and -- an opp never knew which grid row it belonged to. opportunities.fundraising_investor_id -- records the link (set by the new POST /api/fundraising/pipeline/link endpoint), making -- the relationship dedup-able and reconcilable. "Is this investor in the pipeline?" and -- "what stage?" are then DERIVED from a live join on this column — deliberately not a -- denormalized mirror flag on fundraising_investors, which would only reintroduce the -- two-model drift this CRM exists to fight. -- -- fundraising_investor_id is a LOGICAL foreign key to fundraising_investors(id). It is -- intentionally NOT a declared SQLite FOREIGN KEY: opportunities are soft-deleted (never -- hard-deleted) and fundraising_investors rows are rebuilt on every grid save, so there -- is nothing to cascade; SQLite's ALTER TABLE ADD COLUMN cannot add an enforced FK -- cleanly anyway. Nullable so every existing opportunity stays valid — a manually-created, -- non-grid opportunity simply has NULL here. ALTER TABLE opportunities ADD COLUMN fundraising_investor_id TEXT; CREATE INDEX IF NOT EXISTS idx_opportunities_fr_investor ON opportunities(fundraising_investor_id);