20 MAYIS 2026
Yazılıma Ödeme Yapma, Kendin Kur: 4 SaaS Aracı
Ayda $191 ödediğin 4 SaaS aracını (ClickUp, Mailchimp, Zapier, Pipedrive) Claude Code ile bir hafta sonunda yeniden inşa et — tam stack, schema ve prompt'larla yıllık $2,280 tasarruf.
Kullandığın 4 SaaS aracını kendi kodunla değiştir. Ayda $191 SaaS faturası gidiyor. Tek bir hafta sonunda Claude Code yardımıyla hepsini sıfırdan kurabilirsin.
Yıllık Tasarruf Tablosu
| Araç | Aylık | Yıllık |
|---|---|---|
| ClickUp | $99 | $1,188 |
| Mailchimp | $49 | $588 |
| Zapier | $19 | $228 |
| Pipedrive | $24 | $288 |
| Toplam | $191 | $2,292 |
İki bin dolardan fazla — her yıl, her yazılım için kendin kurduğunda tek bir hafta sonu yeterli.
Başlamadan Önce
5 ücretsiz hesaba ve tek bir ücretli kaleme ihtiyacın var:
- Claude Code (kendi kodlayıcın). Kur:
npm install -g @anthropic-ai/claude-code - Vercel (ücretsiz hosting). vercel.com'dan kayıt ol.
- Supabase (ücretsiz Postgres + storage). supabase.com'dan kayıt ol.
- Resend (ücretsiz transactional email, 3K/ay). resend.com'dan kayıt ol.
- GitHub (ücretsiz). github.com'dan kayıt ol.
- Bir domain (tek ödeyeceğin şey). Namecheap veya Porkbun'dan $12/yıl.
Toplam yıllık harcama: $12. Toplam yıllık tasarruf: $2,292. Net cebine: yılda $2,280.
Her build aşağıda tek bir prompt'la başlar. Boş bir klasörde Claude Code'u aç. Prompt'u yapıştır. Takip sorularını cevapla. Yayına al.
Tool 01: ClickUp Yerine
Ne: Sürükle-bırak kolonlu Next.js kanban + Supabase Postgres ile destekli bir görev panosu. Görev listeleri, proje görünümleri, dashboard'lar, otomasyonlar — hepsi senin kodunda.
Süre: 3-4 saat. Tasarruf: $228/yıl.
Prompt
Build me a ClickUp replacement using Next.js 14 (App Router),
TypeScript, Tailwind, and Supabase as the Postgres backend.
Requirements:
1. A /board kanban page with drag-and-drop columns (use @dnd-kit/core)
showing tasks by status: backlog, in-progress, review, done
2. A /list view of the same tasks as a sortable, filterable table
3. A /timer panel that starts/stops time entries against a task
and logs duration to a time_entries table
4. A "tasks" table in Supabase with: id, title, description, status,
assignee, due_date, priority, tags, created_at, updated_at
5. A "time_entries" table with: id, task_id, started_at, ended_at,
duration_seconds
6. Custom views per team: save filter combos ("my tasks this week",
"Que this week") under a name, surface as tabs above the board
7. Webhooks: a Server Action route /api/webhooks/{provider} that
accepts incoming Slack and Gmail payloads and creates tasks
8. A /dashboard page with three tiles: tasks-by-status pie,
time-logged-this-week bar, overdue-tasks list
9. Auth: Supabase Auth magic link. All routes auth-gated.
10. Deploy target Vercel. Wire it up so I can `git push` and it ships.
Start by asking me what task statuses and team members I want. Then
write the SQL migration, then the board view, then time tracking last.Stack
next@14
@supabase/supabase-js
@supabase/auth-helpers-nextjs
@dnd-kit/core
@dnd-kit/sortable
tailwindcss
@tanstack/react-table
zod
date-fnsSchema Pattern
-- supabase/migrations/001_init.sql
create table tasks (
id uuid primary key default gen_random_uuid(),
title text not null,
description text,
status text not null default 'backlog',
assignee text,
due_date timestamptz,
priority text,
tags text[] default '{}',
position int default 0,
created_at timestamptz default now(),
updated_at timestamptz default now()
);
create table time_entries (
id uuid primary key default gen_random_uuid(),
task_id uuid references tasks(id) on delete cascade,
started_at timestamptz not null,
ended_at timestamptz,
duration_seconds int
);
create policy "auth users read tasks" on tasks
for select using (auth.role() = 'authenticated');
create policy "auth users write tasks" on tasks
for all using (auth.role() = 'authenticated');Drag-and-Drop Pattern
// app/board/page.tsx
'use client'
import { DndContext, closestCenter } from '@dnd-kit/core'
import { SortableContext } from '@dnd-kit/sortable'
export function Board({ tasks, updateStatus }) {
return (
<DndContext
collisionDetection={closestCenter}
onDragEnd={(e) => {
if (e.over) updateStatus(e.active.id, e.over.id)
}}
>
{['backlog', 'in-progress', 'review', 'done'].map(col => (
<SortableContext key={col} items={tasks.filter(t => t.status === col)}>
<Column status={col} tasks={tasks.filter(t => t.status === col)} />
</SortableContext>
))}
</DndContext>
)
}Ne Elde Edersin
- Gerçek Postgres. Satır sınırı yok. Koltuk başı ücret yok. Kullanıcı başı ücret yok.
- Tablonun gerçekten hızlı olduğu sürükle-bırak kanban.
- Sorgulanabilir SQL formatında zaman takibi.
- Slack ve Gmail webhook'ları doğrudan panonuza akıyor.
- Takım üyesi başına özel görünümler, URL paramları olarak kaydedilir, plan-tier engeli yok.
Tool 02: Mailchimp Yerine
Ne: Supabase contacts ile Resend destekli email gönderici, SQL ile segmentleme, MJML şablonlar ve kampanya gönderimi için minik dashboard.
Süre: 2 saat. Tasarruf: $156/yıl.
Prompt
Build me a Mailchimp replacement using Next.js 14 (App Router),
TypeScript, Tailwind, Supabase (Postgres), and Resend for sending.
Requirements:
1. A "contacts" table in Supabase with: id, email, first_name,
last_name, tags text array, unsubscribed (bool), created_at
2. A /campaigns dashboard listing past sends + a "+ New Campaign" CTA
3. New-campaign flow:
- pick a segment (a saved Postgres query like "tags contains 'lead'")
- paste a subject line + an HTML body (MJML-compatible)
- preview to my own email first
- "Send to N recipients" button
4. The send route is a Server Action that batches via Resend's
/emails endpoint (max 100 per request). Log each send into a
"campaign_sends" table with status.
5. A public /unsubscribe?email=... page that flips the unsubscribed bool
6. UTM injection on every link in the body before send (utm_source=email,
utm_campaign=[slug])
7. Use Resend's React Email components for templates. Ship 3 starter
templates: plain announcement, newsletter, single-CTA promo
Start by asking what segments I want and what my "from" address is.
Then write the SQL, the contacts admin, the campaign send flow.Send Snippet
// app/actions/send-campaign.ts
'use server'
import { Resend } from 'resend'
import { createClient } from '@/lib/supabase/server'
const resend = new Resend(process.env.RESEND_API_KEY)
export async function sendCampaign(campaignId: string) {
const supa = createClient()
const { data: campaign } = await supa
.from('campaigns')
.select('*, segment_query')
.eq('id', campaignId)
.single()
const { data: recipients } = await supa
.rpc('contacts_for_segment', { q: campaign.segment_query })
// batch 100 at a time
for (let i = 0; i < recipients.length; i += 100) {
const batch = recipients.slice(i, i + 100)
await resend.batch.send(
batch.map(r => ({
from: process.env.FROM_EMAIL,
to: r.email,
subject: campaign.subject,
html: injectUtm(campaign.html, campaign.slug),
}))
)
}
}Ne Elde Edersin
- Sınırsız kontak (Postgres satırları ücretsiz).
- Gerçek SQL segmentleme. "Gelişmiş filtre kullanmak için Plus plan" yok.
- Kod olarak şablonlar, Git'le versiyonlu.
- Analytics'e doğrudan akan UTM takibi, Mailchimp'in kara kutusu değil.
Tool 03: Zapier Yerine
Ne: İki API'yi doğrudan birbirine bağlayan Sunucu Aksiyonları + Vercel Cron Jobs. Görev sınırı yok. "Premium app" tier'ı yok.
Süre: 4 saat. Tasarruf: $228/yıl.
Prompt
Build me a Zapier replacement using Next.js 14 (App Router),
TypeScript, and Vercel Cron Jobs. The goal is direct API-to-API
workflows with no middleman.
Requirements:
1. A /workflows admin page listing all my active workflows
2. Each workflow is a TypeScript file under /workflows/[name].ts
that exports:
- trigger: { type: 'cron' | 'webhook', schedule?: string }
- run: (payload) => Promise<void>
3. A /api/cron/[workflow] route guarded by CRON_SECRET that runs
the workflow's run() function. Wired to vercel.json crons.
4. A /api/webhook/[workflow] route that takes POST bodies and calls
the workflow's run() with the payload
5. A "runs" table in Supabase logging every execution:
workflow_name, status, payload, error, duration_ms, ran_at
6. Ship 3 starter workflows as templates:
- new-stripe-payment -> slack notification + Supabase row
- daily-report -> pull Supabase metrics, email me via Resend
- github-issue -> if labeled "bug", post to Linear API
Start by asking what 1-2 workflows I'd want first. Build those.
Then write the dashboard so I can add more myself.Workflow Pattern
// workflows/new-stripe-payment.ts
import { z } from 'zod'
import { resend } from '@/lib/resend'
import { supa } from '@/lib/supabase'
export const trigger = { type: 'webhook' as const }
const Payload = z.object({
data: z.object({
object: z.object({
id: z.string(),
amount: z.number(),
customer_email: z.string().email(),
}),
}),
})
export async function run(raw: unknown) {
const { data: { object: pay } } = Payload.parse(raw)
await supa.from('payments').insert({
stripe_id: pay.id,
amount_cents: pay.amount,
email: pay.customer_email,
})
await resend.emails.send({
from: 'alerts@yourdomain.com',
to: 'you@yourdomain.com',
subject: `New payment: $${pay.amount / 100} from ${pay.customer_email}`,
html: `<p>Stripe ID: ${pay.id}</p>`,
})
}Cron Bağlantısı
// vercel.json
{
"crons": [
{ "path": "/api/cron/daily-report", "schedule": "0 14 * * *" }
]
}Ne Elde Edersin
- Görev kotası yok. Cron çalıştırmaları Vercel'de cömert sınırlara kadar ücretsiz.
- Doğrudan API çağrıları, tam payload, retry üzerinde tam kontrol.
- Debug edilebilen, log alınabilen, versiyonlanabilen kod.
- Stripe, Slack, GitHub, Linear, Notion, Resend — API'si olan her şeyle bağla.
Tool 04: Pipedrive Yerine
Ne: Sürükle-bırak satış pipeline'lı, Postgres contacts'lı, Gmail-takipli email thread'li ve closed-won deal'lar için Stripe webhook'lu Next.js CRM. Koltuk başı ücret yok. Deal başı sınır yok.
Süre: 6-8 saat. Tasarruf: $288/yıl.
Prompt
Build me a Pipedrive replacement: a custom CRM using Next.js 14
(App Router), TypeScript, Tailwind, Supabase as the Postgres
backend, and the Gmail API for email tracking.
Requirements:
1. A /pipeline page with a drag-and-drop kanban of deals across
stages: new, contacted, qualified, proposal, won, lost
(use @dnd-kit/core, persist column changes to Supabase)
2. A "deals" table in Supabase with: id, title, contact_id, value_cents,
stage, expected_close, owner, source, created_at, updated_at
3. A "contacts" table with: id, name, email, phone, company,
title, custom_fields (jsonb), created_at
4. A /contacts page: searchable, filterable, with a detail panel
showing the contact's deals, emails, and notes
5. A /deals/[id] page: deal detail, activity timeline, notes editor,
stage history, attached emails
6. Gmail integration: OAuth into Gmail, on connect, watch the inbox
for messages from/to any address in contacts table. Sync threads
into a "messages" table tagged to the matching contact.
7. A Stripe webhook at /api/webhooks/stripe: on checkout.session.completed,
auto-create or update a deal in 'won' stage with the line-item value
8. A /reports page: pipeline-value-by-stage bar, won-this-month total,
stage-conversion funnel, source-attribution pie. All driven by SQL,
no chart-library lock-in (use Recharts).
9. Custom fields per deal and contact: schema is jsonb, define field
labels in a settings page, render dynamically.
10. Auth: Supabase Auth magic link. All routes auth-gated.
Start by asking me what stages, sources, and custom fields I want.
Then write the SQL migration. Then the pipeline view. Then Gmail
sync. Then Stripe last.Stack
next@14
@supabase/supabase-js
@supabase/auth-helpers-nextjs
@dnd-kit/core
googleapis
stripe
recharts
tailwindcss
zod
date-fnsSchema Pattern
-- supabase/migrations/001_init.sql
create table contacts (
id uuid primary key default gen_random_uuid(),
name text not null,
email text,
phone text,
company text,
title text,
custom_fields jsonb default '{}'::jsonb,
created_at timestamptz default now()
);
create table deals (
id uuid primary key default gen_random_uuid(),
title text not null,
contact_id uuid references contacts(id),
value_cents int default 0,
stage text not null default 'new',
expected_close date,
owner text,
source text,
custom_fields jsonb default '{}'::jsonb,
created_at timestamptz default now(),
updated_at timestamptz default now()
);
create table messages (
id uuid primary key default gen_random_uuid(),
contact_id uuid references contacts(id),
gmail_thread_id text,
subject text,
snippet text,
sent_at timestamptz,
direction text
);Stripe Webhook Pattern
// app/api/webhooks/stripe/route.ts
import { NextRequest, NextResponse } from 'next/server'
import Stripe from 'stripe'
import { createClient } from '@/lib/supabase/server'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2024-06-20',
})
export async function POST(req: NextRequest) {
const sig = req.headers.get('stripe-signature')!
const body = await req.text()
const event = stripe.webhooks.constructEvent(
body, sig, process.env.STRIPE_WEBHOOK_SECRET!
)
if (event.type === 'checkout.session.completed') {
const session = event.data.object as Stripe.Checkout.Session
const supa = createClient()
const { data: contact } = await supa
.from('contacts')
.upsert({ email: session.customer_details!.email })
.select()
.single()
await supa.from('deals').insert({
title: `Stripe checkout ${session.id}`,
contact_id: contact!.id,
value_cents: session.amount_total!,
stage: 'won',
source: 'stripe',
})
}
return NextResponse.json({ received: true })
}Ne Elde Edersin
- Deal sayısı ne olursa olsun, koltuk başı ücreti $0 olan bir CRM.
- Saatler içinde gemiye giren sürükle-bırak pipeline'ı, gün değil.
- Contacts'a otomatik bağlanan Gmail thread'leri.
- Raporlama gerçek olsun diye won deal'ları auto-log eden Stripe webhook'ları.
- SQL olarak sorgulanabilen jsonb custom field'lar, plan-tier kapısı yok.
Toplam Ticaret
| Önce | Sonra | |
|---|---|---|
| Aylık maliyet | $191 | $0 |
| Yıllık maliyet | $2,292 | $12 (sadece domain) |
| Harcanan saat | 0 | ~15-18 saat, tek seferlik |
| Vendor lock-in | Yüksek | Sıfır (senin kodun) |
| Custom özellik | Roadmap bekle | Bu gece kur |
Yaklaşık iki iş günü harcıyorsun. Bundan sonra her yıl $2,280 tasarruf ediyorsun. Kod senin. Veri senin. Bunların hepsini orijinal SaaS'ın asla izin vermeyeceği şeylere genişletebilirsin.
Takas bu.
Bir Şey Daha
Bunlardan herhangi birinde takılırsan, proje klasöründe Claude Code'un /init komutunu çalıştır. Repo'nu okur ve bir sonraki prompt'unu nereye yönlendireceğini söyler.
Bunlardan birini yayınlarsan görmek isterim. Instagram'da tag at.