cb150f7a24
- CRM domain modules removed (customers, services, software, calendar, tasks, invoices, leads, finance, etc.)
- DLS branding: package name=lab, logo wordmark, sidebar nav, header CTA
- Tenant layer extended with kind dimension (lab|clinic) + requireTenantKind helper
- Schema rewritten for DLS domain: jobs, job_files, job_status_history, prosthetics, connections, finance_entries, notifications
- Onboarding form: clinic/lab account-type selection + auto-generated memberNumber
- Placeholder routes for jobs/{inbound,outbound,new}, products, finance, connections
- PDF spec + spec.md under belgeler/
- db: lab database + 13 collections + indexes + storage bucket (job-files) provisioned via Appwrite MCP
Ref: belgeler/dls-ui-tasarim.pdf
145 lines
7.7 KiB
Markdown
145 lines
7.7 KiB
Markdown
# 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
|