docs: add multilingual i18n rollout plan

This commit is contained in:
poyrazavsever
2026-07-19 03:06:30 +03:00
parent bace8c86cf
commit 0548820584
11 changed files with 2498 additions and 0 deletions
@@ -0,0 +1,171 @@
---
title: Faz 0 ADR Seti
description: Neta cok dilli sisteminin baslangic karar kayitlari.
phase: 0
status: accepted
last_updated: 2026-07-19
---
# Faz 0 ADR Seti
Bu dosya cok dillilik calismasinin ilk uygulama kararlarini kilitler. Amac,
sonraki fazlarda ayni problemi tekrar tekrar tartismadan ilerleyebilmek ve
SQLite tabanli self-host hedefini korumaktir.
## ADR-I18N-0001 — UI cevirisi ve domain icerik cevirisi ayrilacak
### Durum
Kabul edildi.
### Baglam
Neta'da iki farkli metin tipi var:
- Uygulamanin kendisine ait sabit arayuz metinleri.
- Freelancer veya musteri tarafindan uretilen is icerikleri.
Bu iki veri tipini ayni tabloda veya ayni anahtar modeliyle tutmak, hem fallback
hem de izin modeli tarafinda karmasa yaratir.
### Karar
Arayuz cevirileri stabil katalog anahtarlariyla yonetilecek. Built-in `tr` ve
`en` kataloglari kod icinde surumlenecek; instance sahibi tarafindan eklenen
override'lar SQLite icindeki `instance_ui_translations` modelinde tutulacak.
Domain icerik cevirileri entity ve field bazli tutulacak. Bunun icin Faz-1'de
`content_translations` modeli eklenecek.
### Sonuc
- Arayuz metinleri release sureciyle denetlenebilir kalir.
- Sonradan eklenen diller deployment gerektirmeden doldurulabilir.
- Is icerikleri icin form tab'lari net bicimde modellenir.
- Chat, gunluk notu ve musteri mesajlari gibi iletisim icerikleri otomatik
cevrilmez; yazildigi dilde kalir.
## ADR-I18N-0002 — Locale cozumleme onceligi
### Durum
Kabul edildi.
### Baglam
Ayni instance icinde freelancer, musteri portali, davet ekranlari ve public API
farkli baglamlarda calisir. Locale cozumleme her yerde ayni kaynaga bakarsa
portal daveti gibi auth oncesi akislarda yanlis dil gorunebilir.
### Karar
Locale asagidaki sirayla cozumlenecek.
Auth oncesi davet ekranlari:
1. Davet kaydindaki locale.
2. Guvenli locale cookie'si.
3. Instance varsayilan dili.
4. Built-in fallback `tr`.
Freelancer uygulamasi:
1. Oturum acmis kullanicinin `user_preferences.language` degeri.
2. Guvenli locale cookie'si.
3. Instance varsayilan dili.
4. Built-in fallback `tr`.
Musteri portali:
1. Musteri profilinin veya `clients.portal_locale` alaninin locale degeri.
2. Portal davetinden gelen locale.
3. Guvenli locale cookie'si.
4. Instance varsayilan dili.
5. Built-in fallback `tr`.
Mobil ve API istekleri:
1. Auth kullanicisinin kayitli tercihi.
2. Guvenilir endpoint parametresi veya `Accept-Language` sinyali.
3. Instance varsayilan dili.
4. Built-in fallback `tr`.
### Sonuc
- Musteri davet ekrani login olmadan dogru dilde acilir.
- Freelancer tercihi musteri portalini yanlislikla etkilemez.
- Mobil istemci ayni kurallari API kontratindan okuyabilir.
## ADR-I18N-0003 — Dashboard ve portal route'larina locale prefix eklenmeyecek
### Durum
Kabul edildi.
### Baglam
`/tr/dashboard`, `/en/dashboard` gibi route prefix'leri public marketing
sitelerinde gucludur, ancak Neta'nin dashboard ve portal yapisi oturum, davet,
yetki ve self-host basitligi uzerine kurulu. Prefix eklemek route sayisini,
redirect davranislarini ve mobil endpoint eslemesini gereksiz buyutur.
### Karar
Dashboard, portal ve davet route'lari mevcut URL yapisini koruyacak. Dil, locale
resolver ve cookie/user/client kayitlariyla belirlenecek.
### Sonuc
- Var olan internal linkler ve mobil baglanti modeli korunur.
- Self-host deploy ve reverse proxy ayarlari sade kalir.
- Public landing/docs tarafi isterse ileride ayri route prefix stratejisi
kullanabilir; bu karar sadece uygulama kabugu icindir.
## ADR-I18N-0004 — Hafif custom runtime i18n katmani yazilacak
### Durum
Kabul edildi.
### Baglam
Projenin ana hedeflerinden biri dependency sayisini azaltmak ve self-host'u
kolaylastirmak. Mevcut ihtiyaclar temel katalog cozumleme, fallback, namespace
yukleme, `Intl` bicimlendirme ve SQLite override okuma uzerinden karsilanabilir.
### Karar
Ilk cok dillilik surumunde agir bir i18n runtime dependency'si eklenmeyecek.
Neta icinde kucuk bir i18n katmani yazilacak:
- `lib/i18n/*` ortak tip ve format yardimcilari.
- `server/i18n/*` locale resolver, katalog merge ve translator servisleri.
- Client component'ler icin sinirli scope'ta provider.
- Tarih, sayi ve para bicimlendirme icin native `Intl`.
### Sonuc
- Yeni dependency eklenmeden Faz-2 runtime kurulabilir.
- Katalog sozlesmesi Neta'nin domain ihtiyaclarina gore sekillenir.
- Ileride ihtiyac buyurse baska kutuphaneye gecis icin katalog anahtarlari
korunabilir.
## ADR-I18N-0005 — Built-in diller ve yayin kurali
### Durum
Kabul edildi.
### Karar
Turkce (`tr`) ve Ingilizce (`en`) built-in, aktif ve silinemez diller olacak.
Instance varsayilan dili ilk migration sonrasinda `tr` olacak.
Yeni eklenen diller once `draft` durumunda olusturulacak. Portal icin kritik
namespace'leri tamamlanmayan bir dil musteri dili olarak secilemeyecek.
### Sonuc
- Eksik ceviri musteriye yarim bir portal deneyimi olarak yansimaz.
- Instance sahibi yeni dili hazirlayip test ettikten sonra aktif edebilir.
- Fallback davranisi her zaman tahmin edilebilir kalir.
@@ -0,0 +1,44 @@
---
title: Faz 0 Baseline Sonuclari
description: Cok dillilik calismasi baslamadan onceki build, typecheck ve smoke referansi.
phase: 0
status: completed
last_updated: 2026-07-19
---
# Faz 0 Baseline Sonuclari
Bu baseline, cok dillilik kod degisikliklerinden onceki saglik referansidir.
Sonraki fazlarda yeni hata olup olmadigini anlamak icin bu komut setiyle
karsilastirma yapilacak.
## Komut sonuclari
| Komut | Sonuc | Not |
| --- | --- | --- |
| `pnpm typecheck` | Basarili | `tsc --noEmit` hatasiz tamamlandi. |
| `pnpm build` | Basarili | Next.js 16.2.10 production build ve standalone hazirlama tamamlandi. |
| `pnpm phase9:smoke` | Basarili | API boundary, auth/invitation ve mobile API smoke kapilari gecti. |
## Build notu
`pnpm build` sirasinda su Next.js uyarisi goruldu:
```text
Using edge runtime on a page currently disables static generation for that page
```
Bu Faz-0 icin yeni bir hata degil; mevcut route/runtime tercihinden kaynaklanan
uyari olarak kaydedildi.
## Faz-1 icin baseline beklentisi
Faz-1 sonunda en az asagidaki komutlar tekrar calistirilmelidir:
- `pnpm typecheck`
- `pnpm build`
- Locale migration eklendikten sonra ilgili DB smoke komutu
- Varsa yeni `i18n` service unit/smoke komutu
Faz-5 ve Faz-6 gibi domain/portal davranisi degisen fazlarda `phase6:smoke` ve
portal-specific fixture testleri de baseline setine eklenmelidir.
@@ -0,0 +1,181 @@
---
title: Faz 0 I18n Fixture Plani
description: Cok dillilik migration, katalog ve portal testleri icin seed senaryolari.
phase: 0
status: completed
last_updated: 2026-07-19
---
# Faz 0 I18n Fixture Plani
Bu plan Faz-1 sonrasinda script veya test fixture'ina donusturulecek veri setini
tanımlar. Hedef, locale resolver, fallback, domain icerik cevirileri ve portal
dili davranisini ayni senaryoda dogrulamaktir.
## Locale fixture'lari
| Locale | Durum | Built-in | Fallback | Amac |
| --- | --- | --- | --- | --- |
| `tr` | `active` | Evet | Yok | Instance default ve mevcut verinin ana dili. |
| `en` | `active` | Evet | `tr` | Built-in ikinci dil ve portal client testi. |
| `fr` | `draft` | Hayir | `en` | Eksik katalog/fallback testi. |
| `ar-XB` | `test` | Hayir | `en` | RTL smoke ve layout kontrolu. |
`tr` ve `en` silinemez. `fr` portal dili olarak ancak kritik portal namespace'leri
tamamlaninca secilebilir. `ar-XB` urun ayarlarinda normal kullaniciya
gosterilmez.
## Katalog fixture'lari
### Turkce built-in katalog
Tum namespace'lerde eksiksiz olmalidir:
- `common`
- `auth`
- `navigation`
- `dashboard`
- `clients`
- `projects`
- `tasks`
- `calendar`
- `finance`
- `journal`
- `chat`
- `settings`
- `portal`
- `status`
- `validation`
- `api`
### Ingilizce built-in katalog
Turkce ile ayni anahtar setine sahip olmalidir. Faz-2 testinde anahtar farki
release engeli kabul edilir.
### Eksik Fransizca katalog
Fallback test etmek icin bilincli olarak kismi tutulur.
Ornek:
```json
{
"navigation.dashboard": "Tableau de bord",
"navigation.projects": "Projets",
"portal.dashboard.title": "Apercu",
"common.save": "Enregistrer"
}
```
Beklenen davranis: Eksik `portal.tasks.title` gibi anahtarlarda once `en`, sonra
`tr` fallback metni gosterilir; kullaniciya ham anahtar basılmaz.
## Auth fixture'lari
| Kullanici | Rol | Email | Dil | Baglam |
| --- | --- | --- | --- | --- |
| Freelancer | `admin` | `owner@neta.local` | `tr` | Dashboard, ayarlar ve ceviri yonetimi. |
| Turkce musteri | `client` | `client-tr@neta.local` | `tr` | Portal default dil testi. |
| Ingilizce musteri | `client` | `client-en@neta.local` | `en` | Portal client locale testi. |
Freelancer hesabi instance default dilini `tr` olarak korur. Ingilizce musteri
icin davet kaydinda ve `clients.portal_locale` alaninda `en` beklenir.
## Domain veri fixture'i
### Musteriler
| ID | Ad | Portal dili | Not |
| --- | --- | --- | --- |
| `client-tr` | Ada Yilmaz | `tr` | Turkce portal goruntusu. |
| `client-en` | Nova Studio | `en` | Ingilizce portal goruntusu. |
### Projeler
| ID | Musteri | Default baslik | EN baslik | FR baslik | Not |
| --- | --- | --- | --- | --- |
| `project-website` | `client-tr` | Web sitesi yenileme | Website refresh | Bos | Fallback testi. |
| `project-brand` | `client-en` | Marka kiti | Brand kit | Kit de marque | Portal EN ve FR content testi. |
Beklenen davranis:
- `tr` isteyen kullanici default kolon veya `content_translations(tr)` degerini
gorur.
- `en` isteyen kullanici EN content translation'i gorur.
- `fr` isteyen kullanici FR alan bos ise fallback zinciriyle EN veya TR gorur.
### Gorevler
| ID | Proje | Public | TR baslik | EN baslik |
| --- | --- | --- | --- | --- |
| `task-wireframe` | `project-website` | Evet | Ana sayfa wireframe | Homepage wireframe |
| `task-internal` | `project-website` | Hayir | Ic notlari toparla | Gather internal notes |
Portal yalnizca `is_public_to_client = true` gorevleri gosterir.
### Planlama bolumleri
| ID | Proje | Kategori | TR baslik | EN baslik |
| --- | --- | --- | --- | --- |
| `plan-scope` | `project-website` | `scope` | Kapsam | Scope |
| `plan-delivery` | `project-website` | `delivery` | Teslimat | Delivery |
Kategori teknik degeri cevrilmez; label `status` veya `projects` namespace'inden
gelir.
## Portal davet fixture'lari
| Davet | Email | Locale | Beklenen ekran dili |
| --- | --- | --- | --- |
| `invite-tr` | `client-tr@neta.local` | `tr` | Turkce |
| `invite-en` | `client-en@neta.local` | `en` | Ingilizce |
| `invite-fr-draft` | `client-en@neta.local` | `fr` | Portal publish kurali nedeniyle reddedilir veya fallback EN kullanir. |
Davet ekranlari auth oncesi oldugu icin locale'i session'dan degil davet
kaydindan alir.
## API contract fixture'lari
`/api/v1/meta` Faz-8 sonunda en az su localization bilgisini dondurmelidir:
```json
{
"localization": {
"defaultLocale": "tr",
"supportedLocales": [
{ "code": "tr", "name": "Turkce", "status": "active", "builtIn": true },
{ "code": "en", "name": "English", "status": "active", "builtIn": true },
{ "code": "fr", "name": "Francais", "status": "draft", "builtIn": false }
],
"fallbacks": {
"en": "tr",
"fr": "en"
}
}
}
```
Mobil istemci aktif olmayan dilleri kullanici seciminde gostermemeli, ancak
ceviri yonetimi ekranlari icin admin API'de draft dilleri gorebilmelidir.
## Smoke beklentileri
Faz-2 sonrasinda:
- `t("common.save")` `tr` icin `Kaydet`, `en` icin `Save` dondurur.
- `fr` locale'inde eksik anahtar ham key olarak gosterilmez.
- `formatMoney(10000, "TRY", "tr")` Turkce bicim verir.
- `formatDate(..., "en")` Ingilizce ay adi verir.
Faz-6 sonrasinda:
- `client-en` portali EN navigasyon ve EN proje basliklariyla acilir.
- `client-tr` portali TR kalir.
- Davet kabul edildikten sonra secilen locale client kaydina yansir.
Faz-8 sonrasinda:
- `/api/v1/meta` supported locale listesini dondurur.
- `/api/v1/me` kullanicinin etkin locale'ini ve fallback chain'ini dondurur.
- API hata response'lari stabil kod + locale'e uygun insan okunur mesaj tasir.
@@ -0,0 +1,149 @@
---
title: Faz 0 I18n Envanteri
description: Kullaniciya gorunen metinler, locale sabitleri ve namespace migration envanteri.
phase: 0
status: completed
last_updated: 2026-07-19
---
# Faz 0 I18n Envanteri
Bu envanter Faz-1 ve Faz-2 icin kapsam sinirini belirler. Liste uygulama
kodunun mevcut durumuna gore hazirlandi; yeni sayfa eklendikce ayni namespace
modeliyle genisletilmelidir.
## Namespace standardi
Katalog anahtarlari `namespace.section.item` biciminde olacak. Turkce cumleler
anahtar olarak kullanilmayacak.
| Namespace | Sahip oldugu alan |
| --- | --- |
| `common` | Kaydet, iptal, sil, ara, filtrele, yukleniyor, bos durum, toast eylemleri |
| `auth` | Login, register, setup, davet kabul, auth hata mesajlari |
| `navigation` | Freelancer ve portal sidebar grup/link label'lari |
| `dashboard` | Freelancer ana sayfa basliklari, stats, grafik ve son kayit kartlari |
| `clients` | Musteri liste, detay, form, portal hesap islemleri |
| `projects` | Proje liste, detay, form, planlama, revizyon ve risk analizi |
| `tasks` | Gorev liste, kanban, form, durum ve oncelik UI metinleri |
| `calendar` | Takvim, etkinlik kartlari, etkinlik formu |
| `finance` | Finans stats, islem formu, kategori, AI analiz modal'i |
| `journal` | Gunluk liste, form, mood/enerji label'lari |
| `chat` | Sohbet listesi, bos durum, hata ve input metinleri |
| `settings` | Genel gorunum, marka, AI, profil, dil yonetimi |
| `portal` | Musteri portal dashboard, projeler, gorevler, revizyonlar |
| `status` | Enum label'lari: status, priority, type, pipeline, payment |
| `validation` | Form/action hata ve basari mesajlari |
| `api` | Mobil/public API hata kodlari icin insan okunur mesajlar |
## Freelancer migration listesi
Faz-4'te asagidaki sirayla UI sabitleri katalog anahtarina alinacak.
| Sira | Route veya dosya | Namespace'ler | Not |
| --- | --- | --- | --- |
| 1 | `config/sidebar.ts` | `navigation` | Sidebar link ve grup adlari merkezi baslangic noktasi. |
| 2 | `components/layout/app-shell.tsx` | `navigation`, `common`, `settings` | Account menu, tema ve layout metinleri. |
| 3 | `app/(dashboard)/page.tsx`, `dashboard-client.tsx` | `dashboard`, `common`, `status` | Ana stats, grafik bos durumlari ve tarih/para formatlari. |
| 4 | `app/(dashboard)/clients/*` | `clients`, `common`, `status`, `validation` | Liste, detay, portal hesabi, activity mesajlari. |
| 5 | `app/(dashboard)/projects/*` | `projects`, `common`, `status`, `validation` | Proje formu, planlama, revizyon ve risk analizi. |
| 6 | `app/(dashboard)/tasks/*` | `tasks`, `common`, `status`, `validation` | Liste/kanban ayrimi ve gorev action metinleri. |
| 7 | `app/(dashboard)/calendar/*` | `calendar`, `common`, `status` | Date formatting Faz-2 format yardimcilarina tasinir. |
| 8 | `app/(dashboard)/finance/*` | `finance`, `common`, `status`, `validation` | Para formatting ve AI modal metinleri. |
| 9 | `app/(dashboard)/journal/*` | `journal`, `common`, `validation` | Mood label'lari ve date formatter'lar. |
| 10 | `app/(dashboard)/chat/*`, `app/api/chat/route.ts` | `chat`, `api`, `validation` | Kullaniciya donen hata mesaji daha detayli hale getirilmisti; i18n anahtariyla baglanacak. |
| 11 | `app/(dashboard)/settings/*` | `settings`, `common`, `validation` | Dil yonetimi Faz-3'te eklenecegi icin en son genisletilir. |
| 12 | `app/(dashboard)/analytics/*`, `business/*` | `dashboard`, `finance`, `common` | Mevcut business ekranlari i18n kapsamina alinacak. |
## Portal migration listesi
Portal Faz-6'da musteri diliyle birlikte ele alinacak.
| Sira | Route veya dosya | Namespace'ler | Not |
| --- | --- | --- | --- |
| 1 | `config/portal-sidebar.ts` | `navigation`, `portal` | Portal navigasyon label'lari. |
| 2 | `components/layout/portal-shell.tsx` | `portal`, `navigation`, `common` | Kullanici menu ve kabuk metinleri. |
| 3 | `app/portal/page.tsx` | `portal`, `dashboard`, `common` | Musteri dashboard stats ve bos durumlari. |
| 4 | `app/portal/projects/page.tsx` | `portal`, `projects`, `status` | Proje liste metinleri ve tarih formatlari. |
| 5 | `app/portal/projects/[id]/*` | `portal`, `projects`, `tasks`, `status`, `validation` | Cevrilebilir project/task content resolver kullanir. |
| 6 | `app/portal/tasks/page.tsx` | `portal`, `tasks`, `status` | Public gorev metinleri. |
| 7 | `app/portal/revisions/page.tsx` | `portal`, `projects`, `validation` | Revizyon talepleri yazildigi dilde kalir. |
| 8 | `app/invite/[token]/*` | `auth`, `portal`, `validation` | Auth oncesi davet locale'iyle render edilir. |
## Auth ve API migration listesi
| Alan | Dosya | Namespace | Not |
| --- | --- | --- | --- |
| Admin setup | `app/register/page.tsx`, `app/login/*` | `auth`, `validation` | Cift toast fix'i korunarak metinler kataloglanir. |
| Better Auth route | `app/api/auth/[...all]/route.ts` | `api`, `auth` | Kullaniciya acik hata mapping'i gerekir. |
| Portal invitations API | `app/api/portal-invitations/*` | `api`, `portal` | Locale parametresi Faz-6'da kontrata eklenir. |
| Mobile API v1 | `app/api/v1/*`, `server/api/v1/*` | `api`, `common` | Meta endpoint supported/default locale bilgisini dondurur. |
| Branding API | `app/api/branding/*` | `api`, `settings` | Workspace gorunum metinleri ve mobile consumption ayni kalir. |
## Sabit locale kullanimlari
Asagidaki kullanimlar Faz-2 format yardimcilariyla degistirilecek.
| Kullanim | Dosyalar |
| --- | --- |
| `<html lang="tr">` | `app/layout.tsx` |
| `date-fns/locale/tr` | `app/portal/page.tsx`, `app/portal/projects/page.tsx`, `app/portal/tasks/page.tsx`, `app/portal/revisions/page.tsx`, `app/portal/projects/[id]/portal-project-client.tsx`, `app/(dashboard)/clients/clients-client.tsx`, `app/(dashboard)/clients/[id]/client-detail-client.tsx`, `app/(dashboard)/business/proposals/proposals-client.tsx`, `app/(dashboard)/business/invoices/invoices-client.tsx`, `app/(dashboard)/business/subscriptions/subscriptions-client.tsx` |
| `Intl.*("tr-TR")` | `dashboard-client.tsx`, `calendar-client.tsx`, `finance-client.tsx`, `journal-client.tsx`, `projects-client.tsx`, `project-detail-client.tsx`, `tasks-client.tsx`, business client'lari |
| `toLocaleDateString("tr-TR")` | `dashboard-client.tsx`, `project-detail-client.tsx` |
| `localeCompare(..., "tr")` | `app/(dashboard)/projects/page.tsx` |
## Kullaniciya gorunen sabit metin kaynaklari
Turkce karakter iceren veya dogrudan kullaniciya donen string barindirma ihtimali
en yuksek alanlar:
| Klasor | Kapsam |
| --- | --- |
| `app/(dashboard)` | Freelancer ekranlarinin buyuk bolumu. |
| `app/portal` | Musteri portali. |
| `app/invite` | Auth oncesi portal daveti. |
| `app/login`, `app/register` | Auth ekranlari. |
| `app/api` | Kullaniciya donen JSON hata/basari metinleri. |
| `components/layout` | Sidebar, account menu ve shell metinleri. |
| `components/system` | Ortak page header, stat card ve empty/error state metinleri. |
| `config/sidebar.ts` | Freelancer navigasyon metinleri. |
| `config/portal-sidebar.ts` | Portal navigasyon metinleri. |
| `server/auth`, `server/services`, `server/ai` | Server action/API hata ve toast mesajlari. |
## Cevrilebilir domain alan registry'si
Ilk surumde asagidaki alanlar `content_translations` ile locale bazli
cevrilebilir kabul edilir.
| Entity | Field | Zorunlu locale | Not |
| --- | --- | --- | --- |
| `projects` | `name` | Instance default | Mevcut kolon backfill kaynagi. |
| `projects` | `description` | Opsiyonel | Portal ve freelancer detayinda kullanilir. |
| `projects` | `coverImageAlt` | Opsiyonel | A11y icin portalda onemli. |
| `tasks` | `title` | Instance default | Public/private fark etmeksizin ayni alan modeli. |
| `tasks` | `description` | Opsiyonel | Musteriye acik gorevlerde portalda gosterilir. |
| `calendar_events` | `title` | Instance default | Etkinlik ortak alandir, ileride portal visibility eklenirse hazir. |
| `calendar_events` | `description` | Opsiyonel | |
| `clients` | `notes` | Opsiyonel | Ilk surumde internal kalir; ceviri desteklenebilir ama portalda gosterilmez. |
| `planning_sections` | `title` | Instance default | Proje planlama bolumleri icin. |
| `planning_sections` | `content` | Opsiyonel | Rich text degilse plain text olarak saklanir. |
| `branding/settings` | `workspaceName` | Instance default | UI/portal basliklari ve mobile meta icin. |
| `branding/settings` | `metaTitle` | Instance default | Browser metadata. |
| `branding/settings` | `metaDescription` | Opsiyonel | SEO/public metadata. |
Ilk surumde cevrilmeyecek alanlar:
- Chat mesajlari.
- Revizyon talepleri.
- Gunluk notlari.
- Finans islem aciklamalari.
- Maliyet, tarih, para birimi, yuzde ve enum teknik degerleri.
## RTL test locale'i
Ilk release hedefi LTR diller olsa da layout kirilmasini erkenden gormek icin
test locale'i `ar-XB` olarak belirlendi.
Bu locale aktif urun dili olarak sunulmayacak. Faz-7'de `dir="rtl"` davranisini,
sidebar hizalamalarini, form tab'larini ve modal yerlesimlerini smoke etmek icin
fixture olarak kullanilacak.
@@ -0,0 +1,84 @@
---
title: Faz 0 Migration ve Geri Donus Sozlesmesi
description: Cok dillilik calismasi icin expand/migrate/contract sirasi ve backup kurallari.
phase: 0
status: completed
last_updated: 2026-07-19
---
# Faz 0 Migration ve Geri Donus Sozlesmesi
Bu sozlesme Faz-1'den itibaren veritabani degisikliklerinin nasil yapilacagini
tanımlar. Neta self-host bir urun oldugu icin migration'lar veri kaybi riski
tasimamali ve rollback hikayesi basit kalmalidir.
## Uygulama sirasi
1. Expand
Yeni tablolar ve yeni nullable kolonlar eklenir. Mevcut kolonlar kaldirilmaz,
renamelenmez ve zorunlu hale getirilmez.
2. Backfill
Mevcut Turkce veriler instance default locale'i kabul edilerek
`content_translations` icine kopyalanir. Orijinal kolonlar okunabilir kalir.
3. Dual read
Okuma katmani once translation resolver'a bakar, eksikse mevcut kolona duser.
Bu asamada eski veriler ve yeni veriler ayni anda calisir.
4. Dual write
Formlar instance default locale alanini hem mevcut kolona hem translation
tablosuna yazar. Ek locale'ler sadece translation tablosuna yazilir.
5. Contract
Ancak en az bir release sonra eski kolonlarin kaldirilmasi veya tamamen internal
fallback haline getirilmesi tartisilir. Ilk cok dillilik fazlarinda contract
adimi yapilmayacak.
## Backup adimlari
Her schema migration oncesi:
```bash
pnpm db:backup
```
Backup dosyasi deploy notuna yazilmalidir. Dokploy veya Docker deploy'da volume
path'i kontrol edilmeden migration calistirilmamalidir.
## Geri donus adimlari
Migration sonrasi kritik hata varsa:
1. Uygulama yeni surumden onceki image/commit'e geri alinir.
2. SQLite dosyasi backup'tan restore edilir.
3. `pnpm db:restore <backup-file>` veya host tarafindaki manuel restore adimi
kullanilir.
4. Restore sonrasi `pnpm phase9:smoke` ile health/API temel davranisi kontrol
edilir.
## Faz bazli DB dokunuslari
| Faz | DB degisikligi | Risk | Not |
| --- | --- | --- | --- |
| Faz-1 | Locale ve translation tablolari, `clients.portal_locale`, `portal_invitations.locale`, preference check constraint genisletme | Orta | Expand only. |
| Faz-2 | DB yok veya yalnizca katalog version seed'i | Dusuk | Runtime/cache agirlikli. |
| Faz-3 | UI translation CRUD | Orta | Admin-only mutation ve audit gerekli. |
| Faz-5 | Domain content translations dual write | Yuksek | Backfill ve resolver testleri sart. |
| Faz-6 | Portal locale davet akisi | Orta | Auth oncesi davet dili kritik. |
| Faz-8 | API contract genisletme | Dusuk/Orta | Backward compatible response alanlari eklenir. |
## Non-goal
Ilk cok dillilik release'inde asagidakiler yapilmayacak:
- Mevcut `projects.name`, `tasks.title` gibi kolonlari kaldirmak.
- Otomatik makine cevirisi eklemek.
- Public route'lara locale prefix eklemek.
- Chat/gunluk/revizyon taleplerini otomatik cevirmek.
- Kullanici yazili icerigini farkli locale'e sessizce overwrite etmek.