> ## Documentation Index
> Fetch the complete documentation index at: https://docs.quinnsambal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Admin dashboard

<style>
  {`
    [class*="max-w-none"][class*="table"] {
      display: block !important;
      overflow-x: auto !important;
      max-width: 100% !important;
      width: 100% !important;
      flex-grow: 0 !important;
    }
    [class*="max-w-none"][class*="table"] > table {
      width: 100% !important;
      max-width: 100% !important;
      table-layout: fixed !important;
    }
    .mermaid {
      max-width: 100% !important;
      overflow-x: auto !important;
    }
    article svg[role="img"] {
      max-width: 100% !important;
      height: auto !important;
    }
    article img, .prose img {
      max-width: 100% !important;
      height: auto !important;
    }
    img[src*="LOGO"], img[src*="logo"] {
      max-width: 120px !important;
      max-height: 40px !important;
      width: auto !important;
      height: auto !important;
      object-fit: contain !important;
    }
    `}
</style>

***

title: "Admin Dashboard"
description: "Pusat monitoring sistem, manajemen user, audit log, dan health check teknis untuk administrator SNISHOP ERP."
---------------------------------------------------------------------------------------------------------------------------

# Admin Dashboard

<img src="https://mintcdn.com/quinnofspicy/e4f_upKhVWcjsUmM/docs/mintlify/screenshots/core/admin-dashboard.png?fit=max&auto=format&n=e4f_upKhVWcjsUmM&q=85&s=286e13d72bced05a5ab6d6cc3a03cfb4" alt="Admin Dashboard" width="1920" height="1080" data-path="docs/mintlify/screenshots/core/admin-dashboard.png" />

**Admin Dashboard** adalah pusat kendali teknis untuk administrator sistem SNISHOP ERP. Berbeda dengan Dashboard utama yang berfokus pada metrik bisnis, Admin Dashboard dirancang khusus untuk **monitoring kesehatan sistem, keamanan, dan performa teknis** — memberikan visibility penuh terhadap apa yang terjadi di balik layar.

Halaman ini hanya bisa diakses oleh user dengan role **Admin** atau **Owner** dan merupakan tempat pertama yang harus diperiksa ketika ada indikasi masalah teknis.

## Arsitektur Monitoring

```mermaid theme={null}
graph TD
    A[Admin Dashboard] --> B[System Health]
    A --> C[User Management]
    A --> D[Audit & Security]
    A --> E[Performance]
    A --> F[Logs & Debugging]
    
    B --> B1[Server status]
    B --> B2[Database health]
    B --> B3[Background jobs]
    B --> B4[API latency]
    
    C --> C1[Active sessions]
    C --> C2[User list]
    C --> C3[Role management]
    C --> C4[Login history]
    
    D --> D1[Audit log]
    D --> D2[Security alerts]
    D --> D3[Failed logins]
    D --> D4[Data changes]
    
    E --> E1[Response time]
    E --> E2[Resource usage]
    E --> E3[Error rate]
    E --> E4[Traffic pattern]
    
    F --> F1[Error logs]
    F --> F2[Warning logs]
    F --> F3[Debug console]
```

## Komponen Utama

### 1. System Health Monitor

Indikator real-time kesehatan seluruh komponen sistem:

| Komponen | Metrik | Threshold | Alert |
| - | - | - | - |
| **Server** | Uptime, CPU, Memory | > 99.5% uptime | Merah jika down |
| **Database** | Connection pool, query time | \< 100ms avg query | Kuning jika > 200ms |
| **Background Jobs** | Queue depth, success rate | \< 100 pending | Merah jika > 500 pending |
| **API Gateway** | Response time, error rate | \< 500ms p95 | Kuning jika > 1s p95 |
| **Storage** | Disk usage, file count | \< 80% used | Kuning jika > 80% |
| **Cache** | Hit rate, memory | > 90% hit rate | Kuning jika \< 70% |

**Status Indicators:**

* 🟢 **Hijau** — Semua normal, tidak ada masalah
* 🟡 **Kuning** — Warning, perlu perhatian dalam 24 jam
* 🔴 **Merah** — Critical, perlu tindakan segera
* ⚫ **Gray** — Maintenance mode atau tidak aktif

### 2. User Activity Monitor

Monitoring aktivitas user secara real-time:

| Informasi | Deskripsi |
| - | - |
| **User Online** | Jumlah user yang sedang aktif saat ini |
| **Login Hari Ini** | Total login sejak midnight |
| **Sesi Aktif** | Daftar sesi login yang sedang berjalan |
| **Peak Time** | Waktu dengan trafik tertinggi hari ini |
| **Anomali** | Deteksi aktivitas tidak biasa (login dari lokasi aneh, dll) |

**Tabel Sesi Aktif:**

| Kolom | Deskripsi |
| - | - |
| **User** | Nama dan avatar user |
| **IP Address** | Alamat IP dari mana login |
| **Lokasi** | Lokasi geografis (kota, negara) |
| **Device** | Browser dan OS yang digunakan |
| **Login Since** | Sejak kapan sesi ini aktif |
| **Last Activity** | Kapan terakhir ada aktivitas |
| **Aksi** | Force logout / View detail |

### 3. Grafik Penggunaan Sistem

Visualisasi pola penggunaan untuk capacity planning:

| Grafik | Periode | Insight |
| - | - | - |
| **Daily Active Users** | 7 hari terakhir | Pola penggunaan harian |
| **Requests per Minute** | 24 jam terakhir | Peak time identification |
| **Error Rate** | 7 hari terakhir | Stabilitas sistem |
| **Response Time Distribution** | 24 jam terakhir | Performa API |
| **Module Usage** | 30 hari terakhir | Modul mana yang paling sering dipakai |

### 4. Audit Log

Catatan lengkap setiap perubahan penting di sistem:

| Field | Deskripsi |
| - | - |
| **Timestamp** | Kapan aksi terjadi |
| **User** | Siapa yang melakukan |
| **Action** | Apa yang dilakukan (Create, Update, Delete) |
| **Entity** | Tabel/data yang diubah |
| **Record ID** | ID data yang diubah |
| **Before** | Nilai sebelum perubahan (untuk update) |
| **After** | Nilai setelah perubahan (untuk update) |
| **IP Address** | Alamat IP saat aksi dilakukan |
| **User Agent** | Browser/device yang digunakan |

**Filter Audit Log:**

| Filter | Opsi |
| - | - |
| **User** | Pilih user spesifik |
| **Action** | Create, Update, Delete, Login, Logout |
| **Entity** | Pilih tabel/entity spesifik |
| **Date Range** | Rentang tanggal |
| **IP Address** | Filter berdasarkan IP |

### 5. Alert & Peringatan

Sistem alert otomatis untuk masalah teknis:

| Level | Warna | Tindakan | Contoh |
| - | - | - | - |
| **Info** | Biru | Tidak perlu tindakan | Backup selesai, update tersedia |
| **Warning** | Kuning | Investigasi dalam 24 jam | Database slow query, disk > 80% |
| **Error** | Oranye | Investigasi segera | API error rate meningkat |
| **Critical** | Merah | Tindakan segera | Server down, database unreachable |

### 6. Error & Warning Log

Log teknis untuk debugging:

| Kolom | Deskripsi |
| - | - |
| **Level** | Error / Warning / Info / Debug |
| **Message** | Pesan error |
| **Stack Trace** | Detail lokasi error di kode |
| **Count** | Berapa kali error ini terjadi |
| **First Seen** | Kapan pertama kali muncul |
| **Last Seen** | Kapan terakhir muncul |
| **Status** | Open / Investigating / Resolved |

## Cara Akses

| Metode | Cara | Syarat |
| - | - | - |
| **Sidebar** | Menu **Admin** → **Dashboard** | Role: Admin / Owner |
| **Gear Icon** | Klik ikon gear di pojok kanan atas sidebar | Role: Admin / Owner |
| **Command Palette** | `Ctrl+K` → ketik "Admin Dashboard" | Role: Admin / Owner |

## Flow Penggunaan Harian

```mermaid theme={null}
flowchart TD
    A[Buka Admin Dashboard] --> B[Cek System Health]
    B --> C{Semua hijau?}
    C -->|Ya| D[Cek User Activity]
    C -->|Tidak| E[Investigasi masalah]
    E --> F[Lihat detail alert]
    F --> G[Ambil tindakan]
    G --> D
    D --> H[Review Audit Log]
    H --> I[Cek Error Log]
    I --> J{Ada anomali?}
    J -->|Ya| K[Investigasi lebih lanjut]
    J -->|Tidak| L[Semua aman]
```

## Metrik Performa

| Metrik | Target | Alert Threshold |
| - | - | - |
| **Uptime** | > 99.9% | \< 99.5% |
| **Avg Response Time** | \< 200ms | > 500ms |
| **P95 Response Time** | \< 500ms | > 1000ms |
| **Error Rate** | \< 0.1% | > 1% |
| **Database Query Time** | \< 100ms | > 200ms |
| **Cache Hit Rate** | > 95% | \< 70% |
| **Background Job Success** | > 99% | \< 95% |

## Custom Dashboard & Widget System

Admin Dashboard mendukung sistem **Custom Dashboard** yang memungkinkan setiap administrator atau pengguna membuat konfigurasi dashboard mereka sendiri. Konfigurasi ini disimpan dalam entitas `CustomDashboardConfig` dan dapat berisi berbagai jenis widget yang disusun dalam layout grid atau list.

### Jenis Widget yang Tersedia

Setiap widget dalam dashboard dapat dikonfigurasi dengan tipe dan sumber data yang berbeda:

| Widget Type | Deskripsi | Use Case |
| - | - | - |
| **chart** | Visualisasi grafik (line, bar, pie, area) | Tren penjualan, pertumbuhan user, error rate |
| **table** | Tabel data interaktif | Daftar transaksi terbaru, user aktif |
| **metric** | Angka KPI tunggal (single value) | Total revenue, jumlah user online, uptime |
| **list** | Daftar item ringkas | Task pending, notifikasi terbaru |
| **calendar** | Tampilan kalender | Jadwal event, deadline, shift karyawan |
| **forecast** | Prediksi berbasis data | Forecast penjualan, estimasi traffic |

### Konfigurasi Posisi Widget

Setiap widget memiliki properti posisi yang menentukan letaknya dalam layout grid:

| Properti | Tipe | Deskripsi |
| - | - | - |
| `row` | number | Baris posisi widget (dimulai dari 0) |
| `column` | number | Kolom posisi widget (dimulai dari 0) |
| `width` | number | Lebar widget dalam satuan grid |
| `height` | number | Tinggi widget dalam satuan grid |

### Tipe Chart yang Didukung

| Chart Type | Deskripsi | Cocok Untuk |
| - | - | - |
| **line** | Grafik garis | Tren data berkelanjutan (time series) |
| **bar** | Grafik batang | Perbandingan antar kategori |
| **pie** | Grafik lingkaran | Distribusi proporsi data |
| **area** | Grafik area terisi | Volume data dan akumulasi |

### Refresh Interval Widget

Setiap widget dapat dikonfigurasi dengan `refresh_interval` (dalam detik) untuk menentukan seberapa sering data diperbarui secara otomatis. Widget dengan data yang berubah cepat (seperti metrik user online) sebaiknya memiliki interval yang lebih pendek dibandingkan widget laporan bulanan.

## KPI & Performance Monitoring

Admin Dashboard terintegrasi dengan sistem KPI perusahaan untuk memantau performa karyawan secara langsung. Sistem KPI terdiri dari beberapa entitas yang saling terkait:

### Alur Penilaian KPI

```mermaid theme={null}
flowchart LR
    A[KPI Template] -->|Generate| B[CompanyKPI Draft]
    B -->|Employee Input| C[Submitted]
    C -->|Reviewer Review| D[Reviewed]
    D -->|Finalize| E[Finalized]
    E -->|Archive| F[Report Snapshot]
```

### Metrik KPI

Setiap entri KPI (`CompanyKPI`) berisi array `metrics` dengan struktur sebagai berikut:

| Field | Tipe | Deskripsi |
| - | - | - |
| `name` | string | Nama metrik (mis: "Volume Penjualan") |
| `description` | string | Penjelasan metrik |
| `target` | number | Target yang harus dicapai |
| `actual` | number | Realisasi aktual |
| `unit` | string | Satuan pengukuran (%, Rp, unit, dll) |
| `weight` | number | Bobot persentase (0-100) |
| `score` | number | Skor tertimbang untuk metrik ini |

### Perhitungan Otomatis KPI

Template KPI (`KPITemplate`) mendukung perhitungan otomatis dengan konfigurasi berikut:

| Field | Tipe | Default | Deskripsi |
| - | - | - | - |
| `auto_calculate` | boolean | `true` | Apakah KPI dihitung otomatis |
| `calculation_frequency` | enum | `daily` | Frekuensi perhitungan: `daily`, `weekly`, `monthly` |

**Metode Perhitungan Otomatis:**

| Method | Deskripsi |
| - | - |
| `manual` | Input manual oleh reviewer/employee |
| `auto_from_attendance` | Data otomatis dari modul absensi |
| `auto_from_sales` | Data otomatis dari modul penjualan |
| `auto_from_projects` | Data otomatis dari modul proyek |

## Sistem Notifikasi Admin

Admin Dashboard menampilkan notifikasi real-time dari seluruh sistem. Notifikasi dikelola melalui entitas `Notification` dengan berbagai tipe dan prioritas.

### Tipe Notifikasi

Notifikasi memiliki tipe yang menentukan cara render dan aksi yang tersedia:

| Tipe | Deskripsi | Aksi Khusus |
| - | - | - |
| `SYSTEM` | Notifikasi sistem umum | Lihat detail |
| `INVITATION` | Undangan bergabung perusahaan | Terima / Tolak |
| `TASK` | Pembaruan tugas | Lihat tugas |
| `STOCK` | Peringatan stok | Lihat inventori |
| `INVOICE` | Pembaruan invoice | Lihat invoice |
| `WORKFLOW` | Status workflow | Lihat workflow |
| `ANNOUNCEMENT` | Pengumuman sistem | Tutup |
| `ORDER` | Pesanan baru/diperbarui | Lihat pesanan |
| `PAYMENT` | Konfirmasi pembayaran | Verifikasi |
| `LOW_STOCK` | Stok hampir habis | Restok sekarang |
| `DISCREPANCY` | Selisih stok terdeteksi | Investigasi |
| `EXPIRY` | Lot mendekati kedaluwarsa | Lihat lot |
| `BACKUP` | Status backup | Lihat log |
| `BTT_PENDING` | BTT menunggu proses | Proses BTT |
| `PAYMENT_DUE` | Jatuh tempo pembayaran | Lihat invoice |
| `RECALL` | Penarikan produk | Lihat detail recall |

### Prioritas Notifikasi

| Prioritas | Indikator | Tindakan |
| - | - | - |
| `low` | Biru/hijau | Baca saat tersedia |
| `normal` | Kuning | Baca dalam hari yang sama |
| `high` | Merah | Baca segera |

### Idempotency Notifikasi

Setiap notifikasi memiliki field `event_id` dengan format `{type}:{entity}:{id}` yang berfungsi sebagai idempotency key. Notifikasi duplikat dengan `event_id` yang sama akan diabaikan untuk menghindari spam.

## Manajemen Member & Role-Based Access Control

Admin Dashboard menyediakan kontrol penuh terhadap anggota perusahaan (`CompanyMember`) dan hak akses mereka. Sistem RBAC di SNISHOP ERP sangat granular, mencakup akses per modul, per lokasi, dan per operasi.

### Role dalam Perusahaan

Setiap `CompanyMember` memiliki role yang menentukan hak akses default:

| Role | Deskripsi | Akses Default |
| - | - | - |
| `owner` | Pemilik perusahaan | Full access ke semua modul dan pengaturan |
| `admin` | Administrator perusahaan | Akses hampir penuh, kecuali pengaturan billing |
| `supervisor` | Supervisor/mandor | Akses tim dan monitoring |
| `store_admin` | Admin toko/outlet | Akses POS dan inventori outlet |
| `stock_admin` | Admin gudang | Akses inventori dan warehouse |
| `finance_admin` | Admin keuangan | Akses modul keuangan dan invoice |
| `hr_admin` | Admin HR | Akses modul SDM, absensi, payroll |
| `transaction_admin` | Admin transaksi | Akses transaksi penjualan dan pembelian |
| `employee` | Karyawan biasa | Akses terbatas sesuai assignment |
| `production_operator` | Operator produksi | Akses modul produksi |
| `qc_inspector` | Inspector QC | Akses quality control |
| `sales_marketing` | Sales & marketing | Akses penjualan dan distribusi |
| `partner_distributor` | Partner/distributor | Akses B2B dan distribusi |

### Status Keanggotaan

| Status | Deskripsi |
| - | - |
| `active` | Anggota aktif, dapat mengakses sistem |
| `inactive` | Anggota nonaktif, akses ditangguhkan |
| `pending` | Undangan belum diterima, menunggu respons |

### Hak Akses Granular (Permissions)

Setiap `CompanyMember` memiliki objek `permissions` yang mendetail. Berikut adalah daftar lengkap hak akses yang tersedia:

**Akses Dashboard & Task:**

| Permission | Default | Deskripsi |
| - | - | - |
| `can_view_dashboard` | `true` | Melihat dashboard |
| `can_view_tasks` | `true` | Melihat daftar tugas |
| `can_create_tasks` | `true` | Membuat tugas baru |
| `can_edit_tasks` | `true` | Mengedit tugas |
| `can_delete_tasks` | `false` | Menghapus tugas |

**Akses Notes:**

| Permission | Default | Deskripsi |
| - | - | - |
| `can_view_notes` | `true` | Melihat catatan |
| `can_create_notes` | `true` | Membuat catatan baru |
| `can_edit_notes` | `true` | Mengedit catatan |
| `can_delete_notes` | `false` | Menghapus catatan |

**Akses Modul Bisnis:**

| Permission | Default | Deskripsi |
| - | - | - |
| `can_view_hr` | `false` | Melihat modul HR |
| `can_edit_hr` | `false` | Mengedit data HR |
| `can_view_finance` | `false` | Melihat modul keuangan |
| `can_edit_finance` | `false` | Mengedit data keuangan |
| `can_view_inventory` | `false` | Melihat modul inventori |
| `can_edit_inventory` | `false` | Mengedit data inventori |
| `can_view_projects` | `false` | Melihat modul proyek |
| `can_edit_projects` | `false` | Mengedit data proyek |
| `can_view_pos` | `false` | Melihat modul POS |
| `can_use_pos` | `false` | Menggunakan POS untuk transaksi |
| `can_view_reports` | `false` | Melihat laporan |

**Akses Manajemen:**

| Permission | Default | Deskripsi |
| - | - | - |
| `can_manage_members` | `false` | Mengelola anggota perusahaan |
| `can_manage_roles` | `false` | Mengelola role dan permission |
| `can_view_settings` | `false` | Melihat pengaturan perusahaan |
| `can_edit_settings` | `false` | Mengedit pengaturan perusahaan |

**Akses Operasional Khusus:**

| Permission | Default | Deskripsi |
| - | - | - |
| `can_manage_cashier_shift` | `false` | Mengelola shift kasir |
| `can_approve_stock_opname` | `false` | Menyetujui stock opname |
| `can_count_stock_opname` | `false` | Menghitung stock opname |
| `can_transfer_inventory` | `false` | Transfer antar gudang/outlet |
| `can_create_production_batch` | `false` | Membuat batch produksi |
| `can_release_production_qc` | `false` | Release QC produksi |
| `can_view_hpp` | `false` | Melihat Harga Pokok Penjualan |
| `can_manage_channel_pricing` | `false` | Mengelola harga per channel |
| `can_view_distribution` | `false` | Melihat modul distribusi |
| `can_create_distribution_shipment` | `false` | Membuat shipment distribusi |
| `can_confirm_distribution_shipment` | `false` | Konfirmasi shipment distribusi |
| `can_view_b2b_invoices` | `false` | Melihat invoice B2B |
| `can_create_b2b_invoice` | `false` | Membuat invoice B2B |
| `can_verify_b2b_payment` | `false` | Verifikasi pembayaran B2B |

### Lokasi yang Diizinkan (Assigned Locations)

Setiap `CompanyMember` dapat memiliki `assigned_locations` berupa daftar ID lokasi gudang/outlet yang diizinkan untuk diakses. Ini merupakan mekanisme RBAC tambahan untuk membatasi akses fisik member terhadap lokasi tertentu saja.

### Tipe Dashboard per Role

Melalui entitas `MenuAccessProfile`, setiap role dapat dikonfigurasi untuk melihat tipe dashboard yang berbeda:

| Dashboard Type | Deskripsi | Role yang Cocok |
| - | - | - |
| `owner` | Dashboard lengkap semua modul | Owner perusahaan |
| `admin` | Dashboard admin dengan monitoring | Admin perusahaan |
| `supervisor` | Dashboard tim dan monitoring | Supervisor |
| `employee` | Dashboard tugas dan produktivitas | Karyawan |
| `cashier` | Dashboard POS dan transaksi | Kasir |
| `finance` | Dashboard keuangan dan invoice | Finance admin |
| `hr` | Dashboard SDM dan absensi | HR admin |
| `inventory` | Dashboard stok dan gudang | Stock admin |

## Sistem Achievement & Gamifikasi

Admin Dashboard juga menampilkan metrik gamifikasi untuk memantau engagement pengguna. Data ini diambil dari entitas `User` (field produktivitas) dan `Achievement`.

### Metrik Produktivitas User

| Field | Tipe | Deskripsi |
| - | - | - |
| `productivity_score` | number | Skor produktivitas keseluruhan |
| `current_streak` | number | Streak hari berturut-turut menyelesaikan tugas |
| `longest_streak` | number | Streak terpanjang yang pernah dicapai |
| `total_tasks_completed` | number | Total tugas yang telah diselesaikan |
| `total_notes_created` | number | Total catatan yang telah dibuat |
| `achievement_points` | number | Total poin achievement |
| `user_level` | number | Level pengguna berdasarkan achievement points |

### Tipe Achievement

| Achievement Type | Deskripsi |
| - | - |
| `task_streak` | Menyelesaikan tugas beruntun |
| `first_task` | Menyelesaikan tugas pertama |
| `task_master` | Menyelesaikan banyak tugas |
| `note_taker` | Aktif membuat catatan |
| `financial_tracker` | Aktif mencatat keuangan |
| `collaborator` | Kolaborasi dengan tim |
| `early_bird` | Produktif di pagi hari |
| `night_owl` | Produktif di malam hari |
| `team_player` | Kontribusi tim |
| `productivity_champion` | Produktivitas tinggi berkelanjutan |

## Laporan & Snapshot

Admin Dashboard terintegrasi dengan sistem laporan melalui `FinancialReportSnapshot` dan `ReportTemplate` untuk menyediakan data historis dan analisis.

### Tipe Laporan Keuangan

| Report Type | Deskripsi |
| - | - |
| `profit_loss` | Laporan laba rugi |
| `balance_sheet` | Neraca keuangan |
| `cash_flow` | Arus kas |
| `budget_vs_actual` | Perbandingan anggaran vs realisasi |
| `trial_balance` | Neraca saldo |
| `custom` | Laporan kustom |

### Tipe Template Laporan

| Report Type | Deskripsi |
| - | - |
| `financial` | Laporan keuangan |
| `sales` | Laporan penjualan |
| `inventory` | Laporan inventori |
| `hr` | Laporan SDM |
| `project` | Laporan proyek |
| `custom` | Laporan kustom |

### Aggregasi Data pada Kolom Laporan

| Aggregation | Deskripsi |
| - | - |
| `sum` | Total jumlah |
| `count` | Jumlah record |
| `average` | Rata-rata |
| `min` | Nilai minimum |
| `max` | Nilai maksimum |
| `none` | Tanpa agregasi (nilai mentah) |

### Format Kolom Laporan

| Format | Deskripsi |
| - | - |
| `number` | Angka biasa |
| `currency` | Format mata uang (Rp) |
| `date` | Format tanggal |
| `text` | Teks biasa |
| `percentage` | Format persentase |

## Tips

* **Cek Admin Dashboard setiap pagi** sebagai bagian dari morning routine untuk memastikan semua sistem berjalan normal
* **Investigasi indikator kuning segera** sebelum berkembang menjadi masalah yang lebih besar
* **Audit log sangat berguna** untuk menelusuri siapa yang mengubah data tertentu dan kapan — gunakan filter untuk mempercepat pencarian
* **Review daftar sesi aktif secara berkala** dan putuskan sesi yang mencurigakan atau sudah tidak digunakan
* **Set up alert notification** ke email atau WhatsApp admin supaya langsung tahu jika ada masalah critical
* **Monitor grafik penggunaan** untuk mengidentifikasi pola trafik dan merencanakan capacity scaling
* **Export audit log secara berkala** sebagai backup dan untuk keperluan compliance
* **Manfaatkan Custom Dashboard** untuk membuat tampilan yang sesuai dengan peran Anda — owner mungkin memerlukan overview semua modul, sementara finance\_admin hanya perlu widget keuangan
* **Gunakan KPI otomatis** dengan `auto_from_attendance`, `auto_from_sales`, atau `auto_from_projects` untuk mengurangi input manual dan meningkatkan akurasi penilaian
* **Konfigurasi `assigned_locations`** untuk setiap member agar mereka hanya dapat mengakses outlet/gudang yang menjadi tanggung jawab mereka
* **Monitor `event_id` pada notifikasi** untuk memastikan tidak ada notifikasi yang terlewat atau terduplikasi secara anomali

***

## Entity Relationship Diagram

```mermaid theme={null}
erDiagram
    User ||--o{ CompanyMember : "memiliki membership di"
    User ||--o{ CustomDashboardConfig : "memiliki konfigurasi"
    User ||--o{ Notification : "menerima"
    User ||--o{ Achievement : "memperoleh"
    User ||--o{ KPI : "dinilai sebagai employee"
    User ||--o{ WorkspaceMember : "bergabung di"
    User }o--|| Company : "mengelola (owner)"

    Company ||--o{ CompanyMember : "memiliki anggota"
    Company ||--o{ CompanyKPI : "menyelenggarakan penilaian"
    Company ||--o{ CustomDashboardConfig : "memiliki dashboard"
    Company ||--o{ FinancialReportSnapshot : "menghasilkan laporan"
    Company ||--o{ ReportTemplate : "memiliki template"
    Company ||--o{ KPITemplate : "memiliki template"
    Company ||--o{ MenuAccessProfile : "memiliki profil akses"
    Company ||--o{ Workspace : "terhubung dengan"

    CompanyMember }o--|| Company : "bekerja di"
    CompanyMember ||--o{ CompanyKPI : "memiliki penilaian"

    KPITemplate ||--o{ CompanyKPI : "digunakan oleh"

    CustomDashboardConfig {
        string company_id
        string user_id
        string dashboard_name
        string description
        string role
        boolean is_public
        array widgets
        string layout
        datetime created_date
        datetime last_modified_date
    }

    User {
        string email PK
        string full_name
        string role
        string subscription_plan
        string admin_type
        string admin_tier
        number productivity_score
        number current_streak
        number user_level
    }

    Company {
        string name
        string owner_id FK
        string owner_email
        string industry
        string description
        object settings
    }

    CompanyMember {
        string company_id FK
        string user_id FK
        string user_email
        string role
        string status
        object permissions
        array assigned_locations
    }

    CompanyKPI {
        string company_id FK
        string employee_id FK
        string period
        string template_id FK
        array metrics
        number overall_score
        string rating
        string status
    }

    KPITemplate {
        string company_id FK
        string template_name
        array default_metrics
        boolean auto_calculate
        string calculation_frequency
    }

    Notification {
        string user_id FK
        string title
        string message
        string type
        string priority
        boolean is_read
        string event_id
        string company_id FK
    }

    Achievement {
        string user_id FK
        string achievement_type
        string title
        number points
        datetime earned_at
    }

    FinancialReportSnapshot {
        string company_id FK
        string report_type
        string report_name
        date start_date
        date end_date
        object report_data
    }

    ReportTemplate {
        string company_id FK
        string user_id FK
        string report_name
        string report_type
        string data_source
        array columns
    }

    MenuAccessProfile {
        string company_id FK
        string role
        string profile_name
        array allowed_menus
        string dashboard_type
    }

    Workspace {
        string name
        string owner_id FK
        string company_id FK
        boolean is_personal
    }

    WorkspaceMember {
        string workspace_id FK
        string user_id FK
        string role
        object permissions
    }
```

***

## Entity Schema Tables

### User

| Field | Type | Required | Description |
| - | - | - | - |
| `email` | string | Yes | Email pengguna |
| `full_name` | string | Yes | Nama lengkap pengguna |
| `role` | enum(`admin`, `user`) | No | Peran pengguna dalam aplikasi |
| `subscription_plan` | enum(`free`, `pro`, `business`, `advanced`, `enterprise`) | No | Plan subscription (default: `free`) |
| `subscription_start` | date-time | No | Tanggal mulai subscription |
| `subscription_end` | date-time | No | Tanggal berakhir subscription |
| `membership_duration_type` | enum(`monthly`, `yearly`, `custom`, `lifetime`) | No | Tipe durasi membership yang dipilih owner |
| `membership_start_date` | date | No | Tanggal mulai membership |
| `membership_end_date` | date | No | Tanggal berakhir membership |
| `is_readonly_mode` | boolean | No | Mode read-only ketika expired dalam grace period 3 hari (default: `false`) |
| `trial_end` | date-time | No | Tanggal berakhir trial |
| `active_company_id` | string | No | ID perusahaan yang sedang aktif untuk pengguna Business+ |
| `company_slots_purchased` | number | No | Slot perusahaan tambahan yang dibeli di luar batas plan (default: `0`) |
| `ai_monthly_usage` | number | No | Penggunaan AI bulanan (default: `0`) |
| `ai_credits` | number | No | Kredit AI yang tersedia (default: `10`) |
| `ai_addon_quota` | number | No | Kuota addon AI (default: `0`) |
| `ai_usage_period_start` | date | No | Awal periode penggunaan AI |
| `last_credit_reset` | date-time | No | Terakhir kali kredit di-reset |
| `storage_used` | number | No | Penyimpanan yang digunakan (default: `0`) |
| `referred_by` | string | No | Referral code dari pengguna yang mereferensikan |
| `referral_code` | string | No | Kode referral milik pengguna |
| `balance` | number | No | Saldo deposit untuk membeli membership/addon (default: `0`) |
| `commission_balance` | number | No | Saldo komisi dari referral yang dapat ditarik (default: `0`) |
| `admin_commission_balance` | number | No | Saldo komisi admin basic dari proses transaksi (default: `0`) |
| `total_earnings` | number | No | Total komisi yang pernah diterima/akumulasi (default: `0`) |
| `admin_type` | enum(`owner`, `basic`) | No | Tipe admin APLIKASI: owner (full access) atau basic (hanya transaksi produk digital) |
| `admin_tier` | enum(`none`, `business`, `advanced`, `enterprise`) | No | Tier admin untuk company management (default: `none`) |
| `productivity_score` | number | No | Skor produktivitas pengguna (default: `0`) |
| `current_streak` | number | No | Streak hari berturut-turut menyelesaikan tugas (default: `0`) |
| `longest_streak` | number | No | Streak terpanjang yang pernah dicapai (default: `0`) |
| `last_active_date` | date | No | Tanggal terakhir aktif |
| `total_tasks_completed` | number | No | Total tugas yang telah diselesaikan (default: `0`) |
| `total_notes_created` | number | No | Total catatan yang telah dibuat (default: `0`) |
| `achievement_points` | number | No | Total poin achievement (default: `0`) |
| `user_level` | number | No | Level pengguna berdasarkan achievement points (default: `1`) |
| `trial_plan` | string | No | Plan trial yang digunakan |
| `trial_expires` | date-time | No | Tanggal kedaluwarsa trial |
| `trial_used` | object | No | Track trial mana saja yang sudah digunakan |
| `preferences` | object | No | Preferensi pengguna (theme, primary\_color, wallpaper\_url, referral\_modal\_dismissed) |

### Company

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Nama perusahaan |
| `owner_id` | string | Yes | ID owner perusahaan |
| `owner_email` | string | Yes | Email owner |
| `owner_subscription_plan` | enum(`free`, `pro`, `business`, `advanced`, `enterprise`) | No | Plan membership owner saat ini |
| `description` | string | No | Deskripsi perusahaan |
| `industry` | enum(`retail`, `manufacturing`, `services`, `technology`, `food_beverage`, `healthcare`, `education`, `other`) | No | Industri perusahaan |
| `address` | string | No | Alamat perusahaan |
| `phone` | string | No | Nomor telepon |
| `email` | string | No | Email perusahaan |
| `website` | string | No | Website perusahaan |
| `logo_url` | string | No | URL logo perusahaan |
| `tax_id` | string | No | NPWP perusahaan |
| `employee_count` | number | No | Jumlah karyawan (default: `0`) |
| `metadata` | object | No | Data tambahan/legacy |
| `landing_page_config` | object | No | Konfigurasi landing page perusahaan |
| `business_type` | string | No | Kategori bisnis yang dipilih saat onboarding |
| `active_modules` | string | No | JSON string berisi array ID modul aktif |
| `settings` | object | No | Pengaturan perusahaan (working\_hours, leave\_policy, expiry\_thresholds, batch\_allocation\_strategy, tax, spoilage\_default\_treatment) |

### CompanyMember

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `user_id` | string | No | ID pengguna |
| `user_email` | string | Yes | Email pengguna |
| `user_name` | string | No | Nama pengguna |
| `role` | enum | No | Role dalam perusahaan (default: `employee`). Lihat tabel enum di bawah |
| `employee_id` | string | No | Link ke entitas Employee |
| `department` | string | No | Departemen |
| `position` | string | No | Jabatan |
| `status` | enum(`active`, `inactive`, `pending`) | No | Status keanggotaan (default: `active`) |
| `joined_date` | date | No | Tanggal bergabung |
| `invited_by` | string | No | Email yang mengundang |
| `permissions` | object | No | Hak akses detail untuk member (lihat tabel permissions di atas) |
| `assigned_locations` | array\[string] | No | Daftar ID lokasi gudang/outlet yang diizinkan (RBAC) |
| `working_hours` | object | No | Jam kerja karyawan (start, end) |
| `salary` | number | No | Gaji karyawan (opsional) |
| `notes` | string | No | Catatan tambahan |

### CustomDashboardConfig

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `user_id` | string | Yes | ID pengguna pemilik dashboard |
| `dashboard_name` | string | Yes | Nama dashboard |
| `description` | string | No | Deskripsi dashboard |
| `role` | string | No | Role yang bisa mengakses (opsional) |
| `is_public` | boolean | No | Apakah dashboard bisa diakses anggota lain (default: `false`) |
| `widgets` | array\[Widget] | Yes | Daftar widget dalam dashboard |
| `layout` | enum(`grid`, `list`) | No | Tata letak dashboard (default: `grid`) |
| `created_date` | date-time | No | Tanggal pembuatan |
| `last_modified_date` | date-time | No | Tanggal terakhir dimodifikasi |

**Struktur Widget (nested object):**

| Field | Type | Required | Description |
| - | - | - | - |
| `widget_id` | string | No | ID unik widget |
| `widget_type` | enum(`chart`, `table`, `metric`, `list`, `calendar`, `forecast`) | No | Tipe widget |
| `title` | string | No | Judul widget |
| `data_source` | string | No | Entity type sumber data (Invoice, FinancialRecord, dll) |
| `filters` | object | No | Filter data untuk widget |
| `chart_type` | enum(`line`, `bar`, `pie`, `area`) | No | Tipe visualisasi chart |
| `position` | object | No | Posisi widget (row, column, width, height) |
| `refresh_interval` | number | No | Interval refresh dalam detik |

### CompanyKPI

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `employee_id` | string | Yes | ID member (CompanyMember.id) |
| `employee_name` | string | No | Nama karyawan |
| `employee_email` | string | No | Email karyawan |
| `period` | string | Yes | Periode YYYY-MM (mis: "2025-04") |
| `template_id` | string | No | ID template KPI yang digunakan |
| `template_name` | string | No | Nama template |
| `description` | string | No | Penjelasan konteks evaluasi KPI (max 1000 karakter) |
| `metrics` | array\[Metric] | Yes | Daftar metrik penilaian |
| `overall_score` | number | No | Skor rata-rata tertimbang (0-100) |
| `attendance_score` | number | No | Skor kehadiran (0-100) |
| `rating` | enum(`outstanding`, `exceeds`, `meets`, `needs_improvement`, `unsatisfactory`) | No | Rating penilaian |
| `reviewer_id` | string | No | ID reviewer |
| `reviewer_name` | string | No | Nama reviewer |
| `reviewer_notes` | string | No | Catatan reviewer |
| `employee_notes` | string | No | Catatan karyawan |
| `status` | enum(`draft`, `submitted`, `reviewed`, `finalized`) | No | Status penilaian (default: `draft`) |
| `auto_generated` | boolean | No | Apakah di-generate otomatis (default: `false`) |
| `finalized_at` | date-time | No | Tanggal finalized |
| `evidence_url` | string | No | URL bukti/file pendukung pencapaian KPI |
| `evidence_note` | string | No | Catatan singkat tentang bukti (max 500 karakter) |

### KPITemplate

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `template_name` | string | Yes | Nama template KPI |
| `description` | string | No | Penjelasan template (max 1000 karakter) |
| `applicable_roles` | array\[string] | No | Role yang menggunakan template ini |
| `applicable_departments` | array\[string] | No | Departemen yang menggunakan template |
| `default_metrics` | array\[Metric] | Yes | Daftar metrik default template |
| `is_active` | boolean | No | Apakah template aktif (default: `true`) |
| `auto_calculate` | boolean | No | Otomatis calculate KPI setiap periode (default: `true`) |
| `calculation_frequency` | enum(`daily`, `weekly`, `monthly`) | No | Frekuensi perhitungan (default: `daily`) |

### Notification

| Field | Type | Required | Description |
| - | - | - | - |
| `user_id` | string | Yes | ID pengguna penerima notifikasi |
| `title` | string | Yes | Judul notifikasi |
| `message` | string | Yes | Pesan notifikasi |
| `description` | string | No | Detail tambahan/konteks (max 1000 karakter) |
| `url` | string | No | URL tujuan saat notifikasi diklik |
| `type` | enum | No | Tipe notifikasi (default: `SYSTEM`). Lihat tabel enum di bawah |
| `metadata` | object | No | Payload tambahan (invitationId, companyId, companyName) |
| `priority` | enum(`low`, `normal`, `high`) | No | Prioritas notifikasi (default: `normal`) |
| `is_read` | boolean | No | Status sudah dibaca (default: `false`) |
| `event_id` | string | No | Idempotency key (format: `{type}:{entity}:{id}`) |
| `company_id` | string | No | ID perusahaan untuk scope filter |
| `location_id` | string | No | ID lokasi untuk scope filter (opsional) |
| `source_entity` | string | No | Nama entity sumber (POSTransaction, Invoice, dll) |
| `source_id` | string | No | ID record sumber |
| `correlation_id` | string | No | Correlation ID untuk observability (NFR-04) |

### Achievement

| Field | Type | Required | Description |
| - | - | - | - |
| `user_id` | string | Yes | ID pengguna |
| `achievement_type` | enum | Yes | Jenis pencapaian. Lihat tabel enum di bawah |
| `title` | string | Yes | Judul achievement |
| `description` | string | No | Deskripsi achievement |
| `icon` | string | No | Emoji atau icon |
| `earned_at` | date-time | No | Tanggal perolehan |
| `points` | number | No | Poin yang diperoleh (default: `0`) |

### FinancialReportSnapshot

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `report_type` | enum(`profit_loss`, `balance_sheet`, `cash_flow`, `budget_vs_actual`, `trial_balance`, `custom`) | Yes | Jenis laporan |
| `report_name` | string | Yes | Nama laporan |
| `start_date` | date | Yes | Tanggal mulai periode |
| `end_date` | date | Yes | Tanggal akhir periode |
| `generated_by_user_id` | string | Yes | ID pengguna yang generate |
| `generated_date` | date-time | Yes | Tanggal waktu generate |
| `report_data` | object | Yes | JSON data laporan |
| `template_id` | string | No | ID template yang digunakan |
| `notes` | string | No | Catatan tambahan |

### ReportTemplate

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `user_id` | string | Yes | ID pengguna pembuat template |
| `report_name` | string | Yes | Nama template laporan |
| `description` | string | No | Deskripsi template |
| `report_type` | enum(`financial`, `sales`, `inventory`, `hr`, `project`, `custom`) | Yes | Tipe laporan |
| `data_source` | string | Yes | Entity type sumber data |
| `columns` | array\[Column] | Yes | Definisi kolom laporan |
| `filters` | array\[Filter] | No | Filter default |
| `group_by` | array\[string] | No | Field untuk grouping |
| `sort_by` | array\[Sort] | No | Definisi pengurutan |
| `date_range` | object | No | Rentang tanggal (start\_date, end\_date, period\_type) |
| `is_public` | boolean | No | Apakah template bisa diakses publik (default: `false`) |
| `created_date` | date-time | No | Tanggal pembuatan |

### MenuAccessProfile

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan (wajib untuk isolasi data) |
| `role` | enum(`owner`, `admin`, `supervisor`, `store_admin`, `stock_admin`, `finance_admin`, `hr_admin`, `transaction_admin`, `employee`) | Yes | Role yang menggunakan profil akses ini |
| `profile_name` | string | Yes | Nama profil akses menu |
| `description` | string | No | Penjelasan profil akses (max 1000 karakter) |
| `allowed_menus` | array\[string] | Yes | Daftar ID menu yang diizinkan |
| `dashboard_type` | enum(`owner`, `admin`, `supervisor`, `employee`, `cashier`, `finance`, `hr`, `inventory`) | No | Tipe dashboard untuk role ini (default: `employee`) |
| `is_default` | boolean | No | Apakah ini profil default untuk role ini (default: `true`) |
| `created_by` | string | No | Email owner yang membuat profil |

### Workspace

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Nama workspace |
| `owner_id` | string | Yes | ID pemilik workspace |
| `company_id` | string | No | ID perusahaan (null untuk personal workspace) |
| `description` | string | No | Deskripsi workspace |
| `icon` | string | No | Icon workspace |
| `color` | string | No | Warna tema workspace (default: `#2563eb`) |
| `is_personal` | boolean | No | Apakah workspace pribadi (default: `false`) |
| `settings` | object | No | Pengaturan (allow\_public\_sharing, default\_task\_priority) |

### WorkspaceMember

| Field | Type | Required | Description |
| - | - | - | - |
| `workspace_id` | string | Yes | ID workspace |
| `user_id` | string | Yes | ID pengguna |
| `role` | enum(`owner`, `admin`, `member`, `viewer`) | No | Peran dalam workspace (default: `member`) |
| `invited_by` | string | No | ID pengguna yang mengundang |
| `joined_at` | date-time | No | Waktu bergabung |
| `description` | string | No | Catatan tambahan mengenai anggota (max 1000 karakter) |
| `permissions` | object | No | Hak akses (can\_create\_tasks, can\_edit\_tasks, can\_delete\_tasks, can\_invite\_members, can\_access\_all\_tasks) |

***

## State Diagrams

### Status KPI (CompanyKPI & KPI)

```mermaid theme={null}
stateDiagram-v2
    [*] --> Draft: KPI dibuat (manual/otomatis)
    Draft --> Submitted: Employee mengisi data & submit
    Submitted --> Reviewed: Reviewer menilai & memberikan catatan
    Reviewed --> Finalized: Owner/Admin memfinalisasi
    Finalized --> [*]: Arsip ke FinancialReportSnapshot

    Draft --> Draft: Edit metrik/target
    Submitted --> Draft: Reviewer meminta revisi
    Reviewed --> Finalized: Finalisasi dengan approval

    state Draft {
        [*] --> MetricsConfigured
        MetricsConfigured --> DescriptionAdded
    }

    state Reviewed {
        [*] --> ScoreCalculated
        ScoreCalculated --> RatingAssigned
        RatingAssigned --> NotesAdded
    }
```

### Status Notifikasi

```mermaid theme={null}
stateDiagram-v2
    [*] --> Unread: Notifikasi dibuat
    Unread --> Read: User membuka/membaca
    Read --> [*]: Dihapus atau auto-cleanup

    Unread --> Dismissed: User menutup notifikasi
    Dismissed --> [*]: Auto-cleanup

    state Unread {
        [*] --> HighPriority: priority = high
        [*] --> NormalPriority: priority = normal
        [*] --> LowPriority: priority = low
    }
```

### Status Keanggotaan CompanyMember

```mermaid theme={null}
stateDiagram-v2
    [*] --> Pending: Undangan dikirim
    Pending --> Active: Undangan diterima
    Pending --> [*]: Undangan ditolak/kedaluwarsa
    Active --> Inactive: Dinonaktifkan oleh admin
    Inactive --> Active: Diaktifkan kembali
    Inactive --> [*]: Dihapus dari perusahaan
```

### Status Widget Dashboard

```mermaid theme={null}
stateDiagram-v2
    [*] --> Idle: Widget di-render
    Idle --> Loading: Data refresh triggered
    Loading --> Rendering: Data berhasil dimuat
    Loading --> Error: Gagal memuat data
    Rendering --> Idle: Render selesai, tunggu interval
    Error --> Retry: Auto-retry setelah delay
    Retry --> Loading: Retry dimulai
    Error --> Idle: User dismiss error

    state Rendering {
        [*] --> TransformData
        TransformData --> DrawChart
        DrawChart --> ApplyFilters
    }
```

***

## Sequence Diagrams

### Flow Memuat Admin Dashboard

```mermaid theme={null}
sequenceDiagram
    participant Admin as Admin User
    participant UI as Dashboard UI
    participant API as API Gateway
    participant DB as Database
    participant Cache as Cache Layer

    Admin->>UI: Buka Admin Dashboard
    UI->>API: GET /api/admin/dashboard/overview
    API->>Cache: Check cached data

    alt Cache Hit
        Cache-->>API: Return cached overview
    else Cache Miss
        API->>DB: Query system health metrics
        DB-->>API: Health data
        API->>DB: Query active user count
        DB-->>API: User count
        API->>DB: Query recent alerts
        DB-->>API: Alert data
        API->>Cache: Store in cache (TTL: 30s)
    end

    API-->>UI: Dashboard overview payload
    UI->>UI: Render system health indicators
    UI->>UI: Render user activity panel
    UI->>UI: Render alert notifications

    UI->>API: GET /api/admin/custom-dashboards
    API->>DB: Query CustomDashboardConfig (user_id)
    DB-->>API: Dashboard configs
    API-->>UI: Custom dashboard list

    UI->>UI: Render custom widgets
    Admin-->>UI: Dashboard siap digunakan
```

### Flow Real-Time Widget Update

```mermaid theme={null}
sequenceDiagram
    participant Widget as Widget Component
    participant Timer as Refresh Timer
    participant API as API Gateway
    participant DB as Database
    participant WS as WebSocket

    loop Setiap refresh_interval detik
        Timer->>Widget: Trigger refresh
        Widget->>API: GET /api/widgets/{widget_id}/data
        API->>DB: Query data_source with filters
        DB-->>API: Raw data
        API->>API: Apply aggregation & transform
        API-->>Widget: Widget data payload
        Widget->>Widget: Re-render chart/table/metric
    end

    Note over WS: Real-time push (untuk widget high-priority)
    WS->>Widget: Push update event
    Widget->>API: GET /api/widgets/{widget_id}/data?since={timestamp}
    API-->>Widget: Incremental data
    Widget->>Widget: Update display
```

### Flow Pembuatan Custom Dashboard

```mermaid theme={null}
sequenceDiagram
    participant Admin as Admin User
    participant UI as Dashboard Builder
    participant API as API Gateway
    participant DB as Database

    Admin->>UI: Klik "Buat Dashboard Baru"
    UI->>UI: Tampilkan form konfigurasi
    Admin->>UI: Isi nama, deskripsi, pilih layout
    Admin->>UI: Tambah widget pertama
    UI->>UI: Tampilkan widget picker

    Admin->>UI: Pilih widget_type: "chart"
    Admin->>UI: Pilih data_source: "CompanyKPI"
    Admin->>UI: Pilih chart_type: "bar"
    Admin->>UI: Konfigurasi filters & position
    Admin->>UI: Set refresh_interval: 60

    Admin->>UI: Klik "Simpan Dashboard"
    UI->>API: POST /api/custom-dashboards
    Note right of UI: Payload: { company_id, user_id,<br/>dashboard_name, widgets[], layout }
    API->>DB: INSERT CustomDashboardConfig
    DB-->>API: Created record
    API-->>UI: 201 Created + dashboard config
    UI->>UI: Redirect ke dashboard baru
    UI->>UI: Render semua widget
```

### Flow Penilaian KPI Otomatis

```mermaid theme={null}
sequenceDiagram
    participant Cron as Scheduled Job
    participant Engine as KPI Engine
    participant DB as Database
    participant Notif as Notification Service
    participant Admin as Admin/Reviewer

    Cron->>Engine: Trigger daily KPI calculation
    Engine->>DB: Query active KPITemplate (auto_calculate=true)
    DB-->>Engine: Template list

    loop Untuk setiap template
        Engine->>DB: Query CompanyMember (active, applicable_roles)
        DB-->>Engine: Employee list

        loop Untuk setiap employee
            Engine->>DB: Query data berdasarkan calculation_method
            Note right of Engine: auto_from_attendance,<br/>auto_from_sales,<br/>auto_from_projects
            DB-->>Engine: Raw metric data
            Engine->>Engine: Calculate weighted scores
            Engine->>Engine: Calculate overall_score
            Engine->>Engine: Assign rating
            Engine->>DB: UPDATE CompanyKPI metrics & scores
        end
    end

    Engine->>Notif: Send KPI update notifications
    Notif->>DB: INSERT Notification (type: SYSTEM)
    Admin->>DB: View updated KPI scores di Dashboard
```

### Flow Notifikasi Real-Time

```mermaid theme={null}
sequenceDiagram
    participant Source as System Event
    participant NotifSvc as Notification Service
    participant DB as Database
    participant WS as WebSocket Server
    participant Admin as Admin Dashboard

    Source->>NotifSvc: Event triggered (e.g., LOW_STOCK)
    NotifSvc->>NotifSvc: Check event_id (idempotency)

    alt Duplicate event_id
        NotifSvc->>NotifSvc: Skip (already sent)
    else New event
        NotifSvc->>DB: Check event_id exists?
        DB-->>NotifSvc: Not found
        NotifSvc->>DB: INSERT Notification
        DB-->>NotifSvc: Notification created
        NotifSvc->>WS: Push notification event
        WS->>Admin: Real-time notification
        Admin->>Admin: Display notification badge
        Admin->>Admin: Show toast/alert
    end
```

***

## Enum Reference Tables

### User.role

| Value | Deskripsi |
| - | - |
| `admin` | Administrator dengan akses penuh ke fitur admin |
| `user` | Pengguna biasa tanpa akses admin |

### User.subscription\_plan

| Value | Deskripsi |
| - | - |
| `free` | Plan gratis dengan fitur dasar |
| `pro` | Plan profesional dengan fitur lanjutan |
| `business` | Plan bisnis dengan multi-company support |
| `advanced` | Plan advanced dengan fitur enterprise |
| `enterprise` | Plan enterprise dengan akses penuh tanpa batas |

### User.admin\_type

| Value | Deskripsi |
| - | - |
| `owner` | Owner aplikasi — full access ke seluruh fitur aplikasi |
| `basic` | Admin basic — hanya dapat melakukan transaksi produk digital |

### User.admin\_tier

| Value | Deskripsi |
| - | - |
| `none` | Bukan admin company management |
| `business` | Admin tier business |
| `advanced` | Admin tier advanced |
| `enterprise` | Admin tier enterprise |

### User.membership\_duration\_type

| Value | Deskripsi |
| - | - |
| `monthly` | Membership bulanan |
| `yearly` | Membership tahunan |
| `custom` | Durasi kustom |
| `lifetime` | Membership seumur hidup |

### Company.industry

| Value | Deskripsi |
| - | - |
| `retail` | Ritel dan perdagangan |
| `manufacturing` | Manufaktur dan produksi |
| `services` | Jasa dan layanan |
| `technology` | Teknologi dan perangkat lunak |
| `food_beverage` | Makanan dan minuman (F\&B) |
| `healthcare` | Kesehatan dan farmasi |
| `education` | Pendidikan dan pelatihan |
| `other` | Industri lainnya |

### CompanyMember.role

| Value | Deskripsi |
| - | - |
| `owner` | Pemilik perusahaan — akses penuh |
| `admin` | Administrator — akses hampir penuh |
| `supervisor` | Supervisor/mandor — akses tim |
| `store_admin` | Admin toko/outlet — akses POS |
| `stock_admin` | Admin gudang — akses inventori |
| `finance_admin` | Admin keuangan — akses finansial |
| `hr_admin` | Admin HR — akses SDM |
| `transaction_admin` | Admin transaksi — akses transaksi |
| `employee` | Karyawan — akses terbatas |
| `production_operator` | Operator produksi — akses produksi |
| `qc_inspector` | Inspector QC — akses quality control |
| `sales_marketing` | Sales & marketing — akses penjualan |
| `partner_distributor` | Partner/distributor — akses B2B |

### CompanyMember.status

| Value | Deskripsi |
| - | - |
| `active` | Anggota aktif |
| `inactive` | Anggota nonaktif |
| `pending` | Menunggu respons undangan |

### CompanyKPI.status / KPI.status

| Value | Deskripsi |
| - | - |
| `draft` | Draft awal, belum disubmit |
| `submitted` | Sudah disubmit oleh employee |
| `reviewed` | Sudah dinilai oleh reviewer |
| `finalized` | Difiinalisasi, tidak dapat diubah |

### CompanyKPI.rating / KPI.rating

| Value | Deskripsi | Skor |
| - | - | - |
| `outstanding` | Luar biasa, jauh melampaui target | 90-100 |
| `exceeds` | Melampaui target | 75-89 |
| `meets` | Sesuai target | 60-74 |
| `needs_improvement` | Perlu perbaikan | 40-59 |
| `unsatisfactory` | Tidak memuaskan | 0-39 |

### KPITemplate.calculation\_frequency

| Value | Deskripsi |
| - | - |
| `daily` | Perhitungan setiap hari |
| `weekly` | Perhitungan setiap minggu |
| `monthly` | Perhitungan setiap bulan |

### KPITemplate.default\_metrics\[].calculation\_method

| Value | Deskripsi |
| - | - |
| `manual` | Input manual oleh reviewer/employee |
| `auto_from_attendance` | Otomatis dari data absensi |
| `auto_from_sales` | Otomatis dari data penjualan |
| `auto_from_projects` | Otomatis dari data proyek |

### KPITemplate.default\_metrics\[].auto\_source.aggregation

| Value | Deskripsi |
| - | - |
| `sum` | Total jumlah |
| `count` | Jumlah record |
| `average` | Rata-rata |
| `percentage` | Persentase |

### CustomDashboardConfig.layout

| Value | Deskripsi |
| - | - |
| `grid` | Tata letak grid (widget disusun dalam grid) |
| `list` | Tata letak list (widget disusun vertikal) |

### CustomDashboardConfig.widgets\[].widget\_type

| Value | Deskripsi |
| - | - |
| `chart` | Visualisasi grafik |
| `table` | Tabel data |
| `metric` | Angka KPI tunggal |
| `list` | Daftar item |
| `calendar` | Tampilan kalender |
| `forecast` | Prediksi berbasis data |

### CustomDashboardConfig.widgets\[].chart\_type

| Value | Deskripsi |
| - | - |
| `line` | Grafik garis |
| `bar` | Grafik batang |
| `pie` | Grafik lingkaran |
| `area` | Grafik area |

### Notification.type

| Value | Deskripsi |
| - | - |
| `SYSTEM` | Notifikasi sistem umum |
| `INVITATION` | Undangan bergabung perusahaan |
| `TASK` | Pembaruan tugas |
| `STOCK` | Peringatan stok |
| `INVOICE` | Pembaruan invoice |
| `WORKFLOW` | Status workflow |
| `ANNOUNCEMENT` | Pengumuman sistem |
| `ORDER` | Pesanan baru/diperbarui |
| `PAYMENT` | Konfirmasi pembayaran |
| `LOW_STOCK` | Stok hampir habis |
| `DISCREPANCY` | Selisih stok terdeteksi |
| `EXPIRY` | Lot mendekati kedaluwarsa |
| `BACKUP` | Status backup |
| `BTT_PENDING` | BTT menunggu proses |
| `PAYMENT_DUE` | Jatuh tempo pembayaran |
| `RECALL` | Penarikan produk |

### Notification.priority

| Value | Deskripsi |
| - | - |
| `low` | Prioritas rendah |
| `normal` | Prioritas normal |
| `high` | Prioritas tinggi |

### Notification.metadata

| Field | Type | Deskripsi |
| - | - | - |
| `invitationId` | string | ID undangan (untuk tipe INVITATION) |
| `companyId` | string | ID perusahaan terkait |
| `companyName` | string | Nama perusahaan terkait |

### Achievement.achievement\_type

| Value | Deskripsi |
| - | - |
| `task_streak` | Menyelesaikan tugas beruntun |
| `first_task` | Menyelesaikan tugas pertama kali |
| `task_master` | Menyelesaikan banyak tugas |
| `note_taker` | Aktif membuat catatan |
| `financial_tracker` | Aktif mencatat keuangan |
| `collaborator` | Kolaborasi dengan tim |
| `early_bird` | Produktif di pagi hari |
| `night_owl` | Produktif di malam hari |
| `team_player` | Kontribusi tim |
| `productivity_champion` | Produktivitas tinggi berkelanjutan |

### FinancialReportSnapshot.report\_type

| Value | Deskripsi |
| - | - |
| `profit_loss` | Laporan laba rugi |
| `balance_sheet` | Neraca keuangan |
| `cash_flow` | Laporan arus kas |
| `budget_vs_actual` | Perbandingan anggaran vs realisasi |
| `trial_balance` | Neraca saldo |
| `custom` | Laporan kustom |

### ReportTemplate.report\_type

| Value | Deskripsi |
| - | - |
| `financial` | Laporan keuangan |
| `sales` | Laporan penjualan |
| `inventory` | Laporan inventori |
| `hr` | Laporan SDM |
| `project` | Laporan proyek |
| `custom` | Laporan kustom |

### ReportTemplate.columns\[].aggregation

| Value | Deskripsi |
| - | - |
| `sum` | Total jumlah |
| `count` | Jumlah record |
| `average` | Rata-rata |
| `min` | Nilai minimum |
| `max` | Nilai maksimum |
| `none` | Tanpa agregasi |

### ReportTemplate.columns\[].format

| Value | Deskripsi |
| - | - |
| `number` | Format angka |
| `currency` | Format mata uang |
| `date` | Format tanggal |
| `text` | Format teks |
| `percentage` | Format persentase |

### ReportTemplate.filters\[].operator

| Value | Deskripsi |
| - | - |
| `equals` | Sama dengan |
| `contains` | Mengandung |
| `gt` | Lebih besar dari |
| `lt` | Lebih kecil dari |
| `between` | Di antara (range) |

### ReportTemplate.date\_range.period\_type

| Value | Deskripsi |
| - | - |
| `custom` | Rentang kustom |
| `last_7_days` | 7 hari terakhir |
| `last_30_days` | 30 hari terakhir |
| `this_month` | Bulan ini |
| `this_quarter` | Kuartal ini |
| `this_year` | Tahun ini |

### MenuAccessProfile.role

| Value | Deskripsi |
| - | - |
| `owner` | Pemilik perusahaan |
| `admin` | Administrator |
| `supervisor` | Supervisor |
| `store_admin` | Admin toko |
| `stock_admin` | Admin gudang |
| `finance_admin` | Admin keuangan |
| `hr_admin` | Admin HR |
| `transaction_admin` | Admin transaksi |
| `employee` | Karyawan |

### MenuAccessProfile.dashboard\_type

| Value | Deskripsi |
| - | - |
| `owner` | Dashboard lengkap semua modul |
| `admin` | Dashboard admin dengan monitoring |
| `supervisor` | Dashboard tim |
| `employee` | Dashboard tugas & produktivitas |
| `cashier` | Dashboard POS & transaksi |
| `finance` | Dashboard keuangan |
| `hr` | Dashboard SDM & absensi |
| `inventory` | Dashboard stok & gudang |

### WorkspaceMember.role

| Value | Deskripsi |
| - | - |
| `owner` | Pemilik workspace |
| `admin` | Administrator workspace |
| `member` | Anggota biasa |
| `viewer` | Hanya bisa melihat |

### Company.settings.batch\_allocation\_strategy

| Value | Deskripsi |
| - | - |
| `fifo` | First-In-First-Out berdasarkan tanggal terima |
| `fefo` | First-Expiry-First-Out berdasarkan kedaluwarsa |

### Company.settings.spoilage\_default\_treatment

| Value | Deskripsi |
| - | - |
| `absorbed_normal` | Spoilage masuk HPP unit baik |
| `expense_abnormal` | Dipisah sebagai beban periode |

### Company.settings.tax.mode

| Value | Deskripsi |
| - | - |
| `inclusive` | Pajak sudah termasuk dalam harga |
| `exclusive` | Pajak ditambah ke harga |

### Company.settings.tax.rounding

| Value | Deskripsi |
| - | - |
| `per_line` | Pembulatan per baris item |
| `per_transaction` | Pembulatan per transaksi |

***

## RBAC Permission Matrix

Tabel berikut merangkum hak akses default untuk setiap role dalam perusahaan (`CompanyMember`):

| Permission | owner | admin | supervisor | store\_admin | stock\_admin | finance\_admin | hr\_admin | employee |
| - | - | - | - | - | - | - | - | - |
| `can_view_dashboard` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `can_view_tasks` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `can_create_tasks` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `can_edit_tasks` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `can_delete_tasks` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_view_notes` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `can_create_notes` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `can_edit_notes` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `can_delete_notes` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_view_hr` | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
| `can_edit_hr` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ |
| `can_view_finance` | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| `can_edit_finance` | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| `can_view_inventory` | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| `can_edit_inventory` | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| `can_view_projects` | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_edit_projects` | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_view_pos` | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| `can_use_pos` | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| `can_view_reports` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| `can_manage_members` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_manage_roles` | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_view_settings` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_edit_settings` | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_manage_cashier_shift` | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| `can_approve_stock_opname` | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
| `can_count_stock_opname` | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| `can_transfer_inventory` | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| `can_create_production_batch` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_release_production_qc` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_view_hpp` | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| `can_manage_channel_pricing` | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| `can_view_distribution` | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_create_distribution_shipment` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_confirm_distribution_shipment` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `can_view_b2b_invoices` | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| `can_create_b2b_invoice` | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| `can_verify_b2b_payment` | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |

<Caption>
  Tabel RBAC di atas menunjukkan hak akses **default** untuk setiap role. Administrator perusahaan dapat menyesuaikan permission individual per `CompanyMember` melalui objek `permissions`. Permission yang ditampilkan di sini adalah nilai default dari definisi entitas — owner dan admin secara implisit memiliki semua akses terlepas dari nilai default.
</Caption>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.