Growth Engineering
PLG (Product-Led Growth) Implementation
PLG Flywheel
User Signs Up (Free)
|
v
Experiences Value (Aha Moment)
|
v
Invites Team/Colleagues
|
v
Team Adopts Product
|
v
Usage Grows -> Hits Limits
|
v
Converts to Paid
|
v
Expands (More Seats/Features)
|
+---> Refers New Users (loop back)
PLG Architecture
interface PLGConfig {
freeTier: {
features: string[];
limits: Record<string, number>; // { projects: 3, members: 5, storage_gb: 1 }
duration: "unlimited" | number; // gun cinsinden veya sinirsiz
};
trialTier: {
features: string[];
duration_days: number;
requires_cc: boolean;
};
paidTiers: Array<{
name: string;
price_monthly: number;
price_annual: number;
features: string[];
limits: Record<string, number>;
}>;
gates: FeatureGate[];
}
interface FeatureGate {
feature: string;
gate_type: "hard" | "soft" | "usage";
free_limit?: number;
upgrade_prompt: string;
cta: string;
}
// Feature gate middleware
function checkFeatureGate(feature: string) {
return async (req: Request, res: Response, next: NextFunction) => {
const user = req.user;
const gate = gates.find(g => g.feature === feature);
if (!gate) return next();
const plan = await getUserPlan(user.id);
const usage = await getFeatureUsage(user.id, feature);
if (gate.gate_type === "hard" && plan.tier === "free") {
return res.status(403).json({
error: "UPGRADE_REQUIRED",
message: gate.upgrade_prompt,
cta: gate.cta,
upgrade_url: `/billing/upgrade?feature=${feature}`,
});
}
if (gate.gate_type === "usage" && gate.free_limit && usage >= gate.free_limit) {
// Soft limit: izin ver ama uyar
res.setHeader("X-Usage-Warning", gate.upgrade_prompt);
await trackEvent(user.id, "feature_gate_hit", { feature, usage, limit: gate.free_limit });
}
next();
};
}
Aha Moment Definition
| Urun Tipi | Aha Moment Ornegi | Metrik | |-----------|-------------------|--------| | Project Management | Ilk task'i tamamlama | task_completed (first) | | Analytics | Ilk dashboard olusturma | dashboard_created (first) | | Communication | Ilk mesaj gonderme | message_sent (first) | | Development Tool | Ilk basarili build | build_succeeded (first) | | Design Tool | Ilk export/share | design_exported (first) |
interface AhaMoment {
event: string;
conditions: Record<string, unknown>;
time_window_hours: number; // Bu sure icinde olursa "activated"
activation_rate_target: number; // %40-60 hedef
}
const ahaMoment: AhaMoment = {
event: "project_created_with_members",
conditions: { member_count: { gte: 2 }, tasks_added: { gte: 3 } },
time_window_hours: 72, // Kayittan sonra 72 saat icinde
activation_rate_target: 0.50,
};
Referral System Design
Referral Architecture
interface ReferralProgram {
id: string;
name: string;
reward_type: "two_sided" | "referrer_only" | "referee_only";
referrer_reward: Reward;
referee_reward: Reward;
rules: ReferralRules;
}
interface Reward {
type: "credit" | "discount" | "free_months" | "feature_unlock" | "cash";
amount: number;
currency?: string;
description: string;
}
interface ReferralRules {
max_referrals_per_user: number; // spam onleme
qualification_event: string; // ne zaman odul verilir
qualification_window_days: number; // sure siniri
anti_fraud: AntiFraudRules;
}
interface AntiFraudRules {
same_ip_block: boolean;
email_domain_block: string[]; // disposable email engelle
min_activity_threshold: number; // minimum kullanim
cooldown_hours: number; // ayni kisi icin bekleme
}
Referral Flow
Referrer Referee
| |
|-- Shares unique link --------> |
| |-- Signs up
| |-- Completes qualification
| | (first purchase / activation)
|<-- Notification: Reward! ------|
|-- Reward credited |-- Reward credited
| |
v v
Track: referral_completed Track: referred_user_activated
Referral Schema
CREATE TABLE referrals (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
referrer_id UUID NOT NULL REFERENCES users(id),
referee_id UUID REFERENCES users(id),
referral_code VARCHAR(20) UNIQUE NOT NULL,
referral_link TEXT NOT NULL,
status VARCHAR(20) DEFAULT 'pending', -- pending, signed_up, qualified, rewarded, expired
channel VARCHAR(50), -- email, social, direct_link
created_at TIMESTAMPTZ DEFAULT NOW(),
signed_up_at TIMESTAMPTZ,
qualified_at TIMESTAMPTZ,
rewarded_at TIMESTAMPTZ,
referrer_reward_amount DECIMAL,
referee_reward_amount DECIMAL,
metadata JSONB DEFAULT '{}'
);
CREATE INDEX idx_referrals_referrer ON referrals(referrer_id);
CREATE INDEX idx_referrals_code ON referrals(referral_code);
CREATE INDEX idx_referrals_status ON referrals(status);
-- Referral metrikleri
SELECT
referrer_id,
COUNT(*) AS total_referrals,
COUNT(CASE WHEN status = 'signed_up' THEN 1 END) AS signups,
COUNT(CASE WHEN status = 'qualified' THEN 1 END) AS qualified,
COUNT(CASE WHEN status = 'rewarded' THEN 1 END) AS rewarded,
ROUND(100.0 * COUNT(CASE WHEN status = 'qualified' THEN 1 END) /
NULLIF(COUNT(CASE WHEN status = 'signed_up' THEN 1 END), 0), 1) AS conversion_rate
FROM referrals
GROUP BY referrer_id
ORDER BY qualified DESC;
Viral Loops
Viral Loop Types
| Tip | Mekanizma | Ornek | K-Factor Hedef | |-----|-----------|-------|---------------| | Word of Mouth | Organik tavsiye | Slack, Notion | 0.3-0.5 | | Incentivized | Odul ile tavsiye | Dropbox (500MB) | 0.5-0.8 | | Embedded | Urunde gorulme | "Made with X" | 0.2-0.4 | | Collaborative | Birlikte kullanim | Google Docs invite | 0.6-1.0 | | Social Proof | Paylasim/showcase | Spotify Wrapped | 0.3-0.6 | | Content | Icerik uretimi | Canva, Figma links | 0.2-0.4 |
K-Factor (Viral Coefficient)
interface ViralMetrics {
invites_per_user: number; // ortalama gonderilen davet
invite_conversion_rate: number; // davetin kabul orani
cycle_time_days: number; // bir loop'un suresi
}
function calculateKFactor(metrics: ViralMetrics): {
kFactor: number;
viral: boolean;
doublingTimeDays: number | null;
} {
// K = invites_per_user * conversion_rate
const k = metrics.invites_per_user * metrics.invite_conversion_rate;
return {
kFactor: Math.round(k * 100) / 100,
viral: k > 1, // K > 1 = organik buyume
doublingTimeDays: k > 1
? Math.round(metrics.cycle_time_days * Math.log(2) / Math.log(k))
: null,
};
}
// Ornek: 3 invite * %25 conversion = K=0.75 (viral degil ama katkisi var)
// Ornek: 5 invite * %30 conversion = K=1.5 (viral!)
Viral Loop Implementation
// "Made with [Product]" badge (embedded viral loop)
function generateShareableBadge(projectId: string, userId: string): string {
const trackingUrl = `https://app.example.com/r/${encodeBase64(userId)}?ref=badge&project=${projectId}`;
return `
<a href="${trackingUrl}" target="_blank" rel="noopener">
<img src="https://app.example.com/badge.svg" alt="Made with Example" width="120" height="28" />
</a>
`;
}
// Collaborative viral loop
async function inviteToProject(
inviterId: string,
projectId: string,
emails: string[]
): Promise<Invi