Tento dokument specifikuje founder-gated invite cascade pro TalkIDE alpha. Systém umožňuje Mirkovi (founder) manuálně kontrolovat rychlost růstu uživatelské základny synchronně s kapacitou Anthropic API tieru. Vychází z rozhodnutí v ADR-020.
1. Founder-Controlled Cascade
Kaskáda probíhá ve fázích dle reálné kapacity platformy:
[Founder — Mirek] přes admin tool
│
│ Fáze 1: vygeneruje 5–10 invite tokenů (founder-direct seeding)
▼
[Gen 0: Seeded users]
invites_granted = 0 (nemohou ještě nikoho zvát)
│
│ Fáze 2: Mirek vidí v dashboardu "máme rezervu"
│ → bulk grant: každý Gen 0 dostane 3 invites
▼
[Gen 0 pozve Gen 1]
~30 nových userů v dávce (záleží na aktivitě Gen 0)
│
│ Fáze 3: Mirek monitoruje load
│ → postupně grantuje další invites Gen 0 + Gen 1
▼
[Gen 1 pozve Gen 2]
... atd.
Klíčový princip: invites NEJSOU udělované automaticky na základě žádného triggeru. Mirek rozhoduje ručně — capacity recommender (viz sekce 4) mu dává doporučení, ale finální rozhodnutí je vždy na něm.
2. DB Schema
2.1 Tabulka invites
CREATE TABLE invites (
id BIGSERIAL PRIMARY KEY,
token VARCHAR(64) UNIQUE NOT NULL, -- UUID v4
issued_by_user_id BIGINT REFERENCES users(id), -- NULL = founder-direct seeding
issued_to_email VARCHAR(255), -- optional pre-binding na email
claimed_by_user_id BIGINT REFERENCES users(id),
issued_at TIMESTAMPTZ NOT NULL,
expires_at TIMESTAMPTZ NOT NULL, -- default: issued_at + 30 dní
claimed_at TIMESTAMPTZ,
revoked_at TIMESTAMPTZ,
revoked_reason TEXT,
status VARCHAR(20) NOT NULL -- PENDING | CLAIMED | EXPIRED | REVOKED
);
CREATE INDEX idx_invites_token ON invites (token);
CREATE INDEX idx_invites_status ON invites (status);
CREATE INDEX idx_invites_issued_by ON invites (issued_by_user_id);
issued_by_user_id = NULL identifikuje founder-direct tokeny (Fáze 1 seeding). Tyto tokeny
nemají “generaci” zdroje — jsou kořenem kaskády.
2.2 Tabulka user_invite_quota
CREATE TABLE user_invite_quota (
user_id BIGINT PRIMARY KEY REFERENCES users(id),
invites_total INT NOT NULL DEFAULT 0,
invites_used INT NOT NULL DEFAULT 0,
last_grant_at TIMESTAMPTZ
);
invites_remaining = invites_total - invites_used. Uživatel může vytvořit invite jen pokud
invites_remaining > 0.
2.3 Tabulka invite_grants (audit log)
CREATE TABLE invite_grants (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id),
granted_by_admin_id BIGINT NOT NULL REFERENCES users(id),
count INT NOT NULL,
reason TEXT, -- volný text, např. "30 days active, Gen 0 batch"
granted_at TIMESTAMPTZ NOT NULL
);
Každý admin grant je auditovaný. Umožňuje dohledat “kdo, komu, kolik, proč”.
2.4 Rozšíření tabulky users
ALTER TABLE users
ADD COLUMN invite_generation INT NOT NULL DEFAULT 0;
-- 0 = founder-seeded (Gen 0), 1 = pozváni Gen 0, 2 = pozváni Gen 1, atd.
Generace se nastaví při claimu invite: generation = issuer.invite_generation + 1.
Founder-direct tokeny mají issued_by_user_id = NULL → nový user dostane generation = 0.
3. Admin Tool Requirements
Admin tool je web view (admin-only route v talkide-fe, dostupná jen pro role ADMIN)
nebo CLI script jako fallback pro alpha. Obsahuje čtyři panely.
3.1 Users panel
| Sloupec | Zdroj | Poznámka |
|---|---|---|
| users.email | ||
| Generation | users.invite_generation | |
| Joined at | users.created_at | |
| Last active | konverzace nebo session timestamp | |
| Weekly spend | sum(api_usage.cost_cents) / aktuální týden | live |
| Invites remaining | user_invite_quota.invites_total - invites_used |
Akce:
- Bulk select + grant invites: vybrat N userů → zadat count + reason →
INSERT invite_grants- update
user_invite_quota.invites_total
- update
- Per-user revoke invites: snížit
invites_total(nezruší již odeslaná PENDING pozvání) - Suspend: dočasné zablokování přístupu (bez smazání dat)
- Ban: permanentní revoke + flagging
3.2 Invites panel
| Funkce | Popis |
|---|---|
| Generate founder-direct tokens | Vytvoří N invite záznamů s issued_by_user_id = NULL; výstup = tokeny pro ruční distribuci |
| List pending invites | Filter: PENDING / CLAIMED / EXPIRED / REVOKED |
| Per-token detail | Kdo pozval, komu, kdy vydáno, kdy claimed |
| Audit trail | Timeline: vydání → claim → případný revoke |
3.3 Capacity dashboard
Hlavní rozhodovací plocha pro growth management:
| Widget | Zdroj dat |
|---|---|
| Weekly spend progress bar | global:monthly_used_cents (Redis, live) |
| Active users this week (WAU) | COUNT DISTINCT user_id z api_usage / posledních 7 dní |
| Pending outstanding invites | COUNT invites WHERE status = ‘PENDING’ |
| Capacity recommender | Algoritmus z sekce 4 |
Barvy progress baru kopírují Mara fatigue palette: zelená (< 50 %), žlutá (50–70 %), oranžová (70–85 %), červená (> 85 %).
3.4 Mara analytics (read-only)
Podporuje PM rozhodování o budgetu a invite grantech:
| Metrika | Výpočet |
|---|---|
| Top spenders this week | TOP 10 users BY sum(cost_cents) za 7 dní |
| Cache hit rate | sum(cache_read_tokens) / sum(input_tokens + cache_read_tokens) |
| Avg cost per session | avg cost per conversation_id |
| Outliers | Uživatelé s 3× vyšším spend než medián za týden |
| Model distribution | % requestů na Sonnet vs. Haiku (proxy pro fatigue distribution) |
4. Capacity Recommender Algorithm
Algoritmus běží na FE (pure výpočet z dat panelu) — nedává binding rozhodnutí, dává doporučení pro Mirka.
headroom = (weekly_budget - current_weekly_spend) / weekly_budget
projected_new_spend = avg_weekly_spend_per_active_user × pending_outstanding_invites × 0.6
-- 0.6 = odhad WAU rate nových userů (konzervativní)
if headroom > 0.50 AND (current_weekly_spend + projected_new_spend) < 0.70 × weekly_budget:
zobraz: "Bezpečné rozdat 30+ invites — kapacita je dostatečná"
elif headroom > 0.30:
zobraz: "Rozdat 10–15 invites — monitorovat přes víkend"
elif headroom > 0.15:
zobraz: "POZOR: max 5 invites — jsme blízko capacity cap"
else:
zobraz: "STOP: žádné nové invites — nejdřív tier upgrade"
Výstup je barevně odlišen (zelená / žlutá / oranžová / červená) a zobrazuje konkrétní čísla (current headroom %, projected WAU po grantu, days to cap).
5. Anti-Abuse Rules
5.1 Per-user pending limit
Max 5 PENDING invites současně na jednoho uživatele. Pokud user má 5 nevyžádaných tokenů
a chce vytvořit další, BE vrátí 422 s INVITE_PENDING_LIMIT error kódem. Uvolní se až
po claimu nebo expiry existujícího tokenu.
5.2 Burner email blocklist
Při claimu invite BE ověří email invitee proti blocklist doménám (10minutemail, mailinator,
guerrillamail, throwam.com a ~100 dalších). Claim na burner doménu → 422 INVITE_BURNER_EMAIL.
Blocklist uložen v application.yml (nebo externím config souboru) — aktualizovatelný bez kodu.
5.3 IP rate limit na claim
Max 3 invite claims z jedné IP adresy za 24 hodin. Implementováno v gateway vrstvě
(Spring Security nebo rate-limit filter). Překročení → 429 INVITE_IP_RATE_LIMIT.
Cíl: zamezit bulk signupům přes proxy/VPN s rotujícími tokeny.
5.4 Rapid invite notification
Pokud uživatel odešle 5 invites za méně než 1 hodinu → automatická notifikace adminovi (email + dashboard flag). Není automatický block — Mirek rozhodne, jestli je to legitimní.
6. Signup Flow s Invite Tokenem
[User] obdrží invite link: https://talkide.app/join?token=<UUID>
│
▼
[FE] GET /api/invites/validate?token=<UUID>
├── 200 OK: { valid: true, issued_to_email: "..." nebo null }
├── 404 NOT_FOUND: token neexistuje
├── 410 GONE: token CLAIMED nebo REVOKED
└── 422 EXPIRED: token expiroval
│
▼ (pokud valid)
[FE] zobrazí signup form (email prefill pokud issued_to_email != null)
│
▼
[User] vyplní email + heslo → Submit
│
▼
[FE] POST /api/auth/signup-with-invite
body: { token, email, password }
│
▼
[BE]
1. Znovu validuje token (atomicky, SERIALIZABLE transakce)
2. Ověří email není burner
3. Vytvoří users záznam (invite_generation dle issuer)
4. Aktualizuje invite: status = CLAIMED, claimed_by_user_id, claimed_at
5. Aktualizuje user_invite_quota.invites_used pro issuera (+1)
6. Vrátí JWT token (přihlášený)
7. Future Extensions (post-alpha)
Tyto funkce jsou mimo scope alpha — zdokumentovány jako planned extensions aby ovlivnily design DB schéma (přidání sloupců bude additive, ne breaking).
7.1 Earned invites (gamifikace)
| Trigger | Bonus invites |
|---|---|
| Account age ≥ 30 dní | +2 |
| Projekt dosáhne 100 page views | +3 |
| 5 pozvaných userů aktivních 30+ dní | +5 |
Implementace: scheduled job týdně vyhodnotí podmínky a grantuje invites automaticky
(na rozdíl od manuálního admin grantu). Audit log stejnou invite_grants tabulkou
s granted_by_admin_id = NULL (system grant).
7.2 Pricing tier integration
Paid tier users dostanou vyšší základní invite kvótu jako benefit. Logika v user_invite_quota
— při upgrade na paid tier automatický grant bez manuální akce.
7.3 Quality gating
Pokud uživatel má 3+ invitees, kteří churní do 7 dní od signupu → redukce invite kvóty. Signal: issuer pozval lidi, kteří platformu nepoužívají → pravděpodobně masový invite blast.
Implementace: weekly churn job + notification adminovi před automatickým penalty grantem (Mirek má veto).
References
- ADR-020 — architektonická rozhodnutí pro invite systém
- mara-fatigue-fup.md — FUP quota mechanismus a capacity math
Thanks for the feedback.