Domain Model: Sponsorship System
Domain Model: Sponsorship System
Diagram
Components
| Component | Purpose | Notes |
|---|---|---|
| Sponsor | Single model serving both CRM pipeline and presentation layer | SQLAlchemy model in basketball-api. Current schema has CRM fields; presentation fields (tier, logo, display_on_site) pending extension. |
| SponsorStatus | Pipeline stages: prospect → contacted → responded → negotiating → committed → declined | Postgres enum. Drives outreach workflow and blast targeting. |
| SponsorCategory | Business type classification for targeted pitches | 9 values: food, financial, retail, automotive, construction, fitness, dental, grocery, other |
| SponsorTier | Commitment level defining deliverables and pricing | Pending enum: title ($5K+), elite ($2.5K), team ($1K), social ($500), player_sponsor ($300-1.2K), community_partner (in-kind) |
| EmailLog | Audit trail for all sponsor outreach sends | Existing model, extended with EmailType.sponsor_outreach |
| MJML Template | Branded outreach email with category-targeted pitch | sponsor-outreach.html on hostPath. Placeholders: business_name, pitch, sender_name, sender_phone, sponsorship_tiers |
| Sponsors Page | Public landing page displaying committed sponsors | Currently hardcoded Svelte. Future: renders from GET /sponsors?display_on_site=true |
Key Decisions
- Single model, dual purpose. One Sponsor row serves both outreach CRM (status pipeline, blast targeting) and presentation (tier, logo, website for landing page). Avoids a second table and a sync problem. Status=committed + display_on_site=true is the boundary between CRM and display.
- Tier deliverables are documented, not modeled. Each tier's obligations (jersey logo, IG posts, event banners) live in the westside-sponsors pal-e-docs note, not in a database table. At current scale (3 sponsors), Marcus reads the tier checklist. Deliverable tracking model deferred until 10+ committed sponsors.
- Category pitches are code, not data. CATEGORY_PITCHES dict in sponsor_service.py is developer-managed. Marcus can override per-sponsor via custom_pitch field. Keeps pitch text versionable and reviewable in PRs.
- Rate limiting is synchronous. time.sleep(3) between sends. Acceptable for current volume (~50 sponsors). Async blast is a future optimization if volume exceeds Gmail daily limits.
- Tier enum includes community_partner. In-kind sponsors (product exchange, no cash) are first-class in the model. amount_committed is nullable to support this.
Related
westside-sponsors— canonical sponsor reference (tiers, active sponsors, lifecycle)arch-domain-westside-basketball— parent domain model (Tenant, Player, Parent entities)arch-email— email system architectureproject-westside-agency— sponsor-agent is pathway #8board-westside-sponsors— kanban board for sponsor work