# DLS — Ürün Tasarım Spec'i Bu dosya `dls-ui-tasarim.pdf` (orijinal Figma export) baz alınarak hazırlanmış geliştirilmiş ürün spec'idir. PDF UI mock'ları içerir; bu doküman akış, veri modeli, rol ayrımı ve karar gerektiren noktaları somutlaştırır. ## Sistem özeti DLS, **diş klinikleri** ile **diş laboratuvarları** arasındaki iş alışverişini dijitalleştirir: - Klinik bir hasta için protez işi açar (tür, üye sayısı, renk, ölçü taraması, görseller). - İşi bağlı bir laboratuvara yollar. - Laboratuvar gelen kutusundan görür, durum adımlarını işler (Ölçü → Alt Yapı → Üst Yapı → Cila/Bitim). - Tamamlandığında klinik gönderim aşamasına geçer. - Her iki taraf finansal akışı (ödenmiş/bekleyen) kendi tarafında izler. ## Roller Tek bir hesap modeli, iki tenant türü (`kind`): | `kind` | İlgili eylemler | |---|---| | `clinic` | İş yayınla, kendi gönderdiklerini takip et, lab bağlantısı talep et, ödeme yap | | `lab` | Ürün katalog yönet, gelen işleri al/onayla, durum güncelle, fatura kes | `requireTenantKind(ctx, ['lab' \| 'clinic'])` server-side route guard — sayfa render edilmeden önce yetki sorgular. ## Sayfa haritası (PDF'e göre) | URL | PDF sayfa | İçerik | |---|---|---| | `/dashboard` | 1 | Anasayfa — özet kartlar (açık işler, işlem bekleyen, bildirimler, istatistik chart) | | `/jobs/inbound` | 2 | Gelen İşler tablosu (Klinik / Hasta Kodu / Üye / Renk / Tür / Açıklama / İşlem) | | `/jobs/[id]` | 3 | İş detay — bilgiler + durum stepper (Ölçü / Alt Yapı Prova / Üst Yapı Prova / Cila/Bitim) + Görselleri Görüntüle / Taranan Dosyalar / Kaydet | | `/jobs/outbound` | 4 | Giden İşler tablosu (aynı sütunlar) | | `/jobs/new` | (header CTA) | "Yeni İş Yayınla" formu — klinik tarafı | | `/products` | 5 | Eklenen Ürünler (sadece lab) — Protez Türü / Fiyat tablo + ekleme formu | | `/finance` | 6 | Finans (Bekliyor) — tahsilat/ödeme listesi | | `/connections` | 7 | Bağlantı Kur — kendi bağlantı kodun + bekleyen talepler + onaylı bağlantılar | | `/settings/*` | 8 | Ayarlar (workspace, üye, hesap, görünüm) | | `/sign-in`, `/sign-up` | 9 | Giriş/kayıt — PDF "Labaratuvar Giriş" + "Klinik Giriş" iki ayrı form gösteriyor; biz tek form + onboarding'de `kind` seçimi yapıyoruz | > PDF'teki "Üye Numarası" alanı login'de **kullanılmıyor**. Üye numarası `tenant_settings.memberNumber` olarak sistem tarafından üretiliyor ve **bağlantı kodu** olarak işlev görüyor (PDF'teki "Bağlantı Kodu" panelinin de aynısı). ## Veri modeli (`lib/appwrite/schema.ts`) Tüm collection'lar `tenant_settings.tenantId = Appwrite Team.$id`. ### `tenant_settings` - `tenantId` (unique, indexed) - `kind: 'lab' | 'clinic'` - `memberNumber: string` (6 hane, unique, indexed) — bağlantı kodu - `companyName`, `companyTaxId`, `companyAddress`, `companyEmail`, `companyPhone`, `logo` - `defaultCurrency` (varsayılan `TRY`) ### `profiles` Kullanıcı başına ek bilgi (display name, telefon, ünvan). Auth identity Appwrite Auth'tadır; ek alanlar burada. ### `connections` İki tenant arası bağlantı. - `clinicTenantId`, `labTenantId` - `status: 'pending' | 'approved' | 'rejected'` - `requestedBy`, `requestedAt`, `approvedAt?`, `rejectedAt?` - Permission: `Role.team(clinicTenantId)` + `Role.team(labTenantId)` (her ikisi de görür) ### `jobs` - `clinicTenantId`, `labTenantId`, `createdBy` - `patientCode`, `prostheticType` (`metal_porselen`, `zirkonyum`, `implant_ustu_zirkonyum`, `gecici`, `e_max`, `diger`) - `memberCount` (üye sayısı), `color` (Vita renk kodu örn. A2), `description?`, `price?`, `currency?`, `dueDate?` - `status: 'pending' | 'in_progress' | 'sent' | 'delivered' | 'cancelled'` - `currentStep: 'olcu' | 'alt_yapi_prova' | 'ust_yapi_prova' | 'cila_bitim'` - Permission: `Role.team(clinicTenantId)` + `Role.team(labTenantId)` ### `job_files` - `jobId`, `clinicTenantId`, `labTenantId`, `uploadedBy` - `kind: 'scan' | 'image' | 'document'` - `fileId` (Appwrite Storage bucket: `job-files`), `name`, `size`, `mimeType?` - Permission: aynı job permission'ı ### `job_status_history` Stepper geçişleri — denetim izi. - `jobId`, `clinicTenantId`, `labTenantId`, `step`, `completedBy`, `completedAt`, `note?` ### `prosthetics` (lab katalog) - `tenantId` (lab'in tenant id'si), `createdBy` - `name`, `type`, `unitPrice`, `currency?`, `archived?` - Permission: `Role.team(tenantId)` (sadece kendi tarafı) ### `finance_entries` - `tenantId`, `createdBy`, `jobId?`, `counterpartTenantId?` - `type: 'income' | 'expense' | 'receivable' | 'payable'` - `amount`, `currency?`, `status: 'pending' | 'paid' | 'cancelled'`, `date`, `description?` - Permission: `Role.team(tenantId)` (klinik ve lab kendi defterlerini görür; karşı taraf görmez) ### `notifications` - `tenantId`, `userId?`, `jobId?`, `connectionId?`, `message`, `read` ### `audit_logs`, `invite_links`, `password_resets`, `user_preferences` CRM'den birebir kullanılıyor. ## Bağlantı akışı (`connections` yaşam döngüsü) 1. **Klinik** → `/connections` → "Bağlantı talep et" → karşı tarafın `memberNumber`'ını gir. 2. Server action `connections` row yaratır (`status: pending`), her iki team'e permission açar. 3. **Lab** → `/connections` → bekleyen talepler listesinde görür → **Onayla** veya **Reddet**. 4. Onaylanırsa `status: approved`. Klinik artık `/jobs/new` formunda bu lab'i seçebilir. 5. Reddedilirse `status: rejected`, tekrar talep edilebilir. ## İş akışı (`jobs` yaşam döngüsü) 1. Klinik `/jobs/new` formuyla iş açar (lab seçimi onaylı bağlantılardan), durum `pending`. 2. Lab gelen kutusunda görür, **İşleme Al** → `status: in_progress`, `currentStep: olcu`. 3. Lab her aşamayı tamamlayınca `job_status_history` row eklenir + `currentStep` ilerler. 4. Cila/Bitim sonrası `status: sent`. Klinik teslim alınca `delivered`. 5. Tamamlandığında lab `finance_entries` (income, pending) açar; klinik tarafında (expense, pending) açılır (idempotent sync helper ile). ## Onboarding akışı `/onboarding` sayfası: 1. Kayıt sonrası ilk girişte. Mevcut workspace'i yoksa zorunlu. 2. **Hesap türü seç** (Klinik / Lab) → state. 3. Şirket adı + opsiyonel vergi/telefon. 4. Submit → `createWorkspaceAction`: - Appwrite Team yarat - `tenant_settings` row yarat (`kind`, `memberNumber` üretilmiş) - Active tenant cookie + user prefs 5. Redirect `/dashboard`. İmport akışı (cross-app team import) için de `kind` seçimi zorunlu. ## Açık tasarım kararları - **Login formunda "Üye Numarası"** PDF'te var; biz e-posta+şifre kullanıyoruz. `memberNumber` register/login için **kullanılmaz**, sadece bağlantı kurmak için. - **Cila/Bitim** sonrası kargo/teslim alanı PDF'te yok; spec'te `status: sent → delivered` ile temsil edildi. Kargo takip eklenirse `jobs.shipmentTracking?` opsiyonel field eklenir. - **Finans entegrasyonu** PDF'te "Finans (Bekliyor)" başlığı dışında detay vermiyor. Spec'te `finance_entries` (income/expense/receivable/payable) ile başlattık; faturalama, ödeme provider entegrasyonu sonraki faz. - **PDF'in "Bağlantı Kodu" tek bir kalıcı kod** olarak modellendi (`memberNumber`). Her connection için ayrı OTP/kod istenirse `connection_codes` collection eklenir. ## Yapılacaklar (oturum kapanışı sonrası) - [ ] Appwrite MCP ile `lab` database + collection'lar (bu commit'te schema TS hazır, fiziksel oluşturma bir sonraki adım) - [ ] `jobs` modülü (liste + form + detay) - [ ] `connections` modülü (request/approve akışı) - [ ] `products` modülü (lab katalog CRUD) - [ ] `finance` modülü (cross-tenant idempotent sync helper) - [ ] Coolify app + DNS `lab.kovakcrm.com` - [ ] Landing page DLS'e uyarla