chore: add i18n release hardening gates

This commit is contained in:
poyrazavsever
2026-07-19 03:08:07 +03:00
parent 178f285191
commit 7d82bcc4f1
13 changed files with 943 additions and 10 deletions
@@ -0,0 +1,229 @@
---
title: I18n Faz 9 — Hardening, Migrasyon ve Release Readiness
description: Çok dilli sistemin self-host production yayınına hazır olduğunu gösteren migration, backup, API, Dokploy ve operasyon raporu.
phase: 9
status: completed
last_updated: 2026-07-19
---
# I18n Faz 9 — Hardening, migrasyon ve release readiness
Faz-9, çok dilli sistemin production self-host kurulumunda güvenli şekilde
yayınlanabilmesi için migration, backup/restore, import, mobil API ve operasyon
kapılarını kapatır.
## Sonuç
Çok dilli sistem release adayıdır.
- Yeni kurulumda `tr` ve `en` aktif gelir, default locale `tr` olur.
- Eski Türkçe kolonlar `content_translations` içine `tr` locale'iyle backfill
edilir.
- Backfill tekrar çalışan migration'da duplicate üretmez.
- `fr` custom locale, content translation, backup ve restore zincirinde korunur.
- API v1 localization sözleşmesi additive ve eski mobil client'larla uyumludur.
- Runtime Supabase bağımlılığı veya Supabase env kullanımı geri gelmemiştir.
- Built-in kataloglar standalone server bundle içinde bulunur.
## Release kapıları
### Migration
`pnpm i18n:phase9-hardening` şu migration senaryolarını gerçek temp SQLite DB
üzerinde çalıştırır:
1. Boş DB migration.
2. Boş DB üzerinde ikinci migration çalıştırması.
3. 00000007 arası eski schema üzerinde production-benzeri Türkçe veri.
4. 0008 i18n migration'ı sonrası Türkçe backfill doğrulaması.
5. Aynı DB üzerinde tekrar migration ve idempotent count kontrolü.
Backfill doğrulanan alanlar:
- `project.name`
- `project.description`
- `task.title`
- `planning_section.title`
- `branding.portalWelcome`
### Backup ve restore
Hardening smoke, production-benzeri DB'ye `fr` custom locale ve Fransızca proje
çevirisi ekler, backup alır ve ayrı bir data directory içine restore eder.
Restore sonrası:
- `instance_locales.fr` aktif kalır.
- `content_translations` içindeki Fransızca çeviri korunur.
- `foreign_key_check` temiz döner.
Restore failure prosedürü de test edilir: checksum'u bozulan backup restore
edilmez ve mevcut hedef DB korunur.
### Supabase import uyumu
Faz-9, Supabase import aracının Faz-8 smoke kapsamını release blocker kabul eder.
`phase8:import-smoke` şu davranışları doğrular:
- dry-run DB'yi değiştirmez;
- apply import kayıtları taşır;
- `--allow-existing` idempotent upsert yapar;
- invalid enum, eksik foreign key ve unsafe storage path reddedilir;
- pre-import backup restore ile rollback provası yapılır.
Import aracı Supabase SDK kullanmaz; offline `neta-supabase-export` bundle'ını
okur.
## Dokploy / Docker operasyon notu
Dokploy'da `/app/data` kalıcı volume olmalıdır. Bu volume şunları taşır:
- `neta.db`
- `uploads/`
- `backups/`
- `tmp/`
Production deploy öncesi:
```bash
pnpm db:backup -- --retention-count 14
```
Restore provası production volume üstüne değil, ayrı geçici hedefe yapılmalıdır:
```bash
pnpm db:restore -- \
--from /app/data/backups/neta-TIMESTAMP \
--target /tmp/neta-restore-rehearsal \
--force
```
Translation tabloları `neta.db` içinde olduğu için backup/restore kapsamında
otomatik korunur:
- `instance_locales`
- `instance_i18n_settings`
- `instance_ui_translations`
- `content_translations`
- `clients.portal_locale`
- `portal_invitations.locale`
- `user_preferences.language`
## Self-host default locale
Yeni kurulumda default locale `tr` olur. Owner Ayarlar üzerinden varsayılan dili
aktif başka bir locale'e alabilir. Default locale yalnız `active` locale olabilir;
draft veya archived locale default yapılamaz.
Mobil istemciler instance dil bilgisini şu endpoint'lerden keşfeder:
- `GET /.well-known/neta`
- `GET /api/v1/meta`
- `GET /api/v1/me`
## Dil ekleme ve import/export rehberi
Owner akışı:
1. Ayarlar → Diller ve çeviriler bölümünden yeni locale ekle.
2. Locale'i önce `draft` olarak tut.
3. UI çeviri eksiklerini tamamla veya JSON import ile yükle.
4. İçerik formlarındaki locale tab'larında proje/görev/portal metinlerini gir.
5. Portal'a hazır olduğunda locale'i `active` yap.
6. Gerekirse varsayılan locale'i değiştir.
Import/export:
- UI çeviri export paketi `neta-i18n` formatındadır.
- Import yalnız owner scope ile çalışır.
- Built-in locale'ler silinmez veya archived yapılamaz.
- Bozuk namespace/key/value import'u validation ile reddedilir.
## Portal müşterisine dil atama
Müşteri portal dili iki noktada belirlenir:
1. Portal daveti oluştururken seçilen locale.
2. Müşteri detayındaki portal dili ayarı.
Davet kabul edildiğinde:
- `clients.portal_locale` set edilir;
- client user preference dili aynı locale'e alınır;
- davet kabulü sonrası login ekranı davet locale'iyle açılır.
## Mobil API localization sözleşmesi
Mobil taraf locale'i şu sırayla çözmelidir:
1. Explicit query: `/api/v1/me?locale=en`
2. Better Auth session preference
3. Client portal locale
4. `Accept-Language`
5. Instance default locale
Unsupported explicit locale için server:
```json
{
"ok": false,
"error": {
"code": "UNSUPPORTED_LOCALE",
"message": "Unsupported locale.",
"details": {
"messageKey": "validation.unsupportedLocale"
}
}
}
```
Client kullanıcıya gösterilecek metni kendi catalog'undan `messageKey` ile
çözmelidir; program akışı stabil `code` alanına bağlanmalıdır.
## Gözlem ve performans
Faz-9 smoke seviyesi performans kapıları:
- Dashboard ve portal listeleri batch content resolver kullanır; N+1 translation
sorgusu release riski kabul edilir.
- Missing translation durumunda raw key production kullanıcı arayüzüne düşmemeli;
fallback chain kullanılmalıdır.
- Catalog version, UI translation mutation'larında artar ve mobil meta cache
invalidation için kullanılabilir.
- Hassas içerik loglanmamalıdır; missing translation log'u key/locale seviyesinde
kalmalıdır.
## Verification
Çalıştırılan komutlar:
```bash
pnpm phase-i18n:boundary
pnpm i18n:phase9-hardening
pnpm i18n:phase8-smoke
pnpm i18n:phase7-smoke
pnpm i18n:phase5-smoke
pnpm i18n:phase3-smoke
pnpm i18n:phase2-smoke
pnpm i18n:phase1-smoke
pnpm phase8:import-smoke
pnpm typecheck
pnpm build
pnpm phase9:smoke
git diff --check
```
`phase9:smoke` local listener açtığı için sandbox içinde `EPERM` alabilir; bu
durumda izinli çalıştırılmalıdır.
## Release uyarısı
Bu rapor teknik release readiness sağlar. Gerçek production cutover için ortam
sahibi yine şu dış adımları yürütmelidir:
- production backup;
- maintenance/read-only penceresi;
- final Supabase export/import;
- gerçek satır ve dosya checksum karşılaştırması;
- owner/client kabul smoke'u;
- DNS/reverse proxy geçişi;
- rollback retention penceresi.