Summary
Add a status_match column to the opportunity table, auto-derived from the opportunity_volunteer rows.
Also auto-derive opportunity.status = opp-active when at least one volunteer is active.
Full status design
opportunity.status
| Value |
How set |
opp-new |
Default; also reset after 2 months of no card activity |
opp-searching |
Manually by coordinator |
opp-active |
Auto: when ≥1 opportunity_volunteer.status = opp-active |
opp-inactive |
Manually by coordinator (see #412) |
opportunity.status_match (new column)
| Value |
How derived |
vol-no-matches |
Default — no volunteers linked yet |
vol-pending-match |
≥1 opportunity_volunteer.status = opp-pending, none matched |
vol-matched |
≥1 opportunity_volunteer.status = opp-matched |
vol-past |
Active volunteer count < opportunity.number_volunteers (all gone past) |
Changes needed
1. Migration
await queryRunner.query(`
ALTER TABLE "opportunity"
ADD COLUMN IF NOT EXISTS "status_match"
"volunteer_status_match_enum"
NOT NULL DEFAULT 'vol-no-matches'
`);
2. Service logic — update status_match whenever opportunity_volunteer changes
When an opportunity_volunteer record is created or its status changes, recalculate and update the parent opportunity.status_match (and opportunity.status if needed).
Logic:
function deriveOpportunityStatusMatch(volunteers: OpportunityVolunteer[], numberNeeded: number) {
const active = volunteers.filter(v => v.status === 'opp-active').length;
const matched = volunteers.filter(v => v.status === 'opp-matched').length;
const pending = volunteers.filter(v => v.status === 'opp-pending').length;
if (active > 0 && active < numberNeeded) return 'vol-past'; // not enough active
if (matched > 0) return 'vol-matched';
if (pending > 0) return 'vol-pending-match';
return 'vol-no-matches';
}
opportunity.status auto-set to opp-active when active > 0.
Related
Summary
Add a
status_matchcolumn to theopportunitytable, auto-derived from theopportunity_volunteerrows.Also auto-derive
opportunity.status = opp-activewhen at least one volunteer is active.Full status design
opportunity.statusopp-newopp-searchingopp-activeopportunity_volunteer.status = opp-activeopp-inactiveopportunity.status_match(new column)vol-no-matchesvol-pending-matchopportunity_volunteer.status = opp-pending, none matchedvol-matchedopportunity_volunteer.status = opp-matchedvol-pastopportunity.number_volunteers(all gone past)Changes needed
1. Migration
2. Service logic — update status_match whenever opportunity_volunteer changes
When an
opportunity_volunteerrecord is created or its status changes, recalculate and update the parentopportunity.status_match(andopportunity.statusif needed).Logic:
opportunity.statusauto-set toopp-activewhenactive > 0.Related
statusMatchtoApiOpportunityGet