İçeriğe atla

GitHub Spec Kit: Spesifikasyon Güdümlü AI Geliştirme Rehberi

GitHub Spec Kit, başıboş AI kod üretimini dört aşamalı specify-plan-tasks-implement döngüsüyle yapılandırılmış ve sürdürülebilir koda nasıl dönüştürür.

Ayhan Sipahi Ayhan Sipahi

AI araçlarının ürettiği kod genellikle yerel bir smoke test’i geçer ama üretim çıtasını geçemez: belirsiz arayüzler, yukarı akış verisi hakkında doğrulanmamış varsayımlar, eksik hata yönetimi ve kod tabanının konvansiyonlarını değil prompt’u yansıtan bir yapı. Arayüzün, girdilerin, değişmezlerin ve hata modlarının açık, makine okunabilir bir spesifikasyonu, modelin tek satır üretmesinden önce bu boşluğun çoğunu kapatır.

GitHub’ın SpecKit’i bu fikrin bir uygulaması: model tek satır yazmadan önce yazılı bir spesifikasyonu, teknik planı ve task listesini onun önüne koyan bir CLI ve bir dizi slash komutu. Aşağıda spesifikasyon formatı, specify-plan-tasks-implement döngüsü, spesifikasyon ile testler ve üretilen kod arasındaki teslim noktaları ve pratiği sinyal yerine törene çeviren başarısızlık modları (sonradan eklenen spesifikasyon, aşırı spesifikasyon, kırılgan kabul kriterleri) var.

Belirsiz Bir Prompt’un Atladıkları#

Belirsiz bir prompt’la doğrudan implementasyona atlamak hızlı bir MVP için işe yarar. Çıktının bir code review’dan geçmesi gerektiği anda işe yaramaz:

// Spesifikasyon olmadan tipik AI üretimi kod
function processUserData(data: any): any {
  // AI ne istediğini tahmin etmeye çalışır
  const result = data.map((item: any) => {
    if (item.type === 'user') {
      return { ...item, processed: true };
    }
    return item;
  });
  return result;
}

Açık spesifikasyonlar olmadan AI araçları gereksinimler, mimari ve implementasyon detayları hakkında varsayımlar yapar. Bu varsayımlar diff’te görünmez: data: any şekil sözleşmesini gizler, dokunulmayan return item dalı da kimsenin düşünmediği bütün tipleri gizler.

SpecKit’in Prompt ile Kod Arasına Koyduğu Döngü#

SpecKit, prompt ile üretilen kod arasına sıralı dört adım koyar; etraflarında da iki opsiyonel adım vardır:

Constitution

Specify

Clarify

Plan

Tasks

Implement

Review & Iterate

Proje Prensipleri Temel Değerler Standartlar

User Stories Kabul Kriterleri Gereksinimler

Belirsizlikleri Gider Detayları Açıkla Sınır Durumları

Tech Stack Mimari Kısıtlar

Task Breakdown Bağımlılıklar Öncelikler

Kod Implementasyonu Testing Dokümantasyon

Her adım, bir sonraki başlamadan önce modelin hareket alanını daraltır. Sonuçta üretilen kodun dayanağı tek bir prompt’un nasıl yazıldığı olmaktan çıkar; projenin prensipleri ve standartları olur.

/constitution ile Proje Prensipleri#

Opsiyonel bir ilk geçiş. Projenin temel prensipleri ve standartları, herhangi bir spesifik gereksinime girmeden önce yazılır.

# Proje constitution'ı oluştur
/constitution

# Örnek proje constitution'ı
"Bu authentication sistemi şunları öncelemeli:
- Kolaylık yerine güvenlik
- Sessiz hatalar yerine açık error handling
- Akıllı implementasyonlar yerine test edilebilir kod
- Self-documenting kod yerine açık dokümantasyon
- Cutting-edge özellikler yerine progressive enhancement"

Spesifikasyonu Yazmak#

Bu aşama, kod üretilmeden önce gereksinimleri kelimelere dökmeni zorlar ve aracın kendi varsayımlarıyla dolduracağı boşluğu kapatır.

Kurulum ve Yapılandırma#

# Tek kullanımlık kurulum
uvx --from git+https://github.com/github/spec-kit.git specify init my-project

# Kalıcı kurulum (önerilen)
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git

# Belirli AI araçları için yapılandırma
specify init my-project --ai claude  # Claude Code için
specify init my-project --ai copilot  # GitHub Copilot için
specify init my-project --ai gemini  # Gemini CLI için

# Mevcut projede başlatma
specify init --here --ai claude

İlk Spesifikasyonunu Oluştur#

# Spesifikasyon sürecini başlat
/specify

# Kullanıcı authentication sistemi için örnek spesifikasyon
"Next.js uygulaması için şunları destekleyen kullanıcı authentication sistemi geliştir:
- Email/şifre ile kayıt ve giriş
- Refresh tokenlarla JWT token yönetimi
- Email ile şifre sıfırlama işlevi
- Auth endpointler için rate limiting
- Mevcut TypeScript codebase ile entegrasyon
- Production kullanımı için güvenlik best practiceslerine uyum"

SpecKit bu üst düzey açıklamayı detaylı user storyler ve kabul kriterlerine dönüştürür:

## SpecKit Tarafından Üretilen User Storyler

### Epic: Kullanıcı Authentication Sistemi
- **US-001**: Yeni kullanıcı olarak, uygulamaya erişebilmek için email/şifre ile kayıt olmak istiyorum
- **US-002**: Kayıtlı kullanıcı olarak, korumalı özelliklere erişmek için kimlik bilgilerimle giriş yapmak istiyorum
- **US-003**: Kullanıcı olarak, unutursam hesabıma yeniden erişmek için şifremi sıfırlamak istiyorum
- **US-004**: Sistem olarak, brute force saldırılarını önlemek için authentication denemelerini sınırlamak istiyorum

### Kabul Kriterleri
- Kayıt geçerli email formatı ve şifre güçlü doğrulaması gerektirir
- JWT tokenları yapılandırılabilir süre sonra expire olur
- Refresh tokenlar kesintisiz session uzatmayı sağlar
- Şifre sıfırlama emailleri 15 dakika sonra expire olur
- Rate limiting IP başına dakikada maksimum 5 denemeye izin verir

/clarify ile Belirsizlikleri Gidermek#

İkinci opsiyonel adım, teknik planlamadan hemen önce:

# Belirsiz alanları açıklığa kavuştur
/clarify

# SpecKit belirsiz gereksinimleri tanımlar ve çözmeye yardımcı olur
"Sistem aynı kullanıcıdan gelen eşzamanlı giriş denemelerini nasıl ele almalı?"
"Kullanıcı zaten kullanımda olan bir email ile kayıt olmaya çalışırsa ne olacak?"
"Şifre sıfırlama tokenları tek kullanımlık mı yoksa yeniden kullanılabilir mi?"

Teknik Plan#

Stack ve mimari kısıtlar buraya yazılır. Bunlar olmadan aracın, hâlihazırda kullandığın sistemlerle çakışan bir teknolojiyi seçmemesi için hiçbir sebebi yoktur.

/plan

# Teknik kısıtlarını tanımla
"Tech stack: Next.js 15 App Router ile, TypeScript, PostgreSQL ile Prisma ORM
Mimari: Auth operasyonları için server actionlar, route koruma için middleware
Güvenlik: Şifre hashleme için bcrypt, JWT işleme için jose
Email: SMTP ile Nodemailer
Kısıtlar: Mevcut shadcn/ui componentleriyle entegre olmalı, güncel proje yapısını takip etmeli"

SpecKit kapsamlı bir teknik plan üretir:

## Teknik Mimari Planı

### Teknoloji Stack'i
- **Frontend**: Next.js 15 App Router, TypeScript, shadcn/ui
- **Backend**: Next.js API routes, Server Actions
- **Database**: PostgreSQL Prisma ORM ile
- **Authentication**: Refresh tokenları ile JWT
- **Güvenlik**: bcrypt, jose, rate-limiting middleware
- **Email**: SMTP yapılandırmasıyla Nodemailer

### Database Şeması
```sql
-- Users tablosu
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email VARCHAR(255) UNIQUE NOT NULL,
  password_hash VARCHAR(255) NOT NULL,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

-- Refresh tokens tablosu
CREATE TABLE refresh_tokens (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  token VARCHAR(255) UNIQUE NOT NULL,
  expires_at TIMESTAMP NOT NULL,
  created_at TIMESTAMP DEFAULT NOW()
);

Güvenlik Hususları#

  • bcrypt ile şifre hashleme (salt rounds: 12)
  • JWT access tokenları (15 dakika expiry)
  • Refresh tokenları (7 gün expiry)
  • Rate limiting: IP başına dakikada 5 deneme
  • SameSite cookies ile CSRF koruma

## Task Listesi

Çıktı, modelin tek tek ilerleyebileceği Jira benzeri bir plan.

```bash
/tasks

SpecKit numaralandırılmış, öncelik sıralı, açık bağımlılıklara sahip tasklar üretir:

## Implementation Taskları

### Setup ve Yapılandırma (Öncelik: Yüksek)
1. **Task 1**: Users ve refresh_tokens tabloları için Prisma şeması kurulumu
   - Bağımlılıklar: Yok
   - Tahmini süre: 30 dakika
   - Çıktı: Migrationlarla çalışan database şeması

2. **Task 2**: Authentication utilities oluştur (şifre hashleme, JWT işleme)
   - Bağımlılıklar: Task 1
   - Tahmini süre: 45 dakika
   - Çıktı: Auth operasyonları için utility fonksiyonlar

3. **Task 3**: Rate limiting middleware implement et
   - Bağımlılıklar: Yok
   - Tahmini süre: 30 dakika
   - Çıktı: Redis/memory store ile middleware fonksiyon

### Authentication Implementation (Öncelik: Yüksek)
4. **Task 4**: Kayıt server action geliştir
   - Bağımlılıklar: Task 1, Task 2
   - Tahmini süre: 1 saat
   - Çıktı: Validasyonla kayıt endpoint

5. **Task 5**: JWT üretimiyle login server action geliştir
   - Bağımlılıklar: Task 1, Task 2
   - Tahmini süre: 1 saat
   - Çıktı: Access/refresh tokenları dönen login endpoint

6. **Task 6**: Token refresh mekanizması implement et
   - Bağımlılıklar: Task 2, Task 5
   - Tahmini süre: 45 dakika
   - Çıktı: Token refresh endpoint

### UI Components (Öncelik: Orta)
7. **Task 7**: shadcn/ui bileşenleriyle login formu oluştur
   - Bağımlılıklar: Task 5
   - Tahmini süre: 1 saat
   - Çıktı: Validasyonlu stilli login formu

8. **Task 8**: Kayıt formu oluştur
   - Bağımlılıklar: Task 4
   - Tahmini süre: 1 saat
   - Çıktı: Şifre güç validasyonuyla kayıt formu

Taskları Teker Teker Uygulamak#

Her task, bir sonraki başlamadan önce gerçekleştirilir, gözden geçirilir ve düzeltilir. Task 2’deki bir hata, Task 4’ten 8’e kadarki taskların temeline dönüşmeden önce orada yakalanır.

Task 1 Implementation Örneği#

// prisma/schema.prisma - SpecKit guidance ile üretildi
model User {
  id  String  @id @default(cuid())
  email  String  @unique
  passwordHash  String  @map("password_hash")
  createdAt  DateTime  @default(now()) @map("created_at")
  updatedAt  DateTime  @updatedAt @map("updated_at")
  refreshTokens RefreshToken[]

  @@map("users")
}

model RefreshToken {
  id  String  @id @default(cuid())
  userId  String  @map("user_id")
  token  String  @unique
  expiresAt DateTime @map("expires_at")
  createdAt DateTime @default(now()) @map("created_at")
  user  User  @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@map("refresh_tokens")
}

Task 2 Implementation Örneği#

// lib/auth.ts - Düzgün error handling ile utility fonksiyonlar
import bcrypt from 'bcryptjs';
import { SignJWT, jwtVerify } from 'jose';

export class AuthError extends Error {
  constructor(message: string, public code: string) {
    super(message);
    this.name = 'AuthError';
  }
}

export async function hashPassword(password: string): Promise<string> {
  try {
    return await bcrypt.hash(password, 12);
  } catch (error) {
    throw new AuthError('Şifre hashleme başarısız', 'HASH_ERROR');
  }
}

export async function verifyPassword(
  password: string,
  hash: string
): Promise<boolean> {
  try {
    return await bcrypt.compare(password, hash);
  } catch (error) {
    throw new AuthError('Şifre doğrulama başarısız', 'VERIFY_ERROR');
  }
}

export async function generateAccessToken(
  payload: { userId: string; email: string }
): Promise<string> {
  const secret = new TextEncoder().encode(process.env.JWT_SECRET);

  return new SignJWT(payload)
    .setProtectedHeader({ alg: 'HS256' })
    .setExpirationTime('15m')
    .setIssuedAt()
    .sign(secret);
}

export async function verifyAccessToken(
  token: string
): Promise<{ userId: string; email: string }> {
  try {
    const secret = new TextEncoder().encode(process.env.JWT_SECRET);
    const { payload } = await jwtVerify(token, secret);

    return payload as { userId: string; email: string };
  } catch (error) {
    throw new AuthError('Geçersiz token', 'TOKEN_INVALID');
  }
}

Aynı Kayıt Handler’ı, İki Kez#

Öncesi#

// Yapılandırılmamış AI üretimi auth
export default async function handler(req: any, res: any) {
  if (req.method === 'POST') {
    const { email, password } = req.body;
    // Şifreyi bir şekilde hashle
    const hash = bcrypt.hashSync(password, 10);
    // Databaseye kaydet
    const user = await prisma.user.create({
      data: { email, password: hash }
    });
    // Bir şey dön
    res.json({ success: true });
  }
}

Sonrası#

// server/auth/register.ts - Yapılandırılmış, sürdürülebilir implementation
import { z } from 'zod';
import { ratelimit } from '@/lib/rate-limit';
import { hashPassword } from '@/lib/auth';
import { prisma } from '@/lib/prisma';

const registerSchema = z.object({
  email: z.string().email('Geçersiz email formatı'),
  password: z.string()
    .min(8, 'Şifre en az 8 karakter olmalı')
    .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
           'Şifre büyük harf, küçük harf ve sayı içermeli')
});

export async function registerUser(formData: FormData) {
  // Rate limiting
  const { success } = await ratelimit.limit('auth_register');
  if (!success) {
    throw new Error('Çok fazla kayıt denemesi. Lütfen daha sonra tekrar deneyin.');
  }

  // Input validation
  const result = registerSchema.safeParse({
    email: formData.get('email'),
    password: formData.get('password')
  });

  if (!result.success) {
    throw new Error(`Validasyon hatası: ${result.error.issues.map(i => i.message).join(', ')}`);
  }

  const { email, password } = result.data;

  try {
    // Kullanıcı var mı kontrol et
    const existingUser = await prisma.user.findUnique({
      where: { email }
    });

    if (existingUser) {
      throw new Error('Bu email ile kullanıcı zaten mevcut');
    }

    // Hashlenmiş şifre ile kullanıcı oluştur
    const passwordHash = await hashPassword(password);
    const user = await prisma.user.create({
      data: {
        email,
        passwordHash
      },
      select: {
        id: true,
        email: true,
        createdAt: true
      }
    });

    return { success: true, user };
  } catch (error) {
    if (error instanceof Error) {
      throw error;
    }
    throw new Error('Kayıt başarısız. Lütfen tekrar deneyin.');
  }
}

İkinci sürüm şema validasyonu, tekrarlanan email kontrolü, rate limiting ve tiplenmiş hata yolları ekliyor. Bunların her birinin kaynağı kabul kriterlerindeki bir satır; yani hepsi, eksiği fark edecek bir reviewer daha diff’e bakmadan yazılmış oluyor.

Takıma Taşımak#

Tek Bir Özellikle Başlamak#

Takım geneline yayılan bir zorunluluk yerine tek bir özellikle başla:

# Adım 1: Ertelenmiş karmaşık bir özellik seç
specify init payment-processing --ai claude

# Adım 2: Dört aşamayı da kullanarak özelliği tamamla
# Spesifikasyonun çıktıyı nerede değiştirdiğini not et

# Adım 3: Spec ile diff'i takıma yan yana anlat
# Review yorumlarını benzer büyüklükteki yeni bir özellikle karşılaştır

Spesifikasyon Şablonları#

Yaygın proje türleri için spesifikasyon şablonları belirle:

## API Endpoint Spesifikasyon Şablonu

### Fonksiyonel Gereksinimler
- [ ] Input parametrelerini ve validation kurallarını tanımla
- [ ] Output formatını ve error responslarını belirle
- [ ] Authentication/authorization gereksinimlerini dokümante et
- [ ] Rate limiting ve caching stratejilerini tanımla

### Teknik Gereksinimler
- [ ] Database etkileşimlerini ve sorguları belirle
- [ ] Logging ve monitoring gereksinimlerini tanımla
- [ ] External servislerle entegrasyon noktalarını dokümante et
- [ ] Test gereksinimlerini belirle (unit, integration, e2e)

### Performans Gereksinimleri
- [ ] Response time hedefleri
- [ ] Concurrent kullanıcı handling
- [ ] Database sorgu optimizasyon gereksinimleri
- [ ] Caching stratejisi ve invalidation kuralları

Takım Yapılandırması#

Depoya işlenen bir config dosyası, aracı takımın zaten kullandığı konvansiyonlara sabitler:

// .speckit/config.js - Takım yapılandırması
export default {
  aiTool: 'claude',
  projectStructure: {
    srcDir: 'src',
    testDir: '__tests__',
    docsDir: 'docs'
  },
  codeStandards: {
    formatter: 'prettier',
    linter: 'eslint',
    testing: 'jest'
  },
  integrations: {
    jira: {
      enabled: true,
      projectKey: 'AUTH'
    },
    github: {
      issueTemplates: true,
      prTemplates: true
    }
  }
};

Reviewer Tarafında Ne Değişir#

SpecKit üretimi kod context sağlayarak code reviewları basitleştiriyor:

// Her implementation spesifikasyon referansı içeriyor
/**
 * Task 4: Kayıt server action
 * Spesifikasyon: US-001 - Email/şifre ile kullanıcı kayıt
 * Bağımlılıklar: Task 1 (database şema), Task 2 (auth utilities)
 * Güvenlik gereksinimleri: Şifre güçlü validasyon, rate limiting
 */
export async function registerUser(formData: FormData) {
  // Implementation spesifikasyonu tam olarak takip ediyor
}

Reviewerlar gereksinimleri tahmin etmek yerine implementasyonun spesifikasyonlara uyup uymadığını doğrulayabiliyor.

Spesifikasyon Çalışmasının Maliyeti#

Bu iş akışı eforu ortadan kaldırmaz, öne çeker. Spesifikasyonu yazmak, belirsizlikleri gidermek ve task listesini gözden geçirmek, ortada henüz kod yokken zaman harcar; bu zamanın karşılığı ise sonradan, review ve bakım sırasında ortaya çıkar.

Code review’ın neyi tartıştığını da değiştirir. Reviewer niyeti diff’ten yeniden kurmak yerine implementasyonu yazılı bir kabul kriteriyle karşılaştırır. Anlaşmazlıklar da spesifikasyon tarafına taşınır.

Spesifikasyon Kodun Gerisinde Kaldığında#

Gereksinimler değişir. Güncelleme, orijinal spec ile aynı kapıdan girer; SpecKit de değişikliğin nereleri etkilediğini raporlar:

# Development ortasında gereksinimler değiştiğinde
/specify --update

# Yeni gereksinimleri sağla
"Mevcut auth sistemine Google ve GitHub ile OAuth entegrasyonu ekle"

# SpecKit spesifikasyonları günceller ve etkilenen taskları yeniden oluşturur
# Değişikliklerin mevcut implementation üzerindeki etkisini analiz eder

Daha sessiz olan başarısızlık şu: kimse bu komutu çalıştırmaz ve spec zamanla kodu anlatmaz hale gelir. Düzenli bir review geçişi ikisini hizada tutar:

# Düzenli spesifikasyon güncellemeleri
/specify --review

# Implementation öğrenimlerine dayalı spesifikasyonları günceller
# Spec ve gerçeklik arasındaki uyumu korur

Gereğinden Fazla Spesifikasyon#

Her implementation detayını belirtme. Gereksinimlere ve kısıtlara odaklan:

Kötü: "Array'i iterate etmek için for döngüsü kullan ve filter fonksiyon uygula"
İyi: "Son 30 günden sadece aktif kullanıcıları göstermek için kullanıcı datasını filtrele"

AI Araçları Arasında Taşınabilirlik#

SpecKit herhangi bir AI aracıyla çalışan standart dokümantasyon üretir:

# Üretilen spesifikasyonlar araç-bağımsız
## Requirements Document
- Claude Code, GitHub Copilot, Gemini ile uyumlu
- Standart markdown format
- Açık kabul kriterleri
- Farklı AI kodlama araçları arasında taşınabilir

Dört Aşamalı Döngü Ne Zaman Değer Eder#

Döngü, yanlış bir varsayımın spesifikasyondan daha pahalıya patlayacağı kadar yüzey alanı olan özelliklerde masrafını çıkarır: auth akışları, faturalama, veri migrationları, hata modları ancak yük altında ortaya çıkan her şey. Tek dosyalık bir değişiklik ya da bir kerelik bir script için atla; orada spesifikasyon törene dönüşür.

İkinci sınır bakım. Kodla artık örtüşmeyen bir spesifikasyon, ona hâlâ güvenen reviewer’ları yanıltabilir. Gereksinimler, kimsenin spec’i güncelleyebileceğinden hızlı değişiyorsa plan aşamasını mimari kararlar için tut, gerisini bırak.

Makul bir sonraki adım: ertelenmiş tek bir özelliği dört aşamadan geçirmek ve sonucu aynı prompt’un tek başına ürettiğiyle karşılaştırmak.

Kaynaklar#

İlgili yazılar