feat(domain): complete phase 2 backend core
This commit is contained in:
@@ -248,7 +248,7 @@ Checklist:
|
||||
- [x] Davet iptal edilebiliyor.
|
||||
- [x] Aynı müşteri için aktif davet politikası tanımlandı.
|
||||
- [x] Kabul işlemi transaction içinde.
|
||||
- [x] Client profile ve client kimlik bağı atomik kuruluyor (`app_profiles.client_id`; domain FK Faz 2'de eklenecek).
|
||||
- [x] Client profile ve client kimlik bağı atomik kuruluyor (`app_profiles.client_id` + `clients.auth_user_id`).
|
||||
- [x] Kullanılmış veya süresi dolmuş token tekrar kullanılamıyor.
|
||||
- [x] Client hesabı disable/revoke edilebiliyor.
|
||||
|
||||
@@ -567,14 +567,14 @@ Transaction içinde doğrulanacaklar:
|
||||
|
||||
Checklist:
|
||||
|
||||
- [ ] `project_id` ve `client_id` eşleşmesi server-side doğrulanıyor.
|
||||
- [ ] İstemciden gelen `clientId` güven kaynağı olarak kullanılmıyor.
|
||||
- [ ] Quota server-side kontrol ediliyor.
|
||||
- [ ] Quota atomik azaltılıyor veya tüketim kayıtlarından hesaplanıyor.
|
||||
- [ ] Başarısız insert quota tüketmiyor.
|
||||
- [ ] Cross-project revision negatif testi var.
|
||||
- [ ] Başka client adına revision oluşturma negatif testi var.
|
||||
- [ ] Kota aşımı negatif testi var.
|
||||
- [x] `project_id` ve `client_id` eşleşmesi server-side doğrulanıyor.
|
||||
- [x] İstemciden gelen `clientId` güven kaynağı olarak kullanılmıyor.
|
||||
- [x] Quota server-side kontrol ediliyor.
|
||||
- [x] Quota atomik azaltılıyor veya tüketim kayıtlarından hesaplanıyor.
|
||||
- [x] Başarısız insert quota tüketmiyor.
|
||||
- [x] Cross-project revision negatif testi var.
|
||||
- [x] Başka client adına revision oluşturma negatif testi var.
|
||||
- [x] Kota aşımı negatif testi var.
|
||||
|
||||
## 16. API v1 ve mobil hazırlığı
|
||||
|
||||
@@ -600,13 +600,13 @@ DELETE /api/v1/device-sessions/:id
|
||||
|
||||
Mobil hazırlık checklist'i:
|
||||
|
||||
- [ ] API response envelope standardı tanımlandı.
|
||||
- [ ] API hata kodları tanımlandı.
|
||||
- [x] API response envelope standardı tanımlandı.
|
||||
- [x] API hata kodları tanımlandı.
|
||||
- [ ] API sürümleme stratejisi tanımlandı.
|
||||
- [ ] Instance metadata sözleşmesi tanımlandı.
|
||||
- [ ] Minimum desteklenen client sürümü alanı düşünüldü.
|
||||
- [ ] Capability listesi sözleşmesi düşünüldü.
|
||||
- [ ] Service katmanı cookie/Next.js objelerine bağımlı değil.
|
||||
- [x] Service katmanı cookie/Next.js objelerine bağımlı değil.
|
||||
- [ ] Mobil pairing ilk release kapsamı dışında tutuldu.
|
||||
- [ ] Gelecekte HTTPS zorunluluğu belgelendi.
|
||||
|
||||
@@ -714,9 +714,9 @@ Mümkün olduğunda küçük ve doğrudan test araçları tercih edilir; test al
|
||||
- [x] Client invitation testi
|
||||
- [x] Expired/revoked invitation negatif testi
|
||||
- [ ] Her repository için cross-owner negatif test
|
||||
- [ ] Client private task erişim negatif testi
|
||||
- [ ] Revision project-client eşleşme negatif testi
|
||||
- [ ] Revision quota testi
|
||||
- [x] Client private task erişim negatif testi
|
||||
- [x] Revision project-client eşleşme negatif testi
|
||||
- [x] Revision quota testi
|
||||
- [ ] File upload MIME/size testi
|
||||
- [ ] Path traversal negatif testi
|
||||
- [x] Backup oluşturma testi
|
||||
@@ -820,13 +820,22 @@ Faz 1 tamamlanma notu (2026-07-16):
|
||||
|
||||
Amaç: Tüm çekirdek iş verileri için Drizzle schema, migration, repository ve service katmanını kurmak.
|
||||
|
||||
- [ ] Çekirdek tablolar oluşturuldu.
|
||||
- [ ] Repository katmanı oluşturuldu.
|
||||
- [ ] Service katmanı oluşturuldu.
|
||||
- [ ] Actor/authorization sözleşmesi standartlaştırıldı.
|
||||
- [ ] Validation ve error sözleşmesi standartlaştırıldı.
|
||||
- [ ] Negatif authorization testleri yazıldı.
|
||||
- [ ] Analytics aggregate sorgu yaklaşımı belirlendi.
|
||||
- [x] Çekirdek tablolar oluşturuldu.
|
||||
- [x] Repository katmanı oluşturuldu.
|
||||
- [x] Service katmanı oluşturuldu.
|
||||
- [x] Actor/authorization sözleşmesi standartlaştırıldı.
|
||||
- [x] Validation ve error sözleşmesi standartlaştırıldı.
|
||||
- [x] Negatif authorization testleri yazıldı.
|
||||
- [x] Analytics aggregate sorgu yaklaşımı belirlendi.
|
||||
|
||||
Faz 2 tamamlanma notu (2026-07-16):
|
||||
|
||||
- 11 çekirdek domain tablosu ile kaynak verisi korunacak 4 business tablosu Drizzle schema ve migration'a eklendi; storage ve branding tabloları Faz 3 sınırında bırakıldı.
|
||||
- Scope zorunlu repository katmanı ve Next.js/session bağımsız service katmanı; CRUD, ilişki tutarlılığı, otomatik proje ilerlemesi, portal görünürlüğü ve aggregate sorguları uygular.
|
||||
- Davet hedefi yerel owner-scoped client kaydına bağlandı. Kabul transaction'ı `app_profiles.client_id` ve `clients.auth_user_id` kimlik bağlarını birlikte kurar; client session bu iki yönlü bağı doğrular.
|
||||
- Revizyon isteği `BEGIN IMMEDIATE` transaction içinde actor-derived client, proje ilişkisi, aktif proje ve tüketim kayıtlarından kota kontrolüyle oluşturulur.
|
||||
- `phase2:domain-smoke`; cross-owner, client owner-only erişimi, private task, başka client/proje, kota aşımı, ilişkisel owner ve SQLite constraint negatiflerini gerçek migration uygulanmış veritabanında doğrular.
|
||||
- Tasarım ve doğrulama ayrıntıları `phase-2-domain-core.md` belgesinde kaydedildi.
|
||||
|
||||
Çıkış kriteri: Çekirdek domain işlemleri UI veya Supabase'e bağımlı olmadan test edilebiliyor.
|
||||
|
||||
|
||||
@@ -34,12 +34,12 @@ Bu dosya tarihsel adı korunarak Faz 1'de tamamlanan Better Auth + SQLite auth t
|
||||
- Token `randomBytes(32)` ile üretilir; SQLite'ta yalnızca SHA-256 hash saklanır.
|
||||
- Varsayılan TTL 72 saat, servis üst sınırı 168 saattir.
|
||||
- Aynı `clientId` için yeni davet önceki pending davetleri revoke eder ve bu değişiklik audit edilir.
|
||||
- Kabul sırasında Better Auth `user`, credential `account`, `app_profiles` client kaydı, `client_id` identity bağı ve invitation `accepted` durumu tek SQLite transaction'ında yazılır.
|
||||
- Kabul sırasında Better Auth `user`, credential `account`, `app_profiles` client kaydı, `clients.auth_user_id` bağı ve invitation `accepted` durumu tek SQLite transaction'ında yazılır.
|
||||
- Kullanılmış, değiştirilmiş, süresi dolmuş veya revoke edilmiş token yeniden kullanılamaz.
|
||||
- Disable işlemi profile'ı kapatır ve o client'ın aktif Better Auth session kayıtlarını aynı transaction'da siler.
|
||||
- Disabled veya `client_id` bağı eksik client, Better Auth endpoint'ini doğrudan çağırsa bile session oluşturamaz.
|
||||
|
||||
`app_profiles.client_id`, Faz 1 auth sınırında opaque domain identity bağıdır. Yerel `clients` tablosu ve foreign key Faz 2 domain migration'ında eklenecektir; mevcut Supabase client sayfaları bu nedenle henüz domain açısından hibrittir.
|
||||
Faz 2 ile yerel `clients` tablosu eklenmiştir. Davet hedefi artık owner'a ait gerçek bir client kaydı olmak zorundadır; kabul transaction'ı `app_profiles.client_id` ile `clients.auth_user_id` bağlarını birlikte kurar ve session çözümlemesi iki yönlü bağın eşleştiğini doğrular. Mevcut ekran sorgularının Supabase'ten service katmanına taşınması sayfa bazlı dönüşüm fazlarında sürdürülecektir.
|
||||
|
||||
## Audit kapsamı
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: Faz 2 Domain Schema ve Backend Çekirdeği
|
||||
description: SQLite/Drizzle domain modeli, repository-service sınırı, actor yetkilendirmesi ve test sözleşmesi.
|
||||
status: complete
|
||||
last_updated: 2026-07-16
|
||||
---
|
||||
|
||||
# Faz 2 Domain Schema ve Backend Çekirdeği
|
||||
|
||||
Faz 2, Neta'nın iş verilerini Supabase istemcisinden ayıran çalıştırılabilir backend çekirdeğini kurar. Bu faz sayfa sorgularını henüz taşımaz; Drizzle schema, migration, repository ve service katmanları UI, cookie ve Next.js request objelerinden bağımsızdır. Route Handler veya Server Action yalnızca session'ı `DomainActor`'a çevirip service çağırmalıdır.
|
||||
|
||||
## Veri modeli
|
||||
|
||||
`0003_chief_excalibur.sql` migration'ı 15 domain tablosunu ekler:
|
||||
|
||||
- çekirdek: `clients`, `client_activities`, `projects`, `project_planning_sections`, `tasks`, `calendar_events`, `finance_transactions`, `journal_entries`, `project_revisions`, `chat_sessions`, `chat_messages`;
|
||||
- korunacak iş verileri: `proposals`, `contracts`, `invoices`, `subscriptions`.
|
||||
|
||||
Dosya metadata'sı ve instance branding bilinçli olarak Faz 3'e bırakılmıştır. ID'ler mevcut UUID'leri taşıyabilmek için `text`, parasal değerler integer minor unit, iş tarihleri `YYYY-MM-DD`, sistem zamanları UTC epoch millisecond olarak saklanır. Owner'a ait tablolarda açık `owner_user_id`, client portal bağında `clients.auth_user_id` bulunur.
|
||||
|
||||
Schema seviyesinde status/type enumları, negatif para ve süre değerleri, progress aralığı, revizyon kotası, tarih aralığı, currency uzunluğu, journal owner+date tekilliği ve invoice owner+number tekilliği SQLite `CHECK`/unique constraint'leriyle korunur. İlişkisel owner tutarlılığı service katmanında doğrulanır; istemciden gelen owner veya client kimliği güven kaynağı değildir.
|
||||
|
||||
## Katman sınırları
|
||||
|
||||
| Katman | Sorumluluk | Bağımlı olmadığı şeyler |
|
||||
| --- | --- | --- |
|
||||
| Schema | tablo, foreign key, index ve DB constraint | UI, Supabase |
|
||||
| Repository | scope uygulanmış Drizzle sorguları ve aggregate'ler | session/cookie, Next.js |
|
||||
| Service | validation, actor yetkisi, ilişki ve iş kuralları | Route Handler, React |
|
||||
| Adapter | session→actor ve HTTP response dönüşümü | domain kuralı |
|
||||
|
||||
Ana giriş noktaları:
|
||||
|
||||
- `server/domain/actor.ts`: `DomainActor`, `OwnerScope`, `ClientScope` ve role/disabled guard'ları;
|
||||
- `server/domain/validation.ts`: paylaşılan Zod input sözleşmeleri;
|
||||
- `server/domain/errors.ts`: stabil domain error code ve HTTP status eşlemesi;
|
||||
- `server/repositories/domain.ts`: owner/client scope'u sorgu koşuluna dönüştüren repository'ler;
|
||||
- `server/services/domain.ts`: CRUD, ilişki doğrulaması, portal görünürlüğü, revizyon ve aggregate kuralları;
|
||||
- `server/api/responses.ts`: `{ ok, data }` ve `{ ok, error }` API envelope'u;
|
||||
- `server/auth/domain-actor.ts`: web session adapter'ı.
|
||||
|
||||
Repository metoduna çıplak `ownerUserId` yerine tiplenmiş scope verilir. Owner kaynaklarında kimlik filtresi her sorguda uygulanır. Client proje erişimi bağlı `clientId`, görev erişimi ayrıca `is_public_to_client = true` üzerinden kısıtlanır. Calendar, finance, journal ve chat client rolüne kapalıdır.
|
||||
|
||||
## İş kuralları
|
||||
|
||||
- Side project bir client'a bağlanamaz.
|
||||
- Client/project/task/journal ilişkileri aynı owner altında bulunmalı ve birbiriyle uyuşmalıdır.
|
||||
- Otomatik progress kullanan projeler, iptal edilmemiş görevlerdeki `done / total` oranından create/update/delete sonrasında yeniden hesaplanır.
|
||||
- Journal aynı owner ve iş tarihi için upsert edilir.
|
||||
- Chat session ve journal context kayıtları aynı owner'a ait olmak zorundadır.
|
||||
- Business preservation tablolarına yazılan client/project/proposal bağları owner scope'unda doğrulanır.
|
||||
- Davet yalnızca owner'a ait gerçek bir `clients` kaydı için üretilebilir. Kabul işlemi auth kayıtlarıyla birlikte `clients.auth_user_id` değerini aynı transaction'da yazar; session çözümlemesi `app_profiles.client_id` ile bu bağı karşılıklı doğrular.
|
||||
|
||||
## Revizyon transaction'ı
|
||||
|
||||
Revizyon isteği client actor'dan `clientId` almaz; client kimliği actor scope'undan gelir. `BEGIN IMMEDIATE` transaction içinde proje-client eşleşmesi, projenin aktif olması ve reddedilmemiş tüketim kayıtlarından kalan kota kontrol edilir, sonra insert yapılır. Bu yaklaşım ayrı bir mutable sayaç tutmaz; başarısız transaction kota tüketmez ve eşzamanlı yazarlar kontrol ile insert arasına giremez.
|
||||
|
||||
## Analytics yaklaşımı
|
||||
|
||||
Analytics için satırların tamamını belleğe alıp JavaScript'te toplamak yerine repository seviyesinde doğrudan SQLite aggregate sorguları kullanılır:
|
||||
|
||||
- ödenmiş gelir, ödenmiş gider ve planlanan/pending tutarlar koşullu `SUM` ile;
|
||||
- proje ve görev durum dağılımları `GROUP BY` + `COUNT` ile;
|
||||
- tüm sorgular `owner_user_id` scope'u ile.
|
||||
|
||||
İleride dashboard zaman serileri de aynı yaklaşımda tarih aralığı ve currency filtresi eklenerek genişletilmelidir. Farklı para birimleri kur bilgisi olmadan birbirine çevrilmemelidir.
|
||||
|
||||
## Doğrulama
|
||||
|
||||
`npm run phase2:domain-smoke` her çalışmada boş bir SQLite dosyasına gerçek migration'ları uygular, saf TypeScript domain çekirdeğini derler ve aşağıdaki senaryoları doğrular:
|
||||
|
||||
- owner CRUD scope'u ve cross-owner kaynak reddi;
|
||||
- client'ın owner-only modüllerden reddi;
|
||||
- bağlı proje/planlama görünürlüğü ve private task sızıntısının engellenmesi;
|
||||
- otomatik project progress;
|
||||
- project-client eşleşmesi, aktif proje kuralı, atomik quota ve quota aşımı;
|
||||
- journal upsert, chat ownership ve ilişkisel owner doğrulamaları;
|
||||
- owner-scope finance aggregate sonuçları;
|
||||
- korunacak dört business tablosuna service üzerinden yazım;
|
||||
- negatif amount ve geçersiz status için SQLite CHECK constraint'leri.
|
||||
|
||||
Faz 1 auth smoke'u da yerel client fixture'larıyla çalışır ve davet kabulünden sonra hem profile hem `clients.auth_user_id` bağını doğrular.
|
||||
|
||||
| Kontrol | Sonuç |
|
||||
| --- | --- |
|
||||
| `npm run typecheck` | Başarılı |
|
||||
| Değişen Faz 2 dosyalarında targeted ESLint | 0 error, 0 warning |
|
||||
| `npm run phase2:domain-smoke` | Başarılı |
|
||||
| `node scripts/phase1-auth-smoke.mjs` | Başarılı |
|
||||
| `node scripts/phase1-smoke.mjs` | Başarılı; migration, backup ve restore dahil |
|
||||
| `pnpm db:generate` | Schema drift yok |
|
||||
| `npm run build` | Başarılı |
|
||||
|
||||
Repo geneli lint, Faz 0'dan kaydedilmiş ve bu fazın değiştirmediği UI/AI dosyalarındaki baseline nedeniyle 31 error ve 18 warning ile açık kalır. Faz 2 dosyaları bu bulgulara yenisini eklemez.
|
||||
Reference in New Issue
Block a user