Public, unauthenticated flow that captures a referral code from the invite URL, passes it into the join form, and attributes a confirmed referral to the referrer upon successful registration.
- Every waitlist entry receives a unique referral code (format:
{slug(name)}-{4 random alphanum chars}, e.g.janedoe-x4n2). The referral URL ishttps://talkide.app/r/{code}. The generated code has aUNIQUEconstraint in the database; in the unlikely event of a collision, the BE must regenerate the code and retry the insert (up to 3 attempts). - The FE route
/r/:codecaptures the code and redirects to/waitlist?r={code}. The join form (UC-11001) picks up therquery parameter and passes it asreferred_by_codein the API request. - A referral is confirmed when a new entry is successfully persisted with
referred_by_idset to the referrer’s entry id. Referral attribution is recorded at join time — no additional confirmation step. - Each confirmed referral moves the referrer 50 spots closer to the front. The referral benefit is capped at
WAITLIST_REFERRAL_CAP = 10referrals (−500 spots maximum). Position floor is always 1. - Self-referral prevention: if the email being registered matches the referrer’s email (
referred_by_id.email == request.email), thereferred_by_idFK is set to null (referral not counted). This check is performed at insert time in the backend. - Edge case — invalid/unknown code: if
referred_by_codedoes not match any existingreferral_code, the join proceeds normally withreferred_by_id = null. No error is surfaced to the user. - The success screen includes a “Skip the queue” referral block with: the user’s own invite URL, a Copy button, and share intent buttons for Twitter, LinkedIn, and Email.
sequenceDiagram
actor User
User->>+FE: opens talkide.app/r/{code}
FE->>FE: extract referral code from URL
FE->>-User: redirect to /waitlist?r={code}
User->>+FE: /waitlist page loads with ?r={code}
FE->>FE: store referral code in component state <br> (will be sent as referred_by_code on submit)
FE->>-User: render join form (code is invisible to user)
User->>+FE: fills form and submits
FE->>+BE: POST /api/v1/waitlist <br> WaitlistJoinRequest (includes referred_by_code)
BE->>DB: lookup waitlist_entry WHERE referral_code = referred_by_code
alt code not found
BE->>BE: set referred_by_id = null (silent, no error)
end
alt registering email == referrer email (self-referral)
BE->>BE: set referred_by_id = null (self-referral blocked)
end
BE->>DB: INSERT waitlist_entry with referred_by_id
BE->>DB: recalculate referrer position <br> (confirmed_referrals count increases by 1)
BE->>-FE: 201 Created <br> WaitlistJoinResponse
FE->>-User: show success screen with position + referral block
Note over User,FE: Success screen — referral block
User->>+FE: clicks "Copy" on invite link
FE->>FE: copy talkide.app/r/{own_code} to clipboard
FE->>-User: button label changes to "Copied!" for 2s
User->>+FE: clicks share button (Twitter / LinkedIn / Email)
FE->>-User: opens share intent in new tab with prefilled text
Share Intent URLs
The FE constructs share intent URLs client-side. No backend call is needed.
Twitter / X:
https://twitter.com/intent/tweet?text=I+just+joined+the+TalkIDE+waitlist+%E2%80%94+build+apps+by+chatting+with+an+AI+team.+Jump+the+queue+with+my+link%3A+https%3A%2F%2Ftalkide.app%2Fr%2F{code}
LinkedIn:
https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Ftalkide.app%2Fr%2F{code}
Email:
mailto:?subject=Join+me+on+TalkIDE&body=Hey%2C+I+just+got+on+the+TalkIDE+waitlist+%E2%80%94+build+apps+by+chatting+with+AI.+Use+my+link+to+join+and+we%27ll+both+move+up+the+queue%3A+https%3A%2F%2Ftalkide.app%2Fr%2F{code}
All share buttons open in a new tab (window.open(url, '_blank')). No backend tracking of share clicks is implemented in this UC.
Referral Attribution — Position Impact
| Confirmed referrals | Position improvement | Cap hit? |
|---|---|---|
| 1 | −50 | No |
| 5 | −250 | No |
| 10 | −500 | Yes (cap reached) |
| 15 | −500 | Yes (capped at 10 × 50) |
Position is always recalculated live on each API call — it is not stored in the DB. As more people join the list, raw ranks shift and positions change.
UX Guidelines
User Flow
- Uživatel A (referrer) sdílí svůj odkaz ve tvaru
talkide.app/r/{code}— získal ho ze success screenu po registraci (viz UC-11001). - Uživatel B otevře referral URL
/r/{code}— FE extrahuje kód z URL a okamžitě přesměruje na/waitlist?r={code}. - Stránka
/waitlistse načte; referral kód je uložen do state komponenty. Pro uživatele B není viditelný — formulář vypadá identicky jako přímá cesta bez referralu. - Uživatel B vyplní formulář a odešle —
referred_by_codejede jako skrytý parametr v request body. - Po úspěšné registraci (201 OK) se zobrazí standardní success screen (UC-11001) s uživatelovou vlastní queue position a referral blokem “Skip the queue”.
Success screen — referral blok (součást UC-11001 success stavu):
- Uživatel vidí svůj unikátní invite link ve formátu
talkide.app/r/{code}— zobrazen v read-only řádku s Copy tlačítkem. - Kliknutí na Copy: text odkazu se zkopíruje do schránky. Tlačítko okamžitě změní text na “Copied!” a po 2 sekundách se vrátí na “Copy”.
- Kliknutí na Twitter: otevře se nová záložka s
twitter.com/intent/tweet?text=...(prefillovaný tweet s odkazem). - Kliknutí na LinkedIn: otevře se nová záložka s
linkedin.com/sharing/share-offsite/?url=.... - Kliknutí na Email: spustí defaultní mailový klient přes
mailto:s prefillovaným předmětem a tělem.
Layout
Referral flow nemá vlastní stránku — tato UC popisuje:
- Route handler
/r/:code— čistá redirect logika, žádné UI (max 300ms, žádný loading screen) - Referral blok v success screenu (součást UC-11001 success stavu) — vnořený
<div>uvnitř success karty
Referral blok (success karta, sekce “Skip the queue”):
- Container:
var(--bg-1)bg,var(--line-2)border, border-radius 14px (var(--r-lg)), padding 20px, text-align left - Nadpis řádek:
Boltikona 16pxvar(--amber)+ text 14px 500 “Skip the queue”, display flex gap 10px, margin-bottom 10px - Popis: 12px
var(--fg-3), line-height 1.5, margin-bottom 14px — “Share your invite link. Every friend who joins moves you 50 spots up.” - Invite link řádek:
var(--bg-2)bg,var(--line-2)border, border-radius 10px, padding 8px 10px; URL text font-mono 12pxvar(--fg-2)overflow hidden s text-overflow ellipsis; Copy button vpravo - Share tlačítka: flex row, gap 6px, margin-top 10px; 3 tlačítka (“Twitter”, “LinkedIn”, “Email”) každé
flex: 1
Komponenty
| Element | Komponenta / styl | Poznámka |
|---|---|---|
/r/:code route | FE router redirect | Žádné UI, čistý <Navigate to="/waitlist?r={code}" replace /> |
| Referral kód v state | Hidden state | Čten z useSearchParams() hook při mount /waitlist; nikdy se nerenduje jako input |
| Invite link URL | Read-only <span> | font-mono 12px var(--fg-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 |
| Copy tlačítko | <button> amber | var(--amber) bg, var(--primary-fg) text, 5px 12px padding, border-radius 7px, 12px 500; po kliknutí "Copied!" po dobu 2s |
| Twitter tlačítko | <button> ghost-light | var(--bg-2) bg, var(--line-2) border, border-radius 8px, 8px 10px padding, 12px var(--fg-2); window.open(url, '_blank') |
| LinkedIn tlačítko | <button> ghost-light | Stejný styl jako Twitter |
| Email tlačítko | <button> ghost-light | Stejný styl; otevírá mailto: (nevyžaduje novou záložku) |
Validační chování
- Referral kód z URL není validován na FE — cokoliv co přijde z
?r=parametru, jde slepě jakoreferred_by_codedo API. BE ho ignoruje pokud neexistuje nebo jde o self-referral. - Copy tlačítko: pokud je clipboard API nedostupné (HTTP kontext bez HTTPS — dev), catch chyby tiše; tlačítko zůstane aktivní bez “Copied!” feedbacku.
- Share URL je konstruována čistě klientsky z
referral_urlvráceného vWaitlistJoinResponse— žádný backend call.
Accessibility
- Copy tlačítko:
aria-label="Copy invite link"před kopírováním,aria-label="Copied!"po kopírování (2s); live regionaria-live="polite"pro screen readery - Share tlačítka:
aria-label="Share on Twitter"/"Share on LinkedIn"/"Share via Email";target="_blank"doprovázenorel="noopener noreferrer" - Invite link text: i přes vizuální zkrácení dostupný přes
titleatribut s plnou URL - Klávesová navigace: Copy → Twitter → LinkedIn → Email odpovídá Tab pořadí; všechna tlačítka focusovatelná
Loading a Error stavy
- Redirect
/r/:code→/waitlist: instantní, žádný loader; pokud router nějak selže, fallback na/waitlistbez?r=parametru (uživatel vidí čistý formulář) - Copy do schránky: sync operace; žádný loading stav — feedback je pouze změna textu tlačítka
- Otevření share URL:
window.openje synchronní; žádný loading stav; pokud prohlížeč popup zablokuje, nedělá se nic (uživatel je zodpovědný za povolení popupů)
Frontend
Validations
| Field | Constraints | Size | Pattern | Note |
|---|---|---|---|---|
referred_by_code (from URL ?r=) | optional | Passed silently to UC-11001 form submission; not validated on FE |
Backend
Validations
| Field | Constraints | Size | Pattern | Note |
|---|---|---|---|---|
| referred_by_code | optional | If provided: lookup referral_code in waitlist_entry. Not found → null. Self-referral → null. |
Test Cases
| GIVEN | WHEN | THEN |
|---|---|---|
| user opens /r/{valid_code} | route is hit | redirect to /waitlist?r={code}; form loads with code in state |
| user opens /r/{unknown_code} | route is hit | redirect to /waitlist?r={code}; join proceeds; referred_by_id set to null; no error |
| user opens /r/{code} and registers with a different email | join waitlist is called (UC-11001) | 201 Created; referred_by_id set; referrer’s confirmed_referrals count increases by 1 |
| user opens /r/{own_code} and registers with own email (self-referral) | join waitlist is called | 201 Created; referred_by_id set to null; referrer’s position unchanged |
| referrer has 10 confirmed referrals (cap reached) and gets an 11th | join waitlist is called for new registrant | 201 Created; referred_by_id stored; referrer’s position unchanged (cap enforced in position query) |
| user clicks Copy on invite link | copy button is clicked | referral URL copied to clipboard; button shows “Copied!” for 2 seconds |
| user clicks Twitter share button | share button is clicked | new tab opens with prefilled tweet text and referral URL |
| user clicks LinkedIn share button | share button is clicked | new tab opens with LinkedIn share intent |
| user clicks Email share button | share button is clicked | default mail client opens with prefilled subject and body |
FEEDBACK
Referral flow je v handoffu kompletně vyřešen jako součást UC-11001 success screenu — žádná dedikovaná stránka, žádné UX dohady. To je čisté. Co mi chybělo: chování při clipboard API failure (HTTPS požadavek) nebylo v handoffu ani v analytikově sekci zmíněno — přidal jsem silent fallback, ale bylo by dobré mít to explicitně potvrzené. Dále: handoff nespecifikuje animaci přechodu Copy → Copied (je to transition textu, nebo překlápění výšky?); v guidelines předpokládám čistou textovou záměnu.
Thanks for the feedback.