Files

6.4 KiB
Raw Permalink Blame History

title, description, status, last_updated
title description status last_updated
Faz 2 Domain Schema ve Backend Çekirdeği SQLite/Drizzle domain modeli, repository-service sınırı, actor yetkilendirmesi ve test sözleşmesi. complete 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.