Yasin Arsal

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ıkYı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:

  1. Claude Code (kendi kodlayıcın). Kur: npm install -g @anthropic-ai/claude-code
  2. Vercel (ücretsiz hosting). vercel.com'dan kayıt ol.
  3. Supabase (ücretsiz Postgres + storage). supabase.com'dan kayıt ol.
  4. Resend (ücretsiz transactional email, 3K/ay). resend.com'dan kayıt ol.
  5. GitHub (ücretsiz). github.com'dan kayıt ol.
  6. 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

javascript
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

javascript
next@14
@supabase/supabase-js
@supabase/auth-helpers-nextjs
@dnd-kit/core
@dnd-kit/sortable
tailwindcss
@tanstack/react-table
zod
date-fns

Schema Pattern

sql
-- 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

typescript
// 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

javascript
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

typescript
// 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

javascript
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

typescript
// 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ı

json
// 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

javascript
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

javascript
next@14
@supabase/supabase-js
@supabase/auth-helpers-nextjs
@dnd-kit/core
googleapis
stripe
recharts
tailwindcss
zod
date-fns

Schema Pattern

sql
-- 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

typescript
// 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

ÖnceSonra
Aylık maliyet$191$0
Yıllık maliyet$2,292$12 (sadece domain)
Harcanan saat0~15-18 saat, tek seferlik
Vendor lock-inYüksekSıfır (senin kodun)
Custom özellikRoadmap bekleBu 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.