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
+62
View File
@@ -0,0 +1,62 @@
---
title: Faz 5 Çok Dilli Domain İçerikleri
description: Proje, görev, planlama alanı ve portal metinleri için content translation altyapısı.
phase: 5
status: completed
last_updated: 2026-07-19
---
# Faz 5 Çok Dilli Domain İçerikleri
Faz-5, UI katalog çevirilerinden farklı olarak kullanıcı/veri içeriklerini
locale bazlı saklayan domain katmanını devreye aldı.
## Tamamlananlar
- `content_translations` tablosu için ortak registry ve field sözleşmesi
oluşturuldu.
- `ContentTranslationService` eklendi.
- FormData içindeki çok dilli alanları okuyup default locale zorunluluğunu
kontrol eden parser eklendi.
- Proje, görev ve planlama alanı create/update/delete akışları content
translations ile senkronlandı.
- Default locale değerleri eski temel kolonlara projection olarak yazılmaya
devam ediyor.
- Liste/detay okuma akışlarında proje, görev ve planlama alanı içerikleri
seçili locale'e göre resolve ediliyor.
- Liste ekranlarında çeviriler batch okunuyor; N+1 pattern'i oluşmuyor.
- Proje oluşturma/düzenleme formu tab'lı çok dilli alanlara taşındı.
- Görev oluşturma/düzenleme formu tab'lı çok dilli alanlara taşındı.
- Proje detayındaki planlama alanı ve proje görev ekleme formları tab'lı çok
dilli alanlara taşındı.
- Genel ayarlar içinde portal karşılama/footer metinleri `branding` entity'si
olarak çok dilli hale getirildi.
- 0008 migration'a eski Türkçe içerikleri `tr` content translation kayıtlarına
taşıyan idempotent backfill eklendi.
- Faz-5 smoke testi eklendi.
## Domain sözleşmesi
İlk kapsamda aktif entity/field seti:
- `project`: `name`, `description`, `coverImageAlt`
- `planning_section`: `title`, `content`
- `task`: `title`, `description`
- `branding`: `portalWelcome`, `portalFooter`
Default locale'de required olan alanlar boş bırakılamaz. Diğer locale'ler
opsiyoneldir ve eksik kaldığında okuma tarafı default locale'e düşer.
## Verification
Çalıştırılan komutlar:
```bash
pnpm i18n:phase5-smoke
pnpm typecheck
pnpm build
git diff --check
```
Sonuçlar başarılı. `pnpm build` sırasında mevcut Next edge runtime static
generation uyarısı tekrar görüldü; Faz-5 kaynaklı yeni bir hata değil.
+59
View File
@@ -0,0 +1,59 @@
---
title: Faz 6 Müşteri Portal Dili ve Davet Akışı
description: Portal daveti, müşteri locale persistence, portal shell ve client-facing içerik çözümleme çıktıları.
phase: 6
status: completed
last_updated: 2026-07-19
---
# Faz 6 Müşteri Portal Dili ve Davet Akışı
Faz-6, müşteri portalının davet anından itibaren seçilen dilde açılmasını ve
client-facing domain içeriklerinin müşteri locale'inde çözülmesini sağlar.
## Tamamlananlar
- Portal daveti oluşturma akışına `locale` eklendi.
- Compatibility `/api/create-client-user` adapter'ı locale kabul eder hale geldi.
- `/api/portal-invitations` sözleşmesi locale kabul eder hale geldi.
- Davet locale'i yalnız aktif dillerden seçilebiliyor.
- Davet oluştururken invitation audit metadata'sına locale eklendi.
- Davet kabulünde:
- `clients.portal_locale` set ediliyor.
- client `user_preferences.language` kaydı oluşturuluyor.
- accepted audit metadata'sına locale ekleniyor.
- Davet preview response'u locale döndürüyor.
- Davet sayfası invitation locale'i ile render ediliyor.
- Portal shell `I18nProvider` ile sarıldı.
- Portal sidebar seçili locale'e göre lokalize ediliyor.
- Portal dashboard, projeler, görevler, revizyonlar ve proje detay sayfasında
temel UI metinleri portal namespace'ine bağlandı.
- Portal tarih formatları locale-aware formatter'a taşındı.
- Portal proje, planlama ve public görev içerikleri client locale'inde resolve
ediliyor.
- Content resolver artık client-facing fallback zincirinde locale fallback +
default locale kullanıyor.
- Müşteri detayında portal dili gösteriliyor/değiştirilebiliyor.
- Portal dili değişince bağlı client session'ları düşürülüyor; sonraki request
yeni locale ile açılıyor.
## Eklenen route
- `PATCH /api/portal-clients/:clientId/locale`
Bu route sadece freelancer session ile çalışır, aktif locale zorunludur ve
client başka müşterinin locale bilgisini değiştiremez.
## Verification
Çalıştırılan komutlar:
```bash
pnpm typecheck
pnpm build
pnpm phase9:smoke
git diff --check
```
Sonuçlar başarılı. `pnpm build` sırasında mevcut Next edge runtime static
generation uyarısı tekrar görüldü; Faz-6 kaynaklı yeni bir hata değil.
+82
View File
@@ -0,0 +1,82 @@
---
title: Faz 7 Auth, Hata ve Erişilebilirlik Bütünlüğü
description: Auth öncesi locale seçimi, stabil hata kodları, edge ekranlar ve a11y metinleri çıktıları.
phase: 7
status: completed
last_updated: 2026-07-19
---
# Faz 7 Auth, Hata ve Erişilebilirlik Bütünlüğü
Faz-7, kullanıcı oturumu oluşmadan önce ve sistem edge ekranlarında görünen
metinlerin locale modeliyle tutarlı çalışmasını tamamlar.
## Tamamlananlar
- Login ekranı aktif instance dillerini listeleyen locale seçici ile açılır.
- Register ekranı aynı locale seçiciyi kullanır ve ilk admin kurulumu instance
default locale/cookie davranışına bağlanır.
- Auth shell sol pazarlama alanı, feature etiketleri ve footer kopyası `auth`
namespace'inden beslenir.
- Forgot/reset password ekranları eklendi ve katalog metinleriyle render edilir.
- 404 ekranı server catalog üzerinden `common.notFound.*` anahtarlarını kullanır.
- Error boundary için built-in TR/EN fallback eklendi.
- Maintenance copy sözleşmesi `common.maintenance.*` anahtarlarıyla kataloglandı.
- Login/signup server action redirect'leri raw mesaj yerine stabil `code`
parametresine taşındı.
- Portal invite error/success redirect'leri stabil auth code kullanır.
- Invite kabulünden sonra invitation locale'i cookie'ye yazılır; login ekranı aynı
dilde açılır.
- `/api/i18n/locale` response'u kullanıcı metni yerine `messageKey` döndürür.
- Locale select kontrolünde label + `aria-label` korunur.
- Auth formlarındaki label, link ve pending metinleri katalogdan gelir.
- Interpolation ve plural davranışı built-in TR/EN katalogları için smoke test ile
doğrulandı.
- RTL temel direction helper smoke testi eklendi.
## Hata kodu sözleşmesi
Auth sayfaları query üzerinden aşağıdaki modeli kabul eder:
```text
/login?error=true&code=auth.messages.invalidCredentials
/register?error=true&code=auth.messages.signupFailed
/login?code=auth.invite.success
```
Geriye dönük uyumluluk için eski `message` parametresi okunur; yeni server
action'lar raw mesaj üretmez.
## Bildirim/e-posta locale sözleşmesi
İleride e-posta veya notification sistemi eklendiğinde locale önceliği şu
sırayı izlemelidir:
1. Client portal hesabı için `clients.portal_locale`
2. Auth user preference için `user_preferences.language`
3. Invite veya event üzerinde snapshot locale
4. Instance default locale
5. Built-in fallback `tr`
Template key'leri UI kataloglarıyla aynı namespace mantığını kullanmalı, fakat
uzun mail içerikleri ayrı `notification` veya `email` namespace'ine taşınmalıdır.
## RTL notu
`directionForLocale("ar" | "fa" | "he" | "ur")` temel RTL direction üretir.
Faz-7 smoke testi auth shell ve form katmanının direction bilgisini bozmadığını
doğrular. Tam görsel RTL polish için sonraki hardening fazında sayfa bazlı görsel
kontrol önerilir.
## Verification
Çalıştırılan komutlar:
```bash
pnpm i18n:phase7-smoke
pnpm typecheck
pnpm build
git diff --check
```
Sonuçlar başarılı olduğunda Faz-7 tamamlanmış kabul edilir.
@@ -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.