┌─────────────────────────────────────────────────────────────────────────────┐
│ USERS (Kullanıcılar) │
├─────────────────────────────────────────────────────────────────────────────┤
│ • id (PK) │
│ • username (unique) │
│ • role: admin, accounting, sales_agent, customer, warehouse_* │
│ • customer_number │
│ • channel_type: logistics, dealer │
└───────┬─────────────────────────────────────────────────────────────────────┘
│
│ (1:N)
├──────────────────────────────────────────────────────────────────┐
│ │
▼ ▼
┌───────────────────┐ ┌──────────────────┐
│ ORDERS │ │ SALES_ROUTES │
├───────────────────┤ ├──────────────────┤
│ • id (PK) │ │ • id (PK) │
│ • order_number │ │ • sales_agent_id │
│ • customer_id (FK)│◄──────────────┐ │ • customer_id │
│ • sales_rep_id │ │ │ • delivery_day │
│ • status │ │ │ • route_order │
│ • products[] │ │ └──────────────────┘
│ • total_amount │ │
└───────┬───────────┘ │
│ │
│ (N:M via products[]) │
│ │
▼ │
┌───────────────────────────────────┴──────────────────┐
│ PRODUCTS │
├──────────────────────────────────────────────────────┤
│ • id (PK) │
│ • sku (unique) │
│ • name, category, description │
│ • prices: sales, logistics, dealer │
│ • stock_quantity, stock_status │
│ • warehouse_code, shelf_code │
└─────────┬────────────────────────────────────────────┘
│
│ (1:N)
├────────────────────────────────────────┬────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌─────────────────┐ ┌─────────────┐
│ FAVORITES │ │ INVENTORY │ │FAULT_REPORTS│
├───────────────┤ ├─────────────────┤ ├─────────────┤
│ • id (PK) │ │ • id (PK) │ │ • id (PK) │
│ • user_id (FK)│ │ • product_id(FK)│ │ • user_id │
│ • product_id │ │ • warehouse_id │ │ • product_id│
│ (MAX 10/user) │ │ • total_units │ │ • photos[] │
└───────────────┘ │ • expiry_date │ │ • status │
└─────────────────┘ └─────────────┘
│
│ (N:1)
▼
┌─────────────────┐
│ WAREHOUSES │
├─────────────────┤
│ • id (PK) │
│ • name │
│ • location │
│ • manager_id │
│ • capacity │
└─────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ INVOICES (Faturalar) │
├─────────────────────────────────────────────────────────────────────────────┤
│ • id (PK) │
│ • invoice_number (unique) │
│ • customer_id (FK) → users │
│ • customer_tax_id │
│ • invoice_date (DD MM YYYY) │
│ • products[] │
│ • grand_total │
│ • uploaded_by (FK) → users │
└───────┬─────────────────────────────────────────────────────────────────────┘
│
│ (1:N)
│
▼
┌───────────────────────────────────────────────────────────────────────────┐
│ CUSTOMER_CONSUMPTION (Tüketim Analizi) │
├───────────────────────────────────────────────────────────────────────────┤
│ • consumption_id (PK) │
│ • customer_id (FK) → users │
│ • product_id (FK) → products │
│ • source_invoice_id (FK) → invoices (önceki fatura) │
│ • target_invoice_id (FK) → invoices (yeni fatura) │
│ • source_quantity, target_quantity │
│ • days_between (faturalar arası gün) │
│ • consumption_quantity (tüketilen) │
│ • daily_consumption_rate (günlük ort.) │
│ • deviation_rate (sapma %) │
└───────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ CAMPAIGNS (Kampanyalar) │
├─────────────────────────────────────────────────────────────────────────────┤
│ • id (PK) │
│ • name, description, title │
│ • campaign_type: simple_discount, buy_x_get_y, bulk_discount │
│ • discount_value, discount_percentage │
│ • depot_id, sales_agent_ids[] (hedefleme) │
│ • product_ids[] (hangi ürünlere uygulanacak) │
│ • start_date, end_date │
│ • is_active │
└───────┬─────────────────────────────────────────────────────────────────────┘
│
│ (1:N) Kampanya oluşunca bildirim gönderilir
│
▼
┌───────────────────────────────────────────────────────────────────────────┐
│ NOTIFICATIONS (Bildirimler) │
├───────────────────────────────────────────────────────────────────────────┤
│ • id (PK) │
│ • user_id (FK) → users (bildirim alan) │
│ • type: order_created, order_status, campaign, fault_response, etc. │
│ • title, message │
│ • is_read │
│ • related_order_id (FK) → orders (optional) │
│ • related_campaign_id (FK) → campaigns (optional) │
│ • created_at │
└───────────────────────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────────────────────┐
│ SAVED_CARTS (Kaydedilmiş Sepetler) │
├───────────────────────────────────────────────────────────────────────────┤
│ • id (PK) │
│ • user_id (FK) → users (UNIQUE - kullanıcı başına 1 adet) │
│ • products[] (sepetteki ürünler) │
│ • total_amount │
│ • updated_at │
└───────────────────────────────────────────────────────────────────────────┘
Müşteri (Customer)
│
├─> 1. OrderManagement.js (Frontend)
│ • Ürünleri seçer (products koleksiyonundan)
│ • Sepete ekler (state)
│ • "Siparişi Tamamla" butonuna basar
│
├─> 2. POST /api/orders (Backend)
│ • Order kaydı oluşturulur
│ • order_number generate edilir
│ • products[] array'i doldurulur
│ • status: "pending" olarak işaretlenir
│
├─> 3. Notification Service
│ • Müşteriye "Sipariş Oluşturuldu" bildirimi
│ • notification koleksiyonuna kayıt
│
└─> 4. Saved Cart Temizleme
• saved_carts koleksiyonundan silinir
Muhasebe (Accounting)
│
├─> 1. InvoiceUpload.js (Frontend)
│ • HTML fatura yükler
│
├─> 2. POST /api/invoices (Backend)
│ • HTML parse edilir
│ • Invoice kaydı oluşturulur
│ • customer_tax_id ile müşteri eşleştirilir
│
├─> 3. Consumption Calculation Service
│ • Önceki fatura bulunur (source_invoice)
│ • Yeni fatura (target_invoice)
│ • Her ürün için:
│ - consumption_quantity = source_quantity (tüketilen)
│ - days_between hesaplanır
│ - daily_consumption_rate = consumption / days
│ - deviation_rate hesaplanır
│ • customer_consumption koleksiyonuna kayıt
│
└─> 4. Consumption Periods Update
• Haftalık/Aylık toplamlar güncellenir
• consumption_periods koleksiyonu
Admin
│
├─> 1. CampaignManagement.js (Frontend)
│ • Kampanya detayları girilir
│ • Hedef plasiyer seçilir (sales_agent_ids[])
│
├─> 2. POST /api/campaigns (Backend)
│ • Campaign kaydı oluşturulur
│ • is_active: true olarak işaretlenir
│
├─> 3. Notification Service - Campaign
│ • sales_agent_ids BOŞ ise:
│ → Tüm müşterilere bildirim (users.role = customer)
│ • sales_agent_ids DOLU ise:
│ → sales_routes koleksiyonundan ilgili müşteriler bulunur
│ → Sadece o müşterilere bildirim
│ • Her müşteri için notification kaydı oluşturulur
│
└─> 4. Customer Dashboard
• Müşteri giriş yapar
• NotificationCenter bildirim sayısını gösterir
• CampaignsModule kampanyaları listeler
Müşteri
│
├─> 1. ProductCatalog.js (Frontend)
│ • Ürünün yanındaki kalp ikonuna tıklar
│
├─> 2. POST /api/favorites/toggle/{product_id}
│ • favorites koleksiyonu kontrol edilir
│ • count < 10 ise yeni kayıt oluşturulur
│ • count >= 10 ise hata döner
│
└─> 3. FavoritesModule.js
• Favori liste güncellenir
• Hızlı sepete ekleme aktif olur
Admin
│
├─> 1. Rota Atama
│ • sales_routes kaydı oluşturulur
│ • sales_agent_id: plasiyer
│ • customer_id: müşteri
│ • delivery_day: teslimat günü
│
└─> 2. Plasiyer Dashboard
• GET /api/sales-routes/agent/{agent_id}
• Kendi rotalarını görür
• delivery_day bazlı gruplandırılır
• route_order sırasıyla listelenir
-
Favorites (MAX 10)
db.favorites.countDocuments({user_id: X})< 10 kontrolü
-
Saved Cart (1 per user)
user_idunique index ile garanti edilir
-
Fault Photos (MAX 3, 5MB each)
- Backend'de
len(photos) <= 3kontrolü - Her photo için
size <= 5MBkontrolü
- Backend'de
-
Order Number Format
ORD-YYYYMMDD-XXXXXXXX(UUID 8 karakter)- Unique index ile garanti
-
Campaign Targeting
sales_agent_ids == []→ Tüm müşterilersales_agent_ids != []→ Sadece o plasiyerlerin müşterileri
// User silinirse:
- orders.customer_id → SET NULL veya KEEP (historical)
- favorites → DELETE
- saved_carts → DELETE
- fault_reports → DELETE
- notifications → DELETE
// Product silinirse:
- favorites → DELETE
- inventory → DELETE
- orders.products[] → KEEP (historical)
// Campaign silinirse:
- notifications → KEEP (historical)Performans için bazı alanlar denormalize edilmiştir:
sales_routes: {
customer_name: String // users.full_name'den kopyalanır
location: String // users.location'dan (eğer varsa)
}
orders.products[]: {
product_name: String, // products.name'den kopyalanır
product_sku: String, // products.sku'dan kopyalanır
price: Float // products.sales_price'dan kopyalanır
}
customer_consumption: {
product_name: String // products.name'den kopyalanır
}Avantajları:
- Join işlemi gerektirmez
- Sorgu performansı artar
- Historical data korunur (ürün adı değişse bile)
Dezavantajları:
- Data consistency manuel kontrol edilmeli
- Update işlemleri daha kompleks
// Unique Constraints
db.users.createIndex({ username: 1 }, { unique: true })
db.products.createIndex({ sku: 1 }, { unique: true })
db.orders.createIndex({ order_number: 1 }, { unique: true })
db.invoices.createIndex({ invoice_number: 1 }, { unique: true })
db.saved_carts.createIndex({ user_id: 1 }, { unique: true })
// Compound Indexes for Performance
db.orders.createIndex({ customer_id: 1, created_at: -1 })
db.favorites.createIndex({ user_id: 1, product_id: 1 }, { unique: true })
db.sales_routes.createIndex({ sales_agent_id: 1, delivery_day: 1, route_order: 1 })
db.customer_consumption.createIndex({ customer_id: 1, product_id: 1, target_invoice_date: -1 })
db.notifications.createIndex({ user_id: 1, is_read: 1, created_at: -1 })
// Campaign Filtering
db.campaigns.createIndex({
is_active: 1,
start_date: 1,
end_date: 1
})Son Güncelleme: 2025-01-20 Döküman Versiyonu: 2.0