Tek Dilli Bir Post Tablosunu İki Dilli Yapmak: Gerçek Bir Migration Hikayesi
Blog Post modelini tek dilli (title, content, excerpt) yapıdan titleTr/titleEn, contentTr/contentEn çiftlerine geçirmek basit bir şema değişikliği gibi görünüyordu. Gerçekte iki ayrı engelle karşılaştım.
Yeni NOT NULL kolonlar, mevcut satırla çakışıyor
model Post {
titleTr String @map("title_tr")
titleEn String @map("title_en")
// ...
}
Tabloda zaten eski şemayla oluşturulmuş 1 satır vardı. Yeni titleTr/titleEn kolonları NOT NULL ve default değersiz olduğu için, prisma db push --accept-data-loss bile bu satırı geçemedi — Prisma, var olan bir satıra boş bırakılamayacak yeni bir kolon eklemeyi reddediyor, çünkü o satır için hangi değerin yazılacağını bilmiyor.
prisma migrate reset ya da --force-reset tüm veritabanını (o an 15 proje dahil) sıfırlardı — kabul edilemezdi, sadece tek bir taslak yazı satırı yüzünden bütün kataloğu kaybetmenin hiçbir gerekçesi yok. Çözüm çok daha dar kapsamlı oldu: sadece o tek engelleyici satırı DELETE /api/posts/1 ile admin API üzerinden silmek, sonra push'u tekrar çalıştırmak. Migration artık boş bir tabloya karşı çalıştı ve temiz geçti.
Push başarılı, ama typecheck hâlâ kırık
Push'tan sonra bile typecheck kırılmaya devam etti — sebep kod değil, Prisma Client'ın henüz yeni kolonları bilmemesiydi. prisma db push, veritabanı şemasını günceller ama TypeScript tarafındaki client tiplerini otomatik yeniden üretmiyor; ikisi ayrı adımlar. pnpm exec prisma generate çalıştırmak client'ı güncel şemayla senkronize etti ve typecheck temiz geçti.
Servis katmanında hiçbir değişiklik gerekmedi
En dikkat çekici kısım şuydu: posts.service.ts'deki create()/update() metodları (this.prisma.post.create({ data: input }) gibi) tek satır bile değişmedi. CreatePostInput/UpdatePostInput tipleri zaten packages/schemas'daki Zod şemasından türetiliyordu — şema titleTr/titleEn alanlarını içerecek şekilde güncellenip prisma generate çalıştırılınca, servis kodu yeni şekle otomatik olarak uydu. Schema-first yaklaşımın asıl kazancı burada görünüyor: veri şeklini değiştirmek, onu tüketen her yerde elle senkronizasyon gerektirmiyor.
Çıkarım
Riskli bir veritabanı işleminde araçların seni durdurması can sıkıcı görünebilir ama burada gerçek bir risk vardı: yanlışlıkla tüm katalogu silmek. Sorunun kapsamını "tüm veritabanı" yerine "tek bir satır"a indirgemek, güvenli ve geri dönüşü olmayan bir migration arasındaki farkı yarattı.