The conversations we are forced to have
Most of the cost of this coupling never shows up as an incident. It shows up as guidance, the things support has to say to customers every week because the data model gives us no better answer. Each of these is a real, recurring script.
And the display-name workaround itself, step by step
One record, three jobs
Four account fields, first name, last name, phone, and email, seed the payment-verification flow directly today. Because the jobs share fields, the product must either sync them between contexts (and break when validity rules differ) or let them drift (and lose any source of truth). Both failure modes are shipping.
User account record, today
The trend line, three ways
Engineering issues and support volume, February 1 through July 23. The Jira count is a one-time sweep count and the ticket counts are Zoho subject-search floors: search caps and the process-absorbed workarounds above mean true volume is higher. July is a partial month in all three charts.
Coupling-family issues
Name-related tickets
Recipient / verification blocked
View the numbers as a table
| Month | Jira family issues | Name-change tickets | Recipient blocked |
|---|---|---|---|
| Feb | 2 | 18 | 30 |
| Mar | 6 | 15 | 20 |
| Apr | 2 | 19 | 24 |
| May | 6 | 29 | 41 |
| Jun | 12 | 42 | 47 |
| Jul (to 23rd) | 10 | 51 | 116 |
We are not inventing this model. We're the outlier without it.
Public name can be a nickname; the transfer name must be legal, match government ID and the bank exactly, and stays private. The exact two-track model this proposal describes, running at the major competitor.
The verified legal name is “internal compliance only” and never displayed on the profile. Verified attributes live out-of-band from public identity.
KYC lives on a separate account object the platform submits to. Prefilled onboarding data is treated as unconfirmed until the account holder verifies it, and a name mismatch (failed_name_match) disables payouts. Pre-filling verification from unverified profile data is a documented payout-blocking anti-pattern.
Individual vs company is a first-class fork industry-wide, with the company shape nesting a representative's personal name under the org's legal name. The recommended signup model below is the standard record shape, not an invention.
Formally separates identity proofing from authentication as independent assurance dimensions and calls the separation privacy-enhancing. The standards-body name for this decoupling.
Purpose limitation and data minimization: data collected for login/display must not silently become payout-verification data. The same principle, as law.
Three records, one locked link
One kind of account. Being a recipient is a role on a fundraiser, not a kind of account. Each record owns its own data, and nothing syncs.
User account
- Display name, freely self-editable, every change logged
- Email + phone for ownership, sign-in, OTP only
- Password, preferences
Fundraiser
- Withdrawal country: the recipient's country, chosen at creation; drives banking + verification; locked to match the processor
- ZIP/postal: the recipient's local area, for "nearby" discovery — where the recipient lives, not the creator
- Public display feeds from linked accounts: creator byline, recipient received-by
Recipient verification record
- Created fresh per fundraiser at payment connection
- We store only: legal or legal business name, email (locked), city/country, phone, banking
- Tax ID, DOB, street address: processor only. Never stored in our database
- Locked once verified. Never auto-filled from the account
Public “received by” precedence
Showing the verified business name publicly stays. It is a deliberate trust feature beyond what competitors show, and the no-DBA fallback becomes a first-class path instead of a privacy leak.
Every field, its job, its lifecycle
The full proposed data model: what each field is for, where it lives, where it shows, how it changes, and who verifies it. The most sensitive PII never enters our database. Rows marked "spec" are lifecycle details for the engineering spec session.
User account
| Field | Purpose | Stored | Shown | Changed | Verified |
|---|---|---|---|---|---|
| Account type | Individual or Organization/Group; sets the name shape | GSG DB | Indirectly, via name shape | Set at signup; conversion path: spec | — |
| Display name | The one public identity. Individual: first + last. Org: org/group name | GSG DB | Creator byline + received-by on every fundraiser in the account (disclosed at signup) | Self-serve, anytime; every change logged; history feeds verification review | Not verified (public, not legal, identity) |
| Owner/manager name | The human behind an org account | GSG DB | Never public; admin only | Self-serve; logged | Not verified |
| Ownership, sign-in, receipts; the identity anchor | GSG DB | Never public | Change-email flow; lock-match re-checked on change (spec) | Email verification | |
| Phone | OTP and account security only | GSG DB | Never public | Self-serve with OTP re-check | OTP |
| Password, preferences | Auth and settings | GSG DB | Never public | Self-serve | — |
| Retired fields | Organization Name, Country/State/City/ZIP, Social Media Link | Dropped; social link relocates to verification | — | — | — |
Fundraiser
| Field | Purpose | Stored | Shown | Changed | Verified |
|---|---|---|---|---|---|
| Withdrawal country | The recipient's country. Drives banking + verification; must match the processor | GSG DB | Fundraiser page location context | Locked at creation (warning already ships) | — |
| ZIP/postal code | The recipient's local area, for "nearby" discovery — where the recipient lives, not the creator | GSG DB | Fundraiser page location + nearby search | Set at creation; constrained to the withdrawal country; correction path when recipient ≠ creator: spec. Label + validation per-country from maintained address metadata ("ZIP" is US-only vocabulary); optional where a country has no postal system, with "nearby" falling back to city. Never a hand-rolled country list — that's the phone-component mistake in postal form | Not verified |
| Creator byline | Public "organized by" | Derived, not stored — creator's display name | Fundraiser page | Updates automatically when the creator renames | — |
| Received-by line | Public "funds go to" | Derived, not stored — display name → DBA → legal business name | Fundraiser page | Automatic per precedence; never free text | Business names from the verified record |
| Representing (optional) | Group/org/cause label | GSG DB | Alongside, never replacing, the names | Creator-editable | Not verified |
| Recipient link | Which account holds the recipient role | GSG DB | — | Add-recipient and invite flows | — |
Recipient verification record · fresh per fundraiser · Individual and Business/Org variants
| Field | Purpose | Stored | Shown | Changed | Verified |
|---|---|---|---|---|---|
| Legal name(s) | Individual: legal first + last. Business: legal business name + representative's legal name. Payout identity | GSG DB | Individual legal and representative names: never public. Legal business name: public in received-by once the business bank verifies with no DBA | Entered fresh; locked once verified; change = re-verification | Processor identity verification |
| DBA (business, optional) | Public-facing business name | GSG DB | Wins received-by when present | Pre-verification self-serve; after: support with audit (spec) | Processor |
| The identity anchor | GSG DB | Never public | Displayed from the account, locked to match, enforced server-side | Lock-match + account email verification | |
| Phone | Only where the processor requires it for the withdrawal country | GSG DB | Never public | Entered fresh in the recipient-country context | Per processor rules |
| City + country | The payout context the platform actually needs | GSG DB | Never public | Entered fresh; editable pre-verification | Processor |
| Banking | Payout destination | GSG DB (operational reference) | Never public; verified state flips the business-name display | Entered fresh; re-enterable after failed transfer (must-have fix) | Processor bank validation |
| Tax ID, DOB, street address | Identity proofing | Processor only — never in GSG's database | Never | Via processor flows | Processor |
| Social media link | Verification-support signal (relocated from account) | GSG DB (verification context) | Never public | Optional at verification time | Manual review aid |
What shape the display name takes
Recommended direction below. Final call belongs in the engineering spec session, and the decoupling is what makes that safe to defer.
Repurpose the dead Organization Name field
An account-wide override maps to all of a user's fundraisers. One account running a personal and an org fundraiser shows the wrong name on one of them.
Per-fundraiser display name
A third name mapping to build and maintain: overengineering. The optional per-fundraiser “Representing” label serves the group-name case, shown alongside identity, never replacing it.
Account type at signup
Individual: first/last name. Organization/Group: org name as the account name, with an owner/manager first/last nested in the record. Fixes the TS-464 class at the root, gives the no-DBA business case a sane public path, and matches the industry-standard record shape. Disclosed plainly at signup: this name is the public creator and received-by on every fundraiser the account creates or receives funds for.
What's already fixed, and why the gap remains
- DEV-1916: name validation relaxed (emoji, numbers, “and”, special characters no longer block)
- Three per-country phone fixes live: Hong Kong, Morocco, Benin
- GPD-117 + June recovery batch: many re-verification dead ends fixed
- DEV-1901: country-lock warning added at fundraiser creation
- Every fix patches a symptom of the shared-field model, one field, one country, one form at a time
- The phone component failed twice more in July after three patches, exactly as the developer's May 15 note predicted
- DEV-1896 is still failing at scale after the recovery-UX batch
- The name is still uneditable and the workaround is still five steps and a backend edit
What we're asking for in this meeting
Stop the bleeding
- Land TS-508, the phone-autofill removal, ticketed and in code review as of Aug 7 (the autofill stays in production until it deploys); freeze any extension of the behavior in the meantime
- Create the follow-up card the developer recommended May 15: migrate phone validation to the dynamic countries API
- Unlock recipient form state: allow returning to bank account type selection; re-present options after abandonment
- Ticket + fix the recipient-form SMS opt-in silent failure (August 7 observation)
The decoupling
- Three records, server-side email anchor, no cross-sync
- Self-serve display name with rename audit log
- Received-by precedence including the no-DBA path
- Migration path for existing records
- Proposal nice-to-haves: retire Organization Name and the account location block; relocate the social link to verification
The full evidence, one click deep
Nothing was cut to lighten the pitch — the complete timelines and tables live here for questions and the follow-up read. Every item traces to the full proposal document.
Phone — six incidents, one component, zero root-cause fixes
Every phone failure below comes from the same place: a phone input that validates against a static in-code country list and silently defaults to +1. Each fix patched one country. The component then failed for the next one.
A hardcoded “at least 10 digits” rule rejected valid numbers from the US, Canada, Australia, France, and Ghana. Caught by QA as a release blocker. The earliest instance of the exact failure shape that hit Trinidad in July.
US flag, prohibited symbol, even with an HK campaign country. Real customer blocked from recipient setup. Root cause: the phone component silently defaults to +1 with the country picker disabled. Fixed May 20, for Hong Kong only.
9-digit numbers cut to 8 across signup, profile, and every recipient form. Fixed May 22, for Morocco only.
The developer recommended a follow-up card migrating phone validation to the dynamic countries API “to ensure all phone-country mappings and masks continue to work.” No follow-up card appears in Jira.
The field stops at 8 digits; valid Benin numbers are 10. Both old and new formats rejected. Fixed June 9, for Benin only, with another per-country regex.
The June phone-autofill deploy (DEV-1661, flagged in comments before ship) pulled her Thailand security phone into a US-validated banking context and silently failed. She bought a US number to receive her own funds.
No phone input passed the Recipient Information form until the fix shipped Jul 27. While it was open, support's options were: wait indefinitely, or refund.
Email — the lock is right, the plumbing around it isn't
Locking the account email into the self-recipient flow was a deliberate April security decision, and it stays: that flow is strictly for the creator's own account, and third parties go through Invite a Recipient. The problems are everything built around the lock.
Account email locked into the business self-recipient flow, released April 29. Settled policy: self-flow is the creator's own account; third parties get invited.
A confusing-UX and defense-in-depth gap only: the server always persisted the canonical account email, so no data-integrity or account-takeover risk. Fixed June 2026 (DEV-1602, Done Jun 8) with a DOM-level lock plus explicit server-side 422 rejection of substituted emails.
The creator's email auto-populates when re-adding a recipient after deleting one, and recipient email mismatches between the payment processor and our admin with no activity-log record. In July, the legacy flow silently swallowed a failed user creation, orphaning a recipient record with no user account behind it and leaving duplicate user rows on the owner's email; engineering ruled out a migration regression (TS-476). A lock with no single source of truth behind it can't prevent drift.
An account email with multiple periods auto-filled into the locked recipient field, and the form's own validator rejected it. “Enter a valid email address,” on a field the user cannot edit. Completely blocked from receiving transfers.
Copy explaining that the creator's email will be used, instead of a data model that makes it impossible to be confused.
Created June 30, cancelled July 9. The card had been gated on email-lock architectural runway from the day it was filed. The coupling is now costing roadmap, not just tickets.
Name — a field nobody can safely touch
The account name is the public name is the verification name. So every edit is dangerous, every validation is invisible, and every privacy need becomes a project.
Still failing while we read this
| Stream | Impact | Status |
|---|---|---|
| DEV-1897 | 81 events Apr 30 – Jul 17: bank-account country from the recipient address form mismatches the country encoded in the IBAN. Multiple recipients. | Open — fix Ready for Deployment |
| DEV-1896 | 60 events since Jun 12 as of mid-July, 93% mobile: ID document re-upload failing on the recipient-address endpoint, “likely blocks ability to receive payouts.” | Open — fix Ready for Testing |
| TS-485 | Every Trinidad & Tobago recipient hard-blocked at the Recipient Information form for a week (Jul 21–27). | Resolved Jul 27 |
| TS-479 | Recipient DOB field accepts no input on any browser, device, or network. One customer tried a library computer. | Awaiting deploy |
| GPD-115 | Shipped on top of the coupled model. Built before the decoupling, it inherits the defect. | Done Jul 28 |
| GPD-120 / GPD-97 | Parking-lot cards that would build on GPD-115 inherit the defect the same way. Every future recipient-lifecycle card does until the decoupling lands. | Parking lot |
The account record today, field by field
A July 23 audit of signup and account settings.
| Field | What it does today | Verdict |
|---|---|---|
| First + Last Name | The only name the platform has. Sign-in identity, public name on every fundraiser, and a direct verification seed. | Triple duty |
| Account ownership and sign-in, and a verification seed via the email lock. The natural identity anchor, currently anchored wrong. | The one link | |
| Phone (required) | Account security and OTP, and since June auto-fills into country-validated banking forms. | Leaks into banking |
| Country / State / City / ZIP | Four location fields with no consumer the fundraiser's withdrawal country doesn't already cover. The major competitor carries no account-level location at all; it collects location per fundraiser, at creation. | No consumer |
| Organization Name | Collected at signup, shown in settings, maps to nothing anywhere in the product. | Dead field |
| Social Media Link | UI copy: “For quicker verification times enter a social media profile link.” An account field explicitly recruited for verification duty. | Verification duty |