-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Problem
billing and contact_persons currently live on the sponsor document (the global company record). This creates two issues:
- Billing details change between conferences. A sponsor may use different billing emails, PO numbers, or references from year to year. Storing billing on the global record means updating it overwrites the previous year's data.
- Contact persons rotate. The people handling a sponsorship often change between events. A sponsor's contact for 2025 may not be the same person for 2026, yet the current model only tracks one set of contacts globally.
Both fields are inherently per-engagement data and should live on sponsorForConference alongside the other relationship-specific fields (tier, status, contract value, etc.).
Proposal
Phase 1: Migrate billing to sponsorForConference
This is the clearest win — billing is strictly per-conference data.
Schema changes:
- Add
billingobject tosponsorForConferenceschema (same shape:email,reference,comments) - Keep the field on
sponsortemporarily for backwards compatibility
Migration:
- Write a Sanity migration that copies
sponsor.billing→sponsorForConference.billingfor all existing records - Only copy if
sponsorForConference.billingis not already set
Code changes (surface area):
src/lib/sponsor/sanity.ts— GROQ queries (3 occurrences) that projectbilling{}from sponsorsrc/lib/sponsor/types.ts—SponsorData,SponsorInput,SponsorUpdateInputinterfacessrc/server/schemas/sponsor.ts—BillingInfoSchema/CreateSponsorSchemasrc/app/(admin)/admin/sponsors/contacts/page.tsx— readsconferenceSponsor.sponsor.billingsrc/components/admin/sponsor/SponsorTierManagement.tsx— checkssponsor.sponsor.billingsrc/lib/conference/sanity.ts— GROQ query projectingbilling{}src/lib/tickets/api.ts—billingCrmquery
Phase 2: Migrate contact_persons to sponsorForConference
More nuanced — contacts have a dual role (global company directory vs. per-conference relationship).
Option A: Move entirely to sponsorForConference
- Simplest model, each engagement tracks its own contacts
- Downside: when creating a new conference entry for a returning sponsor, contacts must be copied or re-entered
Option B: Keep on sponsor as a global directory, add per-conference override on sponsorForConference
sponsorForConference.contact_personsoverridessponsor.contact_personswhen present- CRM and email operations read from the conference-level contacts
- Global contacts serve as defaults / address book for new engagements
- More complex but preserves the "company directory" use case
Code changes (surface area):
src/lib/sponsor/sanity.ts— GROQ queries (3 occurrences) projectingcontact_persons[]src/lib/sponsor/types.ts— type definitionssrc/lib/sponsor/audience.ts— Resend audience sync readscontact_personssrc/lib/sponsor/validation.ts— contact person validationsrc/server/schemas/sponsor.ts—ContactPersonSchemasrc/app/(admin)/admin/sponsors/contacts/page.tsx— readsconferenceSponsor.sponsor.contact_personssrc/app/(admin)/admin/api/sponsors/email/send/route.ts— reads contacts for sendingsrc/app/(admin)/admin/api/sponsors/email/audience/sync/route.ts— audience syncsrc/app/(admin)/admin/api/sponsors/email/discount/route.ts— discount code emailssrc/components/admin/sponsor/SponsorTierManagement.tsx— missing-contacts check
Cleanup
After migration is verified:
- Remove
billingfromsponsorschema (or mark deprecated) - If Option A for contacts: remove
contact_personsfromsponsorschema - Update
docs/SPONSOR_SYSTEM.mddata model section
Acceptance Criteria
-
billinglives onsponsorForConferenceand all reads/writes use it there - Decision made on contact_persons approach (Option A vs B)
- Contact persons accessible per-conference in CRM, email, and contacts pages
- Sanity migration script for existing data
- No regressions in sponsor email sending, audience sync, or contacts page
- Existing conference data preserved during migration
Dependencies
None — can be worked independently. Should be completed before #303 (contract signing) since contract emails will need per-conference contact data.