chore: add i18n release hardening gates
This commit is contained in:
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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. 0000–0007 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.
|
||||
Reference in New Issue
Block a user