> ## 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.

# Company settings

<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: "Company Settings"
description: "Konfigurasi tingkat perusahaan untuk profil, branding, multi-lokasi, pajak, integrasi, dan kebijakan global SNISHOP ERP."
---------------------------------------------------------------------------------------------------------------------------------------

# Company Settings

<img src="https://mintcdn.com/quinnofspicy/e4f_upKhVWcjsUmM/docs/mintlify/screenshots/core/company-settings.png?fit=max&auto=format&n=e4f_upKhVWcjsUmM&q=85&s=105c6b556e61c9eb909e8705ca872ef6" alt="Company Settings" width="1920" height="1080" data-path="docs/mintlify/screenshots/core/company-settings.png" />

**Company Settings** adalah pusat konfigurasi tingkat perusahaan yang hanya bisa diakses oleh admin atau owner. Halaman ini mengatur **identitas, operasional, dan integrasi** perusahaan secara keseluruhan — semua pengaturan di sini berlaku global untuk seluruh user dan modul di dalam perusahaan.

Pengaturan yang benar di halaman ini sangat kritis karena menjadi **foundation** bagi seluruh modul lainnya. Data perusahaan muncul di invoice, laporan, receipt, dan dokumen legal lainnya.

## Arsitektur Konfigurasi

```mermaid theme={null}
graph TD
    A[Company Settings] --> B[Identitas]
    A --> C[Branding]
    A --> D[Multi-Lokasi]
    A --> E[Pajak]
    A --> F[Integrasi]
    A --> G[Dokumen]
    A --> H[Operasional]
    
    B --> B1[Nama & NPWP]
    B --> B2[Alamat legal]
    B --> B3[Logo & warna]
    
    D --> D1[Cabang]
    D --> D2[Gudang]
    D --> D3[Toko]
    
    E --> E1[PPN]
    E --> E2[PPh]
    E --> E3[Pajak daerah]
    
    F --> F1[Payment gateway]
    F --> F2[Marketplace]
    F --> F3[WhatsApp API]
    F --> F4[Akuntansi]
    
    G --> G1[Prefix nomor]
    G --> G2[Template dokumen]
    
    H --> H1[Jam operasional]
    H --> H2[Hari libur]
    H --> H3[Mata uang]
```

## Ringkasan Entitas

Halaman Company Settings mengelola **seluruh entitas konfigurasi** yang saling terhubung. Setiap entitas bertanggung jawab atas satu domain konfigurasi spesifik:

| Entitas | Fungsi Utama | Scope |
| - | - | - |
| **Company** | Identitas legal, profil, dan pengaturan global perusahaan | Perusahaan |
| **CompanyMember** | Manajemen anggota, role, dan hak akses (RBAC) | Perusahaan |
| **CompanyPOSSettings** | Konfigurasi sistem kasir (POS) dan pengaturan struk POS | Perusahaan |
| **CompanyReceiptSettings** | Konfigurasi tampilan struk pembelian | Perusahaan |
| **CompanyAttendanceSettings** | Kebijakan absensi, geofence, shift, dan lembur | Perusahaan |
| **CompanyModuleSettings** | Aktivasi modul, metode inventaris, dan workflow automation | Perusahaan |
| **CompanyWablasSettings** | Integrasi WhatsApp via Wablas untuk notifikasi transaksi | Perusahaan |
| **PrinterSettings** | Konfigurasi printer thermal Bluetooth untuk cetak struk | User/Perusahaan |
| **Subscription** | Manajemen langganan layanan dan billing cycle | User/Perusahaan |
| **CompanyBackup** | Backup dan restore data perusahaan | Perusahaan |
| **CompanyInvitation** | Undangan member baru ke perusahaan | Perusahaan |
| **WarehouseLocation** | Lokasi gudang, outlet, dan transit | Perusahaan |
| **ShopSettings** | Konfigurasi tampilan toko online | Perusahaan |

## Tab Konfigurasi

### 1. Tab Profil Perusahaan

Informasi legal dan identitas perusahaan:

| Field | Deskripsi | Wajib | Ditampilkan Di |
| - | - | - | - |
| **Nama Perusahaan** | Nama legal perusahaan (PT/CV) | Ya | Invoice, laporan, receipt |
| **Nama Dagang** | Nama brand/merek yang dikenal pelanggan | Ya | Toko online, marketing |
| **NPWP** | Nomor Pokok Wajib Pajak | Ya | Faktur pajak, laporan pajak |
| **NIB** | Nomor Induk Berusaha | Tidak | Dokumen legal |
| **Alamat Legal** | Alamat sesuai akta perusahaan | Ya | Invoice, kwitansi |
| **Kota** | Kota domisili perusahaan | Ya | Alamat invoice |
| **Kode Pos** | Kode pos alamat | Ya | Alamat invoice |
| **Telepon** | Nomor telepon kantor | Ya | Kontak di invoice |
| **Email** | Email resmi perusahaan | Ya | Korespondensi |
| **Website** | URL website perusahaan | Tidak | Marketing material |

### 2. Tab Branding

Kustomisasi visual untuk dokumen dan aplikasi:

| Pengaturan | Deskripsi | Spesifikasi |
| - | - | - |
| **Logo Utama** | Logo perusahaan | PNG/JPG, min 300x300px, max 5MB |
| **Logo Kecil** | Logo untuk favicon & header | PNG, 64x64px |
| **Warna Primer** | Warna utama brand | Hex code (contoh: #FF5722) |
| **Warna Sekunder** | Warna aksen | Hex code |
| **Font Dokumen** | Font untuk invoice & laporan | Sans-serif / Serif / Mono |
| **Tagline** | Slogan perusahaan | Max 100 karakter |
| **Footer Dokumen** | Teks footer di invoice/laporan | Custom text |
| **Watermark** | Watermark untuk dokumen | PNG transparan (opsional) |

**Preview Branding:**
Setiap perubahan branding bisa langsung di-preview pada template invoice, receipt, dan laporan sebelum disimpan.

### 3. Tab Lokasi

Manajemen multi-lokasi usaha (cabang, gudang, toko):

| Field | Deskripsi |
| - | - |
| **Nama Lokasi** | Nama cabang/gudang/toko |
| **Tipe** | Cabang / Gudang / Toko / Kantor Pusat |
| **Alamat** | Alamat lengkap lokasi |
| **Kota** | Kota lokasi |
| **Telepon** | Nomor telepon lokasi |
| **PIC** | Person in charge di lokasi |
| **Jam Operasional** | Jam buka dan tutup |
| **Status** | Aktif / Non-aktif |

**Fitur Multi-Lokasi:**

* Tambah unlimited lokasi (sesuai paket berlangganan)
* Stok terpisah per lokasi dengan transfer antar lokasi
* Laporan penjualan & stok per lokasi
* Harga berbeda per lokasi (opsional)
* User assignment per lokasi

### 4. Tab Pajak

Konfigurasi perpajakan perusahaan:

| Jenis Pajak | Tarif | Deskripsi |
| - | - | - |
| **PPN** | 11% | Pajak Pertambahan Nilai (default) |
| **PPnBM** | Custom | Pajak Penjualan atas Barang Mewah |
| **PPh 21** | Progressive | Pajak penghasilan karyawan |
| **PPh 23** | 2% / 15% | Pajak atas jasa |
| **Pajak Daerah** | Custom | Retribusi atau pajak daerah |

**Pengaturan Pajak:**

* Aktifkan/nonaktifkan per jenis pajak
* Set tarif custom per jenis pajak
* Konfigurasi apakah harga sudah termasuk pajak (tax inclusive) atau belum (tax exclusive)
* Mapping akun pajak untuk integrasi dengan modul Keuangan
* Format faktur pajak sesuai regulasi terbaru

### 5. Tab Integrasi

Hubungkan SNISHOP ERP dengan layanan eksternal:

| Integrasi | Status | Fungsi |
| - | - | - |
| **Payment Gateway** | Connect/Disconnect | Terima pembayaran online (Midtrans, Xendit) |
| **Marketplace** | Connect/Disconnect | Sync produk & order dari Tokopedia, Shopee |
| **WhatsApp API** | Connect/Disconnect | Kirim notifikasi & chat via WhatsApp |
| **Akuntansi** | Connect/Disconnect | Sync jurnal ke software akuntansi |
| **Email Marketing** | Connect/Disconnect | Kirim campaign email (Mailgun, SendGrid) |
| **Shipping** | Connect/Disconnect | Cek ongkir & generate resi (RajaOngkir, JNE) |
| **Accounting** | Connect/Disconnect | Export laporan ke format akuntansi |

### 6. Tab Dokumen

Konfigurasi penomoran dan template dokumen:

| Dokumen | Prefix | Format | Contoh |
| - | - | - | - |
| **Invoice** | INV | INV/YYYY/MM/XXXX | INV/2026/01/0001 |
| **Purchase Order** | PO | PO/YYYY/MM/XXXX | PO/2026/01/0001 |
| **Sales Order** | SO | SO/YYYY/MM/XXXX | SO/2026/01/0001 |
| **Delivery Order** | DO | DO/YYYY/MM/XXXX | DO/2026/01/0001 |
| **Stock Opname** | SO | SO-OPN/YYYY/MM/XXXX | SO-OPN/2026/01/0001 |
| **Production Order** | PROD | PROD/YYYY/MM/XXXX | PROD/2026/01/0001 |
| **Receipt** | RCP | RCP/YYYY/MM/XXXX | RCP/2026/01/0001 |

### 7. Tab Operasional

Pengaturan operasional harian:

| Pengaturan | Opsi | Deskripsi |
| - | - | - |
| **Mata Uang Utama** | IDR / USD / Custom | Mata uang default di laporan |
| **Jam Operasional** | Custom per hari | Jam buka dan tutup perusahaan |
| **Hari Libur** | List tanggal | Hari libur nasional & cuti bersama |
| **Fiscal Year** | Januari-Desember / April-Maret | Tahun buku perusahaan |
| **Rounding** | Ke rupiah terdekat / Tanpa rounding | Pembulatan angka di transaksi |

***

## Pengaturan POS (CompanyPOSSettings)

Entitas **CompanyPOSSettings** mengelola konfigurasi sistem kasir (POS) perusahaan. Pengaturan ini mencakup deskripsi konfigurasi dan pengaturan struk POS yang detail.

### Fungsi Utama

* Menyimpan catatan konfigurasi sistem kasir yang digunakan perusahaan
* Mengatur tampilan dan konten struk POS
* Menentukan ukuran kertas, font, dan elemen visual struk
* Mengontrol apakah informasi tertentu ditampilkan di struk (logo, NPWP, nama kasir, dll)

### Pengaturan Struk POS

| Field | Tipe | Default | Deskripsi |
| - | - | - | - |
| `receipt_settings.logo_url` | string | - | URL logo perusahaan untuk struk |
| `receipt_settings.business_name` | string | - | Nama bisnis yang ditampilkan di struk |
| `receipt_settings.business_address` | string | - | Alamat lengkap di struk |
| `receipt_settings.business_phone` | string | - | Nomor telepon di struk |
| `receipt_settings.business_email` | string | - | Email bisnis di struk |
| `receipt_settings.tax_id` | string | - | NPWP/Tax ID di struk |
| `receipt_settings.receipt_width` | enum | `80mm` | Ukuran kertas struk: `58mm` atau `80mm` |
| `receipt_settings.show_logo` | boolean | `true` | Tampilkan logo di struk |
| `receipt_settings.show_tax_id` | boolean | `false` | Tampilkan NPWP di struk |
| `receipt_settings.show_cashier_name` | boolean | `true` | Tampilkan nama kasir |
| `receipt_settings.show_customer_info` | boolean | `true` | Tampilkan informasi customer |
| `receipt_settings.show_item_image` | boolean | `false` | Tampilkan gambar item di struk |
| `receipt_settings.header_text` | string | `STRUK PEMBELIAN` | Teks header struk |
| `receipt_settings.footer_message` | string | `Terima kasih atas kunjungan Anda!...` | Teks footer struk |
| `receipt_settings.print_auto_after_transaction` | boolean | `true` | Auto cetak setelah transaksi |
| `receipt_settings.font_size` | enum | `medium` | Ukuran font: `small`, `medium`, `large` |

***

## Pengaturan Struk (CompanyReceiptSettings)

Entitas **CompanyReceiptSettings** mengelola konfigurasi tampilan struk pembelian secara terpisah dari pengaturan POS. Entitas ini memberikan kontrol lebih granular atas elemen-elemen yang ditampilkan pada struk.

### Elemen Tampilan Struk

| Field | Tipe | Default | Deskripsi |
| - | - | - | - |
| `show_company_logo` | boolean | `true` | Tampilkan logo perusahaan di struk |
| `show_company_address` | boolean | `true` | Tampilkan alamat perusahaan |
| `show_customer_name` | boolean | `true` | Tampilkan nama customer |
| `show_customer_points` | boolean | `true` | Tampilkan total poin customer saat ini |
| `show_points_earned` | boolean | `true` | Tampilkan poin yang didapat dari transaksi ini |
| `show_payment_details` | boolean | `true` | Tampilkan detail pembayaran |
| `show_change` | boolean | `true` | Tampilkan uang kembalian |
| `custom_header_text` | string | - | Teks custom di header struk |
| `custom_footer_text` | string | `Terima kasih sudah berbelanja!` | Teks custom di footer struk |
| `show_promo_message` | boolean | `false` | Tampilkan pesan promo/marketing |
| `promo_message` | string | - | Isi pesan promo/marketing |

<Tip>
  Gunakan `show_promo_message` dan `promo_message` untuk menyisipkan pesan marketing di setiap struk, misalnya informasi diskon berikutnya, program loyalty, atau promo musim tertentu.
</Tip>

***

## Pengaturan Absensi (CompanyAttendanceSettings)

Entitas **CompanyAttendanceSettings** mengelola kebijakan absensi dan pengaturan jam kerja perusahaan secara komprehensif. Termasuk dukungan multi-lokasi geofence dan manajemen shift.

### Lokasi Kantor & Geofence

| Field | Tipe | Default | Deskripsi |
| - | - | - | - |
| `office_location.latitude` | number | - | Garis lintang kantor utama |
| `office_location.longitude` | number | - | Garis bujur kantor utama |
| `office_location.address` | string | - | Alamat fisik kantor utama |
| `office_radius_meters` | number | `100` | Radius geofence kantor utama (meter) |
| `require_office_location` | boolean | `false` | Wajibkan absen dari lokasi kantor |
| `default_accuracy_tolerance_meters` | number | `150` | Toleransi akurasi GPS default (meter) |

### Multi-Lokasi Geofence

Sistem mendukung **multi-lokasi geofence** melalui array `locations`. Setiap lokasi memiliki konfigurasi independen:

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `location_id` | string | Ya | ID unik area/lokasi absensi |
| `name` | string | Ya | Nama lokasi (misal: Head Office, Outlet 2) |
| `address` | string | Tidak | Alamat fisik lokasi |
| `latitude` | number | Ya | Garis lintang pusat geofence |
| `longitude` | number | Ya | Garis bujur pusat geofence |
| `radius_meters` | number | Tidak | Radius lingkaran geofence (default: 100m) |
| `accuracy_tolerance_meters` | number | Tidak | Toleransi akurasi GPS (default: 150m) |
| `assigned_employee_ids` | array\[string] | Tidak | Daftar ID karyawan yang ditugaskan (kosong = semua) |
| `is_active` | boolean | Tidak | Status aktif lokasi geofence |

### Jam Kerja & Shift

**Pengaturan jam kerja default:**

| Field | Tipe | Default | Deskripsi |
| - | - | - | - |
| `working_hours.start_time` | string | `09:00` | Jam mulai kerja (HH:MM) |
| `working_hours.end_time` | string | `17:00` | Jam selesai kerja (HH:MM) |
| `working_hours.break_duration_minutes` | number | `60` | Durasi istirahat (menit) |
| `working_days` | array\[number] | `[1,2,3,4,5]` | Hari kerja (1=Senin, 7=Minggu) |

**Pengaturan shift** disimpan sebagai array `shifts`:

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `shift_id` | string | Ya | ID unik shift |
| `shift_name` | string | Ya | Nama shift (misal: Shift Pagi) |
| `start_time` | string | Ya | Jam mulai shift (HH:MM) |
| `end_time` | string | Ya | Jam selesai shift (HH:MM) |
| `break_duration_minutes` | number | Tidak | Durasi istirahat shift (default: 60 menit) |

### Lembur & Toleransi

| Field | Tipe | Default | Deskripsi |
| - | - | - | - |
| `overtime_settings.enabled` | boolean | `true` | Aktifkan fitur lembur |
| `overtime_settings.start_after_hours` | number | `8` | Lembur dimulai setelah X jam kerja |
| `overtime_settings.max_overtime_hours_per_day` | number | `4` | Maksimal jam lembur per hari |
| `late_tolerance_minutes` | number | `15` | Toleransi keterlambatan (menit) |

### Pengaturan Absensi Lainnya

| Field | Tipe | Default | Deskripsi |
| - | - | - | - |
| `auto_clock_out_enabled` | boolean | `false` | Otomatis clock out jika karyawan lupa |
| `auto_clock_out_time` | string | `18:00` | Jam auto clock out |
| `require_photo` | boolean | `true` | Wajib foto selfie saat absen |
| `require_notes` | boolean | `false` | Wajib catatan saat absen |

***

## Pengaturan Printer (PrinterSettings)

Entitas **PrinterSettings** mengelola konfigurasi printer thermal Bluetooth yang digunakan untuk mencetak struk. Setiap user bisa memiliki beberapa printer yang tersimpan, dan satu di antaranya bisa dijadikan printer default.

### Konfigurasi Printer

| Field | Tipe | Default | Deskripsi |
| - | - | - | - |
| `printer_name` | string | - | Nama printer yang tersimpan |
| `device_id` | string | - | Bluetooth device ID |
| `device_name` | string | - | Nama device dari Bluetooth |
| `paper_width` | enum | `80mm` | Lebar kertas thermal: `58mm` atau `80mm` |
| `encoding` | enum | `UTF-8` | Character encoding: `UTF-8`, `GB18030`, `Big5`, `Shift_JIS`, `EUC-KR` |
| `auto_cut` | boolean | `true` | Auto cut paper setelah print |
| `beep_on_print` | boolean | `false` | Beep sound saat print |
| `auto_reconnect` | boolean | `true` | Auto reconnect jika disconnect |
| `print_logo` | boolean | `true` | Print logo di struk |
| `logo_url` | string | - | URL logo untuk di-print |
| `header_text` | string | `STRUK PEMBELIAN` | Header struk |
| `footer_text` | string | `Terima kasih atas kunjungan Anda` | Footer struk |
| `font_size` | enum | `normal` | Ukuran font: `small`, `normal`, `large` |
| `is_default` | boolean | `false` | Jadikan printer default |

### Monitoring Koneksi

| Field | Tipe | Default | Deskripsi |
| - | - | - | - |
| `last_connected` | datetime | - | Terakhir kali printer terhubung |
| `connection_count` | number | `0` | Jumlah koneksi berhasil |

<Warning>
  Printer diatur pada level **per-user**, bukan per-perusahaan. Setiap karyawan yang menangani kasir perlu mengonfigurasi printer mereka masing-masing. Field `company_id` pada PrinterSettings bersifat opsional dan digunakan jika printer dipakai bersama dalam satu perusahaan.
</Warning>

***

## Cara Akses

| Metode | Cara | Syarat |
| - | - | - |
| **Sidebar** | Menu **Settings** → tab **Company Settings** | Role: Admin / Owner |
| **Quick Access** | Klik avatar → **Company Settings** | Role: Admin / Owner |
| **Command Palette** | `Ctrl+K` → ketik "Company Settings" | Role: Admin / Owner |

## Flow Setup Awal

```mermaid theme={null}
flowchart TD
    A[Setup Awal Perusahaan] --> B[Isi Profil Perusahaan]
    B --> C[Upload Logo & Branding]
    C --> D[Tambahkan Lokasi Usaha]
    D --> E[Konfigurasi Pajak]
    E --> F[Set Prefix Dokumen]
    F --> G[Atur Jam Operasional]
    G --> H[Hubungkan Integrasi]
    H --> I[Simpan & Verifikasi]
    I --> J[Perusahaan siap digunakan]
```

## Perizinan Akses

| Role | Lihat | Edit Profil | Edit Branding | Edit Lokasi | Edit Pajak | Edit Integrasi |
| - | - | - | - | - | - | - |
| **Owner** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| **Admin** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| **Manager** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Staff** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |

## Tips

* **Lengkapi profil perusahaan di awal implementasi** — data ini muncul di semua invoice dan laporan yang kamu buat
* **Upload logo dengan resolusi minimal 300x300px** supaya tidak pecah saat dicetak di invoice atau laporan
* **Tambahkan semua lokasi usaha sejak awal** supaya data stok dan penjualan per lokasi langsung terpantau
* **Konsultasikan konfigurasi pajak dengan akuntan** sebelum mengaktifkan, supaya setting sesuai kewajiban perpajakan
* **Test integrasi payment gateway di sandbox** sebelum go-live untuk memastikan alur pembayaran berjalan benar
* **Backup konfigurasi secara berkala** — export settings ke file JSON untuk keperluan disaster recovery
* **Review prefix dokumen** sebelum mulai bertransaksi — mengubah prefix setelah ada transaksi bisa menyebabkan duplikasi nomor

***

## Entity Relationship Diagram

```mermaid theme={null}
erDiagram
    Company ||--o{ CompanyMember : "memiliki"
    Company ||--o{ CompanyBackup : "di-backup"
    Company ||--o{ CompanyInvitation : "mengirim"
    Company ||--o| CompanyPOSSettings : "mengkonfigurasi POS"
    Company ||--o| CompanyReceiptSettings : "mengkonfigurasi struk"
    Company ||--o| CompanyAttendanceSettings : "mengkonfigurasi absensi"
    Company ||--o{ CompanyModuleSettings : "mengkonfigurasi"
    Company ||--o{ CompanyWablasSettings : "mengintegrasikan"
    Company ||--o{ PrinterSettings : "menggunakan printer"
    Company ||--o{ WarehouseLocation : "memiliki"
    Company ||--o{ ShopSettings : "mengatur"
    Company ||--o{ Subscription : "memiliki"
    Company }o--|| PricingPlan : "berlangganan"
    Company ||--o{ AddonRequest : "mengajukan"
    CompanyMember }o--o{ WarehouseLocation : "di-assign ke lokasi"
    CompanyMember }o--|| User : "terhubung ke user"
    CompanyAttendanceSettings ||--o{ locations : "multi-geofence"
    CompanyAttendanceSettings ||--o{ shifts : "daftar shift"
    PrinterSettings }o--|| User : "dimiliki oleh user"

    Company {
        string id PK
        string name "Nama perusahaan"
        string owner_id FK "ID owner perusahaan"
        string owner_email "Email owner"
        string owner_subscription_plan "Plan membership owner"
        string description "Deskripsi perusahaan"
        string industry "Sektor industri"
        string address "Alamat legal"
        string phone "Nomor telepon"
        string email "Email resmi"
        string website "URL website"
        string logo_url "URL logo"
        string tax_id "NPWP"
        number employee_count "Jumlah karyawan"
        object metadata "Data tambahan / legacy"
        object landing_page_config "Konfigurasi landing page"
        string business_type "Kategori bisnis onboarding"
        string active_modules "JSON array ID modul aktif"
        object settings "Pengaturan operasional"
    }

    CompanyMember {
        string id PK
        string company_id FK "ID perusahaan"
        string user_id FK "ID pengguna"
        string user_email "Email pengguna"
        string user_name "Nama pengguna"
        string role "Role dalam perusahaan"
        string employee_id "Link ke Employee"
        string department "Departemen"
        string position "Jabatan"
        string status "Status keanggotaan"
        date joined_date "Tanggal bergabung"
        string invited_by "Email pengundang"
        object permissions "Hak akses detail"
        array assigned_locations "Daftar ID lokasi"
        object working_hours "Jam kerja karyawan"
        number salary "Gaji karyawan"
        string notes "Catatan tambahan"
    }

    CompanyBackup {
        string id PK
        string company_id FK "ID perusahaan"
        string company_name "Nama perusahaan snapshot"
        string backup_type "Jenis backup"
        string backup_scope "Cakupan backup"
        datetime backup_date "Tanggal backup"
        string created_by_email "Email pembuat backup"
        string created_by_name "Nama pembuat backup"
        object data_summary "Ringkasan data backup"
        string file_url "URL file backup JSON"
        number file_size_mb "Ukuran file MB"
        string notes "Catatan backup"
        string status "Status backup"
        string checksum "SHA-256 checksum"
        string schema_version "Versi schema backup"
        string backup_version "Versi platform"
        string error_log "Log error"
        datetime restore_tested_at "Timestamp restore test"
        number restore_record_count "Jumlah record restore"
        number retention_days "Hari retensi backup"
        string drive_file_id "ID file Google Drive"
        string drive_integration_status "Status integrasi Drive"
    }

    CompanyInvitation {
        string id PK
        string company_id FK "ID perusahaan"
        string company_name "Nama perusahaan"
        string invited_email "Email yang diundang"
        string invited_by "Email pengundang"
        string invited_by_name "Nama pengundang"
        string role "Role yang ditawarkan"
        string department "Departemen"
        string position "Jabatan"
        string description "Pesan undangan"
        object permissions "Hak akses awal"
        string message "Pesan tambahan"
        string status "Status undangan"
        datetime expires_at "Kadaluarsa"
        datetime accepted_at "Diterima"
        datetime rejected_at "Ditolak"
        datetime cancelled_at "Dibatalkan"
    }

    CompanyPOSSettings {
        string id PK
        string company_id FK "ID perusahaan"
        string description "Catatan konfigurasi POS"
        object receipt_settings "Pengaturan struk POS"
    }

    CompanyReceiptSettings {
        string id PK
        string company_id FK "ID perusahaan"
        string description "Catatan konfigurasi struk"
        boolean show_company_logo "Tampilkan logo"
        boolean show_company_address "Tampilkan alamat"
        boolean show_customer_name "Tampilkan nama customer"
        boolean show_customer_points "Tampilkan poin customer"
        boolean show_points_earned "Tampilkan poin didapat"
        boolean show_payment_details "Tampilkan detail bayar"
        boolean show_change "Tampilkan kembalian"
        string custom_header_text "Header custom"
        string custom_footer_text "Footer custom"
        boolean show_promo_message "Tampilkan promo"
        string promo_message "Pesan promo"
    }

    CompanyAttendanceSettings {
        string id PK
        string company_id FK "ID perusahaan"
        string description "Catatan kebijakan absensi"
        object office_location "Lokasi kantor utama"
        number office_radius_meters "Radius geofence"
        boolean require_office_location "Wajib dari kantor"
        number default_accuracy_tolerance_meters "Toleransi GPS"
        array locations "Multi-lokasi geofence"
        object working_hours "Jam kerja"
        array shifts "Daftar shift"
        object overtime_settings "Pengaturan lembur"
        number late_tolerance_minutes "Toleransi terlambat"
        array working_days "Hari kerja"
        boolean auto_clock_out_enabled "Auto clock out"
        string auto_clock_out_time "Jam auto clock out"
        boolean require_photo "Wajib foto selfie"
        boolean require_notes "Wajib catatan"
    }

    CompanyModuleSettings {
        string id PK
        string company_id FK "ID perusahaan"
        string description "Catatan konfigurasi"
        object modules_enabled "Modul yang diaktifkan"
        string business_type "Tipe bisnis"
        string inventory_method "Metode inventaris"
        boolean multi_warehouse_enabled "Multi gudang"
        boolean lot_tracking_enabled "Lot tracking"
        boolean serial_tracking_enabled "Serial tracking"
        boolean barcode_enabled "Barcode"
        boolean auto_reorder_enabled "Auto reorder"
        boolean production_planning_enabled "Production planning"
        boolean quality_control_enabled "Quality control"
        boolean attendance_integration "Integrasi absensi"
        boolean invoice_auto_create "Auto create invoice"
        boolean pos_inventory_sync "Sync POS ke inventory"
        boolean finance_auto_record "Auto record finance"
        array custom_fields "Custom fields per modul"
        array workflow_rules "Automation workflow"
        object notification_settings "Pengaturan notifikasi"
    }

    CompanyWablasSettings {
        string id PK
        string company_id FK "ID perusahaan"
        string description "Catatan integrasi"
        boolean use_system_api "Gunakan API sistem"
        string wablas_api_key "API Key Wablas"
        string wablas_secret_key "Secret Key Wablas"
        string wablas_domain "Domain server Wablas"
        boolean is_active "Status aktif"
        boolean auto_send_receipt "Auto kirim struk"
        string receipt_message_template "Template pesan struk"
    }

    PrinterSettings {
        string id PK
        string company_id FK "ID perusahaan (opsional)"
        string user_id FK "ID user pemilik"
        string printer_name "Nama printer"
        string description "Catatan konfigurasi"
        string device_id "Bluetooth device ID"
        string device_name "Nama device Bluetooth"
        string paper_width "Lebar kertas: 58mm/80mm"
        string encoding "Character encoding"
        boolean auto_cut "Auto cut paper"
        boolean beep_on_print "Beep saat print"
        boolean auto_reconnect "Auto reconnect"
        boolean print_logo "Print logo"
        string logo_url "URL logo"
        string header_text "Header struk"
        string footer_text "Footer struk"
        string font_size "Font: small/normal/large"
        datetime last_connected "Terakhir terhubung"
        number connection_count "Jumlah koneksi"
        boolean is_default "Printer default"
    }

    WarehouseLocation {
        string id PK
        string company_id FK "ID perusahaan"
        string location_name "Nama lokasi"
        string location_code "Kode unik lokasi"
        string location_type "Tipe lokasi"
        string description "Penjelasan lokasi"
        string address "Alamat"
        string city "Kota"
        string manager_name "Nama manajer"
        string manager_contact "Kontak manajer"
        number capacity "Kapasitas maksimal"
        number current_utilization "Utilisasi saat ini"
        boolean is_active "Status aktif"
        object coordinates "Koordinat GPS"
    }

    ShopSettings {
        string id PK
        string setting_key "Kunci pengaturan unik"
        string description "Penjelasan konfigurasi"
        string banner_image_url "URL banner toko"
        string banner_title "Judul banner"
        string banner_subtitle "Subtitle banner"
        array featured_categories "Kategori unggulan"
        object promo_banner "Banner promosi"
        object reseller_discounts "Diskon reseller per tier"
    }

    Subscription {
        string id PK
        string user_id FK "ID pemilik langganan"
        string company_id FK "ID perusahaan"
        string service_name "Nama layanan"
        number cost "Biaya per periode"
        string currency "Mata uang"
        string billing_cycle "Siklus penagihan"
        date next_due_date "Jatuh tempo berikutnya"
        date start_date "Tanggal mulai"
        date end_date "Tanggal akhir"
        string status "Status langganan"
        string payment_method "Metode pembayaran"
        boolean auto_renew "Perpanjang otomatis"
        string notes "Catatan"
    }

    PricingPlan {
        string id PK
        string planKey "Kunci unik paket"
        string name "Nama paket"
        string description "Deskripsi paket"
        number price "Harga bulanan"
        number yearlyPrice "Harga tahunan"
        array features "Daftar fitur"
        array limitations "Daftar batasan"
        string color "Kelas warna CSS"
        boolean popular "Paket populer"
        boolean isActive "Status aktif"
        number order "Urutan tampilan"
        number ai_credits_per_month "Kredit AI per bulan"
        number max_tasks "Maks tugas"
        number max_notes "Maks catatan"
        number max_workspaces "Maks workspace"
        number max_storage_mb "Maks storage MB"
        number max_team_members "Maks anggota tim"
        number max_companies "Maks perusahaan"
        number company_slots "Slot perusahaan"
        boolean allow_company_features "Izin fitur bisnis"
        object enabled_features "Fitur yang diaktifkan"
        object feature_prices "Harga per fitur"
        boolean is_custom_plan "Paket custom"
    }

    AddonPackage {
        string id PK
        string key "Kunci unik paket"
        string name "Nama paket"
        string description "Deskripsi paket"
        number requests "Jumlah permintaan AI"
        number price "Harga"
        boolean popular "Paket populer"
        boolean isActive "Status aktif"
        number order "Urutan tampilan"
    }

    AddonRequest {
        string id PK
        string user_id FK "ID pengguna"
        string user_email "Email pengguna"
        string user_full_name "Nama lengkap"
        string request_type "Jenis permintaan"
        string requested_package "Paket yang diminta"
        number price_paid "Harga dibayar"
        string proof_image_url "URL bukti bayar"
        string status "Status permintaan"
        string admin_notes "Catatan admin"
        string description "Keterangan pengguna"
        number balance_used "Saldo komisi terpakai"
    }
```

***

## Entity Schema Tables

### Company

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Ya | Nama perusahaan |
| `owner_id` | string | Ya | ID owner perusahaan |
| `owner_email` | string | Ya | Email owner |
| `owner_subscription_plan` | string | Tidak | Plan membership owner saat ini (free, pro, business, advanced, enterprise) |
| `description` | string | Tidak | Deskripsi perusahaan |
| `industry` | string | Tidak | Sektor industri perusahaan (retail, manufacturing, services, technology, food\_beverage, healthcare, education, other) |
| `address` | string | Tidak | Alamat legal perusahaan |
| `phone` | string | Tidak | Nomor telepon kantor |
| `email` | string | Tidak | Email resmi perusahaan |
| `website` | string | Tidak | URL website perusahaan |
| `logo_url` | string | Tidak | URL logo perusahaan |
| `tax_id` | string | Tidak | NPWP perusahaan |
| `employee_count` | number | Tidak | Jumlah karyawan (default: 0) |
| `metadata` | object | Tidak | Data tambahan / legacy |
| `landing_page_config` | object | Tidak | Konfigurasi landing page perusahaan (tema, konten, pembayaran, dll) |
| `business_type` | string | Tidak | Kategori bisnis yang dipilih saat onboarding |
| `active_modules` | string | Tidak | JSON string berisi array ID modul aktif |
| `settings` | object | Tidak | Pengaturan operasional perusahaan (jam kerja, kebijakan cuti, pajak, dll) |

### CompanyMember

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan tempat member terdaftar |
| `user_id` | string | Tidak | ID pengguna di sistem |
| `user_email` | string | Ya | Email pengguna yang menjadi member |
| `user_name` | string | Tidak | Nama lengkap pengguna |
| `role` | string | Tidak | Role dalam perusahaan (owner, admin, supervisor, store\_admin, stock\_admin, finance\_admin, hr\_admin, transaction\_admin, employee, production\_operator, qc\_inspector, sales\_marketing, partner\_distributor) |
| `employee_id` | string | Tidak | Link ke entitas Employee |
| `department` | string | Tidak | Departemen tempat member bekerja |
| `position` | string | Tidak | Jabatan atau posisi member |
| `status` | string | Tidak | Status keanggotaan (active, inactive, pending) |
| `joined_date` | date | Tidak | Tanggal bergabung dengan perusahaan |
| `invited_by` | string | Tidak | Email yang mengundang member ini |
| `permissions` | object | Tidak | Hak akses detail untuk member |
| `assigned_locations` | array | Tidak | Daftar ID lokasi gudang/outlet yang diizinkan untuk member (RBAC-01) |
| `working_hours` | object | Tidak | Jam kerja karyawan (start, end) |
| `salary` | number | Tidak | Gaji karyawan (opsional) |
| `notes` | string | Tidak | Catatan tambahan mengenai member |

### CompanyBackup

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan yang di-backup |
| `company_name` | string | Tidak | Nama perusahaan (snapshot saat backup) |
| `backup_type` | string | Tidak | Jenis backup: manual, auto\_reminder, atau scheduled |
| `backup_scope` | string | Tidak | Cakupan backup: full atau partial |
| `backup_date` | datetime | Ya | Tanggal dan waktu backup dilakukan |
| `created_by_email` | string | Ya | Email user yang membuat backup |
| `created_by_name` | string | Tidak | Nama user yang membuat backup |
| `data_summary` | object | Tidak | Ringkasan data yang di-backup (total members, tasks, notes, transactions, inventory, customers, employees, projects, assets, total\_size\_mb) |
| `file_url` | string | Tidak | URL file backup dalam format JSON |
| `file_size_mb` | number | Tidak | Ukuran file backup dalam megabyte |
| `notes` | string | Tidak | Catatan mengenai backup ini |
| `status` | string | Tidak | Status backup (completed, failed, processing) |
| `checksum` | string | Tidak | SHA-256 checksum dari file backup JSON (hex) — BKP-03 |
| `schema_version` | string | Tidak | Versi schema backup saat file dibuat untuk kompatibilitas restore — BKP-04 |
| `backup_version` | string | Tidak | Platform version string — BKP-04 |
| `error_log` | string | Tidak | Log error jika backup parsial atau gagal — BKP-03 |
| `restore_tested_at` | datetime | Tidak | Timestamp terakhir restore berhasil diverifikasi di environment terisolasi — BKP-04 |
| `restore_record_count` | number | Tidak | Jumlah record yang diverifikasi saat restore test — BKP-04 |
| `retention_days` | number | Tidak | Berapa hari backup ini disimpan sebelum boleh dihapus (default: 30) |
| `drive_file_id` | string | Tidak | ID file di Google Drive jika tersimpan di Drive — BKP-02 |
| `drive_integration_status` | string | Tidak | Status integrasi Google Drive (not\_configured, active, failed, disabled) |

### CompanyInvitation

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan yang mengirim undangan |
| `company_name` | string | Tidak | Nama perusahaan |
| `invited_email` | string | Ya | Email calon member yang diundang |
| `invited_by` | string | Ya | Email user yang mengirim undangan |
| `invited_by_name` | string | Tidak | Nama user yang mengirim undangan |
| `role` | string | Tidak | Role yang ditawarkan (owner, admin, supervisor, store\_admin, stock\_admin, finance\_admin, hr\_admin, transaction\_admin, employee) |
| `department` | string | Tidak | Departemen yang ditawarkan |
| `position` | string | Tidak | Jabatan yang ditawarkan |
| `description` | string | Tidak | Pesan atau keterangan tambahan yang disertakan dalam undangan |
| `permissions` | object | Tidak | Hak akses awal yang diberikan |
| `message` | string | Tidak | Pesan tambahan untuk calon member |
| `status` | string | Tidak | Status undangan (pending, accepted, rejected, expired, cancelled) |
| `expires_at` | datetime | Tidak | Waktu kadaluarsa undangan |
| `accepted_at` | datetime | Tidak | Waktu undangan diterima |
| `rejected_at` | datetime | Tidak | Waktu undangan ditolak |
| `cancelled_at` | datetime | Tidak | Waktu undangan dibatalkan |

### CompanyPOSSettings

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `description` | string | Tidak | Catatan mengenai konfigurasi sistem kasir (POS) yang digunakan perusahaan (max 1000 karakter) |
| `receipt_settings` | object | Tidak | Pengaturan struk POS (lihat sub-field di bawah) |
| `receipt_settings.logo_url` | string | Tidak | URL logo perusahaan untuk struk |
| `receipt_settings.business_name` | string | Tidak | Nama bisnis di struk |
| `receipt_settings.business_address` | string | Tidak | Alamat lengkap di struk |
| `receipt_settings.business_phone` | string | Tidak | Nomor telepon di struk |
| `receipt_settings.business_email` | string | Tidak | Email bisnis di struk |
| `receipt_settings.tax_id` | string | Tidak | NPWP/Tax ID di struk |
| `receipt_settings.receipt_width` | string | Tidak | Ukuran kertas struk: `58mm`, `80mm` (default: `80mm`) |
| `receipt_settings.show_logo` | boolean | Tidak | Tampilkan logo di struk (default: `true`) |
| `receipt_settings.show_tax_id` | boolean | Tidak | Tampilkan NPWP di struk (default: `false`) |
| `receipt_settings.show_cashier_name` | boolean | Tidak | Tampilkan nama kasir (default: `true`) |
| `receipt_settings.show_customer_info` | boolean | Tidak | Tampilkan info customer (default: `true`) |
| `receipt_settings.show_item_image` | boolean | Tidak | Tampilkan gambar item (default: `false`) |
| `receipt_settings.header_text` | string | Tidak | Header struk (default: `STRUK PEMBELIAN`) |
| `receipt_settings.footer_message` | string | Tidak | Footer struk |
| `receipt_settings.print_auto_after_transaction` | boolean | Tidak | Auto cetak setelah transaksi (default: `true`) |
| `receipt_settings.font_size` | string | Tidak | Font: `small`, `medium`, `large` (default: `medium`) |

### CompanyReceiptSettings

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `description` | string | Tidak | Catatan mengenai konfigurasi tampilan struk pembelian (max 1000 karakter) |
| `show_company_logo` | boolean | Tidak | Tampilkan logo perusahaan di struk (default: `true`) |
| `show_company_address` | boolean | Tidak | Tampilkan alamat perusahaan (default: `true`) |
| `show_customer_name` | boolean | Tidak | Tampilkan nama customer (default: `true`) |
| `show_customer_points` | boolean | Tidak | Tampilkan total poin customer saat ini (default: `true`) |
| `show_points_earned` | boolean | Tidak | Tampilkan poin yang didapat dari transaksi ini (default: `true`) |
| `show_payment_details` | boolean | Tidak | Tampilkan detail pembayaran (default: `true`) |
| `show_change` | boolean | Tidak | Tampilkan uang kembalian (default: `true`) |
| `custom_header_text` | string | Tidak | Teks custom di header struk |
| `custom_footer_text` | string | Tidak | Teks custom di footer struk (default: `Terima kasih sudah berbelanja!`) |
| `show_promo_message` | boolean | Tidak | Tampilkan pesan promo/marketing (default: `false`) |
| `promo_message` | string | Tidak | Isi pesan promo/marketing |

### CompanyAttendanceSettings

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `description` | string | Tidak | Penjelasan mengenai kebijakan absensi dan pengaturan jam kerja (max 1000 karakter) |
| `office_location` | object | Tidak | Lokasi kantor utama (latitude, longitude, address) |
| `office_radius_meters` | number | Tidak | Radius geofence kantor utama dalam meter (default: 100) |
| `require_office_location` | boolean | Tidak | Wajib absen dari lokasi kantor (default: `false`) |
| `default_accuracy_tolerance_meters` | number | Tidak | Toleransi akurasi GPS dalam meter (default: 150) |
| `locations` | array\[object] | Tidak | Daftar multi-lokasi geofence absensi |
| `working_hours` | object | Tidak | Jam kerja default (start\_time, end\_time, break\_duration\_minutes) |
| `shifts` | array\[object] | Tidak | Daftar shift kerja (shift\_id, shift\_name, start\_time, end\_time, break\_duration\_minutes) |
| `overtime_settings` | object | Tidak | Pengaturan lembur (enabled, start\_after\_hours, max\_overtime\_hours\_per\_day) |
| `late_tolerance_minutes` | number | Tidak | Toleransi terlambat dalam menit (default: 15) |
| `working_days` | array\[number] | Tidak | Hari kerja, 1=Senin 7=Minggu (default: `[1,2,3,4,5]`) |
| `auto_clock_out_enabled` | boolean | Tidak | Otomatis clock out jika lupa (default: `false`) |
| `auto_clock_out_time` | string | Tidak | Jam auto clock out (default: `18:00`) |
| `require_photo` | boolean | Tidak | Wajib foto selfie saat absen (default: `true`) |
| `require_notes` | boolean | Tidak | Wajib catatan saat absen (default: `false`) |

### CompanyModuleSettings

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `description` | string | Tidak | Catatan mengenai konfigurasi modul yang diaktifkan |
| `modules_enabled` | object | Tidak | Modul yang diaktifkan (manufacturing, inventory\_advanced, pos, crm, hr\_payroll, projects, assets, documents, email\_marketing, appointments, team\_chat) |
| `business_type` | string | Tidak | Tipe bisnis perusahaan (retail, manufacturing, services, digital\_products, food\_beverage, healthcare, education, consulting, hybrid) |
| `inventory_method` | string | Tidak | Metode penilaian persediaan (FIFO, LIFO, Average, Specific\_Identification) |
| `multi_warehouse_enabled` | boolean | Tidak | Fitur multi gudang diaktifkan (default: false) |
| `lot_tracking_enabled` | boolean | Tidak | Pelacakan lot diaktifkan (default: false) |
| `serial_tracking_enabled` | boolean | Tidak | Pelacakan serial number diaktifkan (default: false) |
| `barcode_enabled` | boolean | Tidak | Fitur barcode diaktifkan (default: false) |
| `auto_reorder_enabled` | boolean | Tidak | Auto reorder stok diaktifkan (default: false) |
| `production_planning_enabled` | boolean | Tidak | Production planning diaktifkan (default: false) |
| `quality_control_enabled` | boolean | Tidak | Quality control diaktifkan (default: false) |
| `attendance_integration` | boolean | Tidak | Integrasi otomatis absensi ke payroll (default: true) |
| `invoice_auto_create` | boolean | Tidak | Otomatis create invoice dari sales order (default: false) |
| `pos_inventory_sync` | boolean | Tidak | Sync otomatis POS ke inventory (default: true) |
| `finance_auto_record` | boolean | Tidak | Otomatis record transaksi ke finance (default: false) |
| `custom_fields` | array | Tidak | Custom fields per modul |
| `workflow_rules` | array | Tidak | Automation workflow rules |
| `notification_settings` | object | Tidak | Pengaturan notifikasi (low\_stock\_alert, order\_approval\_required, production\_complete, invoice\_overdue, leave\_approval) |

### CompanyWablasSettings

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `description` | string | Tidak | Catatan mengenai konfigurasi integrasi Wablas WhatsApp |
| `use_system_api` | boolean | Tidak | Gunakan API Wablas default sistem atau API sendiri (default: true) |
| `wablas_api_key` | string | Tidak | Wablas API Key sendiri (jika use\_system\_api = false) |
| `wablas_secret_key` | string | Tidak | Wablas Secret Key sendiri |
| `wablas_domain` | string | Tidak | Domain Wablas server (default: solo.wablas.com) |
| `is_active` | boolean | Tidak | Status integrasi aktif (default: true) |
| `auto_send_receipt` | boolean | Tidak | Otomatis kirim struk ke customer setelah transaksi (default: false) |
| `receipt_message_template` | string | Tidak | Template pesan struk WhatsApp |

### WarehouseLocation

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan pemilik lokasi |
| `location_name` | string | Ya | Nama lokasi (Gudang Utama, Toko Cabang A, dll) |
| `location_code` | string | Ya | Kode unik lokasi |
| `location_type` | string | Tidak | Tipe lokasi (warehouse, store, transit, virtual) |
| `description` | string | Tidak | Penjelasan mengenai lokasi gudang, kapasitas, dan jenis barang yang disimpan |
| `address` | string | Tidak | Alamat lengkap lokasi |
| `city` | string | Tidak | Kota lokasi |
| `manager_name` | string | Tidak | Nama manajer atau PIC lokasi |
| `manager_contact` | string | Tidak | Kontak manajer lokasi |
| `capacity` | number | Tidak | Kapasitas maksimal (unit atau m2) |
| `current_utilization` | number | Tidak | Utilisasi saat ini dalam persen (default: 0) |
| `is_active` | boolean | Tidak | Status lokasi aktif (default: true) |
| `coordinates` | object | Tidak | Koordinat GPS lokasi (latitude, longitude) |

### ShopSettings

| Field | Type | Required | Description |
| - | - | - | - |
| `setting_key` | string | Ya | Kunci pengaturan unik |
| `description` | string | Tidak | Penjelasan mengenai konfigurasi toko ini |
| `banner_image_url` | string | Tidak | URL banner toko |
| `banner_title` | string | Tidak | Judul banner toko |
| `banner_subtitle` | string | Tidak | Subtitle banner toko |
| `featured_categories` | array | Tidak | Kategori yang ditampilkan sebagai unggulan |
| `promo_banner` | object | Tidak | Banner promosi (active, title, description, discount\_percentage, valid\_until) |
| `reseller_discounts` | object | Tidak | Discount percentage untuk setiap tier membership (free: 0, pro: 0.05, business: 0.1, advanced: 0.15, enterprise: 0.2) |

### Subscription

| Field | Type | Required | Description |
| - | - | - | - |
| `user_id` | string | Ya | ID pengguna pemilik langganan |
| `company_id` | string | Tidak | ID perusahaan (null untuk personal) |
| `service_name` | string | Ya | Nama layanan/produk berlangganan |
| `cost` | number | Ya | Biaya langganan per periode |
| `currency` | string | Tidak | Mata uang (default: IDR) |
| `billing_cycle` | string | Tidak | Siklus penagihan (weekly, monthly, quarterly, yearly) |
| `next_due_date` | date | Ya | Tanggal jatuh tempo pembayaran berikutnya |
| `start_date` | date | Tidak | Tanggal mulai langganan |
| `end_date` | date | Tidak | Tanggal akhir langganan (jika ada) |
| `status` | string | Tidak | Status langganan (active, paused, cancelled) |
| `payment_method` | string | Tidak | Metode pembayaran yang digunakan |
| `auto_renew` | boolean | Tidak | Apakah otomatis diperpanjang (default: true) |
| `notes` | string | Tidak | Catatan tambahan mengenai langganan |

### PrinterSettings

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Tidak | ID perusahaan (null untuk personal) |
| `user_id` | string | Ya | ID user pemilik printer |
| `printer_name` | string | Tidak | Nama printer yang tersimpan |
| `description` | string | Tidak | Catatan mengenai konfigurasi printer thermal (max 1000 karakter) |
| `device_id` | string | Tidak | Bluetooth device ID |
| `device_name` | string | Tidak | Nama device dari Bluetooth |
| `paper_width` | string | Tidak | Lebar kertas thermal: `58mm`, `80mm` (default: `80mm`) |
| `encoding` | string | Tidak | Character encoding: `UTF-8`, `GB18030`, `Big5`, `Shift_JIS`, `EUC-KR` (default: `UTF-8`) |
| `auto_cut` | boolean | Tidak | Auto cut paper setelah print (default: `true`) |
| `beep_on_print` | boolean | Tidak | Beep sound saat print (default: `false`) |
| `auto_reconnect` | boolean | Tidak | Auto reconnect jika disconnect (default: `true`) |
| `print_logo` | boolean | Tidak | Print logo di struk (default: `true`) |
| `logo_url` | string | Tidak | URL logo untuk di-print |
| `header_text` | string | Tidak | Header struk (default: `STRUK PEMBELIAN`) |
| `footer_text` | string | Tidak | Footer struk (default: `Terima kasih atas kunjungan Anda`) |
| `font_size` | string | Tidak | Font: `small`, `normal`, `large` (default: `normal`) |
| `last_connected` | datetime | Tidak | Terakhir kali printer terhubung |
| `connection_count` | number | Tidak | Jumlah koneksi berhasil (default: 0) |
| `is_default` | boolean | Tidak | Printer default (default: `false`) |

### PricingPlan

| Field | Type | Required | Description |
| - | - | - | - |
| `planKey` | string | Ya | Kunci unik untuk paket (free, pro, business, custom, corporate) |
| `name` | string | Ya | Nama paket yang ditampilkan ke user |
| `description` | string | Tidak | Deskripsi paket |
| `price` | number | Ya | Harga bulanan |
| `yearlyPrice` | number | Ya | Harga tahunan |
| `features` | array | Tidak | Daftar fitur yang termasuk dalam paket |
| `limitations` | array | Tidak | Daftar batasan pada paket |
| `color` | string | Tidak | Gradient color CSS class (contoh: from-blue-600 to-indigo-600) |
| `popular` | boolean | Tidak | Ditandai sebagai paket populer (default: false) |
| `isActive` | boolean | Tidak | Status paket aktif ditampilkan (default: true) |
| `order` | number | Tidak | Urutan tampilan paket (default: 0) |
| `ai_credits_per_month` | number | Tidak | Jumlah kredit AI per bulan (default: 10) |
| `max_tasks` | number | Tidak | Maksimal tugas (0 = unlimited) |
| `max_notes` | number | Tidak | Maksimal catatan (0 = unlimited) |
| `max_workspaces` | number | Tidak | Maksimal workspace (0 = unlimited) |
| `max_storage_mb` | number | Tidak | Maksimal storage dalam MB (default: 100) |
| `max_team_members` | number | Tidak | Maksimal anggota tim per workspace (0 = unlimited) |
| `max_companies` | number | Tidak | Maksimal perusahaan (0 = tidak bisa buat company) |
| `company_slots` | number | Tidak | Jumlah slot company yang bisa dibuat |
| `allow_company_features` | boolean | Tidak | Apakah paket mengizinkan fitur bisnis/company (POS, HR, CRM, dll) |
| `enabled_features` | object | Tidak | Fitur-fitur yang diaktifkan untuk paket ini (pos, crm, hr\_payroll, attendance, inventory, invoices, projects, manufacturing, team\_chat, email\_marketing, whatsapp, analytics, goal\_tracking, documents, assets, appointments) |
| `feature_prices` | object | Tidak | Harga per fitur untuk paket Custom dalam Rupiah/bulan |
| `is_custom_plan` | boolean | Tidak | Apakah ini paket Custom yang bisa dipilih fitur per fitur (default: false) |

### AddonPackage

| Field | Type | Required | Description |
| - | - | - | - |
| `key` | string | Ya | Kunci unik untuk paket (contoh: 500\_requests) |
| `name` | string | Ya | Nama paket add-on |
| `description` | string | Tidak | Penjelasan detail mengenai paket add-on, manfaat, dan fitur yang disertakan |
| `requests` | number | Ya | Jumlah permintaan AI yang disertakan |
| `price` | number | Ya | Harga paket add-on |
| `popular` | boolean | Tidak | Ditandai sebagai paket populer (default: false) |
| `isActive` | boolean | Tidak | Status paket aktif ditampilkan (default: true) |
| `order` | number | Tidak | Urutan tampilan (default: 0) |

### AddonRequest

| Field | Type | Required | Description |
| - | - | - | - |
| `user_id` | string | Ya | ID pengguna yang mengajukan |
| `user_email` | string | Ya | Email pengguna |
| `user_full_name` | string | Tidak | Nama lengkap pengguna |
| `request_type` | string | Tidak | Jenis permintaan (ai\_quota) |
| `requested_package` | string | Ya | Paket add-on yang dibeli (contoh: 500\_requests) |
| `price_paid` | number | Ya | Harga yang dibayar |
| `proof_image_url` | string | Ya | URL bukti pembayaran |
| `status` | string | Tidak | Status permintaan (pending, approved, rejected) |
| `admin_notes` | string | Tidak | Catatan admin mengenai permintaan |
| `description` | string | Tidak | Keterangan atau alasan pembelian add-on dari pengguna |
| `balance_used` | number | Tidak | Jumlah saldo komisi yang digunakan (default: 0) |

***

## Status Lifecycle — CompanyInvitation

```mermaid theme={null}
stateDiagram-v2
    [*] --> pending: Undangan dibuat
    pending --> accepted: Undangan diterima oleh user
    pending --> rejected: Undangan ditolak oleh user
    pending --> expired: Melebihi batas waktu expires_at
    pending --> cancelled: Dibatalkan oleh admin/owner
    accepted --> [*]
    rejected --> [*]
    expired --> [*]
    cancelled --> [*]

    state pending {
        [*] --> MenungguRespon
        MenungguRespon --> EmailTerkirim
        EmailTerkirim --> MenungguRespon
    }
```

## Status Lifecycle — CompanyBackup

```mermaid theme={null}
stateDiagram-v2
    [*] --> processing: Backup dimulai
    processing --> completed: Backup berhasil selesai
    processing --> failed: Terjadi error saat backup
    completed --> [*]
    failed --> processing: Retry backup
    failed --> [*]

    state completed {
        [*] --> Tersimpan
        Tersimpan --> DriveSynced: Upload ke Google Drive
        DriveSynced --> Verified: Restore test berhasil
        Verified --> Retained: Dalam masa retensi
        Retained --> Expired: Melebiwi retention_days
        Expired --> [*]
    }
```

## Status Lifecycle — Subscription

```mermaid theme={null}
stateDiagram-v2
    [*] --> active: Langganan dimulai
    active --> paused: Langganan dijeda
    active --> cancelled: Langganan dibatalkan
    paused --> active: Langganan dilanjutkan
    cancelled --> active: Langganan diperbarui
    cancelled --> [*]

    state active {
        [*] --> PembayaranAktif
        PembayaranAktif --> MenungguJatuhTempo: Mendekati next_due_date
        MenungguJatuhTempo --> PembayaranAktif: auto_renew = true
        MenungguJatuhTempo --> PembayaranAktif
    }
```

## Status Lifecycle — Konfigurasi Settings

```mermaid theme={null}
stateDiagram-v2
    [*] --> BelumTerkonfigurasi: Perusahaan baru dibuat

    BelumTerkonfigurasi --> ProfilDiisi: Admin mengisi profil
    ProfilDiisi --> BrandingDiatur: Upload logo dan branding
    BrandingDiatur --> ModulDiaktifkan: Aktifkan modul
    ModulDiaktifkan --> IntegrasiTerhubung: Hubungkan integrasi
    IntegrasiTerhubung --> SiapProduksi: Verifikasi konfigurasi

    SiapProduksi --> Aktif: Konfigurasi aktif
    Aktif --> Aktif: Sinkronisasi perubahan
    Aktif --> Aktif: Broadcast ke semua client
    Aktif --> PerluUpdate: Ada perubahan di sistem
    PerluUpdate --> Aktif: Update diterapkan

    state Aktif {
        [*] --> Sinkron
        Sinkron --> Sinkron: Real-time sync
    }
```

## Status Lifecycle — Pengaturan Absensi

```mermaid theme={null}
stateDiagram-v2
    [*] --> AbsensiBelumDikonfigurasi: Perusahaan baru

    AbsensiBelumDikonfigurasi --> LokasiDidaftarkan: Daftarkan lokasi kantor
    LokasiDidaftarkan --> GeofenceDiaturn: Atur radius geofence
    GeofenceDiaturn --> JamKerjaDiaturn: Atur jam kerja
    JamKerjaDiaturn --> ShiftDibuat: Buat shift kerja
    ShiftDibuat --> LemburDiaturn: Konfigurasi lembur
    LemburDiaturn --> AbsensiAktif: Aktifkan absensi

    AbsensiAktif --> AbsensiAktif: Update lokasi
    AbsensiAktif --> AbsensiAktif: Ubah shift
    AbsensiAktif --> AbsensiNonaktif: Nonaktifkan
    AbsensiNonaktif --> AbsensiAktif: Aktifkan kembali
```

***

## Sequence Diagrams

### 1. Flow Update Pengaturan Perusahaan

```mermaid theme={null}
sequenceDiagram
    participant Admin as Admin/Owner
    participant UI as Company Settings UI
    participant API as Backend API
    participant DB as Database
    participant Cache as Cache Layer

    Admin->>UI: Buka tab Company Settings
    UI->>API: GET /api/company/:id
    API->>DB: Query Company + CompanyModuleSettings
    DB-->>API: Return data perusahaan
    API-->>UI: Return settings lengkap
    Admin->>UI: Ubah konfigurasi (profil, pajak, branding)
    UI->>UI: Validasi input client-side
    Admin->>UI: Klik "Simpan"
    UI->>API: PUT /api/company/:id/settings
    API->>API: Validasi permission (owner/admin only)
    API->>DB: UPDATE Company SET settings = ...
    DB-->>API: Update berhasil
    API->>Cache: Invalidate cache company settings
    API-->>UI: Return success + data terbaru
    UI-->>Admin: Tampilkan notifikasi "Pengaturan berhasil disimpan"
```

### 2. Flow Pembuatan Backup Perusahaan

```mermaid theme={null}
sequenceDiagram
    participant Admin as Admin/Owner
    participant UI as Backup UI
    participant API as Backend API
    participant Worker as Backup Worker
    participant Storage as File Storage
    participant Drive as Google Drive
    participant DB as Database

    Admin->>UI: Klik "Buat Backup"
    UI->>API: POST /api/company/:id/backup
    API->>DB: INSERT CompanyBackup (status: processing)
    DB-->>API: Return backup record
    API->>Worker: Trigger backup job (async)
    API-->>UI: Return "Backup sedang diproses"

    Worker->>DB: Query semua data perusahaan
    DB-->>Worker: Return data (members, tasks, inventory, dll)
    Worker->>Worker: Serialize data ke JSON
    Worker->>Worker: Hitung SHA-256 checksum
    Worker->>Storage: Upload file JSON backup
    Storage-->>Worker: Return file_url + file_size_mb

    alt drive_integration_status = active
        Worker->>Drive: Upload file ke Google Drive
        Drive-->>Worker: Return drive_file_id
    end

    Worker->>DB: UPDATE CompanyBackup SET status=completed, checksum, file_url, data_summary
    Worker-->>UI: WebSocket notification "Backup selesai"
    UI-->>Admin: Tampilkan notifikasi + link download
```

### 3. Flow Perubahan Paket Langganan

```mermaid theme={null}
sequenceDiagram
    participant Owner as Owner
    participant UI as Pricing Page
    participant API as Backend API
    participant PaymentGW as Payment Gateway
    participant DB as Database
    participant Notif as Notification Service

    Owner->>UI: Buka halaman Pricing
    UI->>API: GET /api/pricing-plans
    API->>DB: Query PricingPlan (isActive=true)
    DB-->>API: Return daftar paket
    API-->>UI: Return PricingPlans
    Owner->>UI: Pilih paket & klik "Upgrade"
    UI->>API: POST /api/subscription/upgrade
    API->>DB: Query Subscription + Company saat ini
    API->>API: Hitung proration (sisa hari periode lama)
    API-->>UI: Return jumlah pembayaran
    Owner->>UI: Konfirmasi & bayar
    UI->>PaymentGW: Process payment
    PaymentGW-->>UI: Payment success

    UI->>API: POST /api/subscription/confirm
    API->>DB: UPDATE Subscription SET status, cost, billing_cycle
    API->>DB: UPDATE Company SET owner_subscription_plan = new_plan
    API->>DB: UPDATE CompanyModuleSettings (enable new features based on plan)
    API->>Notif: Kirim email konfirmasi upgrade
    Notif-->>Owner: Email "Upgrade berhasil"
    API-->>UI: Return success
    UI-->>Owner: Redirect ke dashboard dengan fitur baru aktif
```

### 4. Flow Undangan Member Baru

```mermaid theme={null}
sequenceDiagram
    participant Admin as Admin/Owner
    participant UI as Member Management UI
    participant API as Backend API
    participant DB as Database
    participant Email as Email Service
    participant Invitee as Calon Member

    Admin->>UI: Klik "Undang Member"
    Admin->>UI: Isi email, role, department, permissions
    UI->>API: POST /api/company/:id/invitation
    API->>API: Validasi permission (can_manage_members)
    API->>DB: CHECK apakah email sudah menjadi member
    DB-->>API: Return hasil cek

    alt Email sudah terdaftar sebagai member
        API-->>UI: Return error "Email sudah menjadi member"
    else Email belum terdaftar
        API->>DB: INSERT CompanyInvitation (status: pending, expires_at: +7 hari)
        DB-->>API: Return invitation record
        API->>Email: Kirim undangan ke invited_email
        Email-->>Invitee: Email "Anda diundang bergabung ke [company_name]"
        API-->>UI: Return success "Undangan terkirim"
    end

    Invitee->>UI: Klik link undangan di email
    UI->>API: GET /api/invitation/:id
    API->>DB: Query CompanyInvitation

    alt status = pending DAN belum expired
        DB-->>API: Return valid invitation
        Invitee->>UI: Klik "Terima Undangan"
        UI->>API: POST /api/invitation/:id/accept
        API->>DB: UPDATE CompanyInvitation SET status=accepted, accepted_at=now()
        API->>DB: INSERT CompanyMember (dari data invitation)
        API->>Email: Notifikasi ke Admin "Member baru bergabung"
        API-->>UI: Return success
        UI-->>Invitee: Redirect ke dashboard perusahaan
    else status != pending atau sudah expired
        DB-->>API: Return invalid invitation
        API-->>UI: Return error "Undangan tidak valid atau sudah kadaluarsa"
    end
```

### 5. Flow Broadcast Perubahan Konfigurasi ke Semua Tab

```mermaid theme={null}
sequenceDiagram
    actor AdminA as Admin (Tab A)
    participant API as Backend API
    participant WS as WebSocket Server
    actor AdminB as Admin (Tab B)
    actor Kasir as Kasir (POS Tab)

    AdminA->>API: Update receipt settings
    API->>API: Validate & save to DB
    API->>WS: Emit "company_settings_updated"
    
    par Broadcast ke semua client
        WS-->>AdminB: Event: settings_updated {entity: "CompanyReceiptSettings"}
        AdminB->>AdminB: Auto-refresh receipt preview
    and
        WS-->>Kasir: Event: settings_updated {entity: "CompanyReceiptSettings"}
        Kasir->>Kasir: Reload receipt template
    end

    Note over AdminB, Kasir: Semua client menerima perubahan secara real-time
```

### 6. Flow Sinkronisasi Pengaturan POS ke Printer

```mermaid theme={null}
sequenceDiagram
    actor Admin
    participant UI as Settings UI
    participant API as Backend API
    participant DB as Database
    participant POS as POS Terminal
    participant Printer as Printer Thermal

    Admin->>UI: Atur receipt settings (logo, footer, width)
    UI->>API: PUT /api/company/pos-settings
    API->>DB: Save CompanyPOSSettings
    DB-->>API: Updated

    Admin->>UI: Pilih printer & test print
    UI->>API: POST /api/printer/test
    API->>POS: Forward print command
    POS->>Printer: Bluetooth ESC/POS command
    Printer-->>POS: Print result
    POS-->>API: Success/failure
    API-->>UI: Print result

    Note over POS, Printer: Printer menggunakan encoding dan paper_width dari PrinterSettings
```

### 7. Flow Absensi dengan Geofence Validation

```mermaid theme={null}
sequenceDiagram
    actor Employee as Karyawan
    participant App as Mobile App
    participant GPS as GPS Sensor
    participant API as Backend API
    participant DB as Database
    participant ATS as AttendanceSettings

    Employee->>App: Klik "Clock In"
    App->>GPS: Get current location
    GPS-->>App: latitude, longitude, accuracy

    App->>API: POST /api/attendance/clock-in {lat, lng, accuracy}
    API->>DB: Get CompanyAttendanceSettings
    DB-->>API: locations[], office_location, require_office_location

    alt require_office_location = true
        API->>API: Hitung jarak ke lokasi terdekat
        alt Dalam radius geofence
            API->>API: Cek akurasi GPS vs tolerance
            alt Akurasi dalam toleransi
                API->>DB: Save attendance record
                API-->>App: Clock-in berhasil
            else Akurasi di luar toleransi
                API-->>App: Error: Akurasi GPS terlalu rendah
            end
        else Di luar radius geofence
            API-->>App: Error: Di luar area kantor
        end
    else require_office_location = false
        API->>DB: Save attendance record
        API-->>App: Clock-in berhasil
    end
```

### 8. Flow Pengiriman Struk via WhatsApp

```mermaid theme={null}
sequenceDiagram
    actor Kasir
    participant POS as POS Terminal
    participant API as Backend API
    participant Wablas as Wablas API
    participant Customer as Customer (WhatsApp)

    Kasir->>POS: Proses transaksi
    POS->>API: POST /api/transactions {items, payment, customer}
    API->>API: Save transaction

    API->>API: Check CompanyWablasSettings
    alt auto_send_receipt = true
        API->>API: Render message dari template
        Note over API: Replace {company_name}, {transaction_id}, {date}, {total}
        API->>Wablas: POST /send-message {phone, message}
        Wablas-->>API: Message sent (message_id)
        API-->>POS: Transaction complete + receipt sent
    else auto_send_receipt = false
        API-->>POS: Transaction complete
    end

    POS-->>Customer: Struk cetak (jika print_auto = true)
    Wablas-->>Customer: Terima struk digital via WhatsApp
```

***

## Enum Reference Tables

### owner\_subscription\_plan (Company)

| Nilai | Deskripsi |
| - | - |
| `free` | Paket gratis dengan fitur dasar |
| `pro` | Paket profesional dengan fitur lanjutan |
| `business` | Paket bisnis untuk usaha menengah |
| `advanced` | Paket advanced dengan fitur lengkap |
| `enterprise` | Paket enterprise untuk organisasi besar |

### industry (Company)

| Nilai | Deskripsi |
| - | - |
| `retail` | Usaha ritel / penjualan langsung |
| `manufacturing` | Usaha manufaktur / produksi |
| `services` | Usaha jasa / layanan |
| `technology` | Usaha teknologi / software |
| `food_beverage` | Usaha makanan dan minuman |
| `healthcare` | Usaha kesehatan / medis |
| `education` | Usaha pendidikan / pelatihan |
| `other` | Sektor industri lainnya |

### role (CompanyMember / CompanyInvitation)

| Nilai | Deskripsi |
| - | - |
| `owner` | Pemilik perusahaan dengan akses penuh |
| `admin` | Administrator dengan akses hampir penuh |
| `supervisor` | Supervisor yang mengawasi operasional |
| `store_admin` | Admin toko / outlet |
| `stock_admin` | Admin gudang / stok |
| `finance_admin` | Admin keuangan |
| `hr_admin` | Admin HR / kepegawaian |
| `transaction_admin` | Admin transaksi |
| `employee` | Karyawan biasa |
| `production_operator` | Operator produksi |
| `qc_inspector` | Inspector quality control |
| `sales_marketing` | Tim sales dan marketing |
| `partner_distributor` | Partner / distributor |

### status (CompanyMember)

| Nilai | Deskripsi |
| - | - |
| `active` | Member aktif dan bisa mengakses sistem |
| `inactive` | Member non-aktif, akses ditangguhkan |
| `pending` | Member menunggu konfirmasi undangan |

### status (CompanyInvitation)

| Nilai | Deskripsi |
| - | - |
| `pending` | Undangan menunggu respon dari calon member |
| `accepted` | Undangan diterima, member sudah bergabung |
| `rejected` | Undangan ditolak oleh calon member |
| `expired` | Undangan kadaluarsa karena melebihi batas waktu |
| `cancelled` | Undangan dibatalkan oleh admin/owner |

### status (CompanyBackup)

| Nilai | Deskripsi |
| - | - |
| `completed` | Backup berhasil diselesaikan |
| `failed` | Backup gagal karena error |
| `processing` | Backup sedang dalam proses |

### backup\_type (CompanyBackup)

| Nilai | Deskripsi |
| - | - |
| `manual` | Backup dibuat manual oleh admin |
| `auto_reminder` | Backup otomatis berdasarkan pengingat |
| `scheduled` | Backup terjadwal sesuai konfigurasi |

### backup\_scope (CompanyBackup)

| Nilai | Deskripsi |
| - | - |
| `full` | Backup lengkap seluruh data perusahaan |
| `partial` | Backup sebagian data tertentu saja |

### drive\_integration\_status (CompanyBackup)

| Nilai | Deskripsi |
| - | - |
| `not_configured` | Integrasi Google Drive belum dikonfigurasi |
| `active` | Integrasi Google Drive aktif dan berfungsi |
| `failed` | Integrasi Google Drive gagal terhubung |
| `disabled` | Integrasi Google Drive dinonaktifkan |

### status (Subscription)

| Nilai | Deskripsi |
| - | - |
| `active` | Langganan aktif dan berjalan |
| `paused` | Langganan dijeda sementara |
| `cancelled` | Langganan dibatalkan |

### billing\_cycle (Subscription)

| Nilai | Deskripsi |
| - | - |
| `weekly` | Penagihan mingguan |
| `monthly` | Penagihan bulanan |
| `quarterly` | Penagihan per kuartal (3 bulan) |
| `yearly` | Penagihan tahunan |

### location\_type (WarehouseLocation)

| Nilai | Deskripsi |
| - | - |
| `warehouse` | Gudang penyimpanan barang |
| `store` | Toko / outlet penjualan |
| `transit` | Lokasi transit / perantara |
| `virtual` | Lokasi virtual (untuk stok digital) |

### business\_type (CompanyModuleSettings)

| Nilai | Deskripsi |
| - | - |
| `retail` | Usaha ritel / penjualan langsung |
| `manufacturing` | Usaha manufaktur / produksi |
| `services` | Usaha jasa / layanan |
| `digital_products` | Usaha produk digital |
| `food_beverage` | Usaha makanan dan minuman |
| `healthcare` | Usaha kesehatan / medis |
| `education` | Usaha pendidikan / pelatihan |
| `consulting` | Usaha konsultasi |
| `hybrid` | Usaha campuran beberapa sektor |

### inventory\_method (CompanyModuleSettings)

| Nilai | Deskripsi |
| - | - |
| `FIFO` | First In First Out — barang pertama masuk, pertama keluar |
| `LIFO` | Last In First Out — barang terakhir masuk, pertama keluar |
| `Average` | Rata-rata tertimbang dari harga pokok |
| `Specific_Identification` | Identifikasi spesifik per unit barang |

### request\_type (AddonRequest)

| Nilai | Deskripsi |
| - | - |
| `ai_quota` | Permintaan penambahan kuota AI |

### status (AddonRequest)

| Nilai | Deskripsi |
| - | - |
| `pending` | Permintaan menunggu verifikasi admin |
| `approved` | Permintaan disetujui dan kuota ditambahkan |
| `rejected` | Permintaan ditolak oleh admin |

### Tax Mode (Company.settings.tax.mode)

| Nilai | Deskripsi |
| - | - |
| `inclusive` | Pajak sudah termasuk dalam harga barang |
| `exclusive` | Pajak ditambahkan di luar harga barang |

### Tax Rounding (Company.settings.tax.rounding)

| Nilai | Deskripsi |
| - | - |
| `per_line` | Pembulatan pajak per baris item |
| `per_transaction` | Pembulatan pajak per total transaksi |

### Batch Allocation Strategy (Company.settings.batch\_allocation\_strategy)

| Nilai | Deskripsi |
| - | - |
| `fifo` | First In First Out — alokasi batch berdasarkan tanggal penerimaan |
| `fefo` | First Expiry First Out — alokasi batch berdasarkan tanggal kedaluwarsa terdekat |

### Spoilage Default Treatment (Company.settings.spoilage\_default\_treatment)

| Nilai | Deskripsi |
| - | - |
| `absorbed_normal` | Spoilage masuk HPP unit baik (biaya normal) |
| `expense_abnormal` | Spoilage dipisah sebagai beban periode (biaya abnormal) |

### enabled\_features (PricingPlan)

| Key | Deskripsi |
| - | - |
| `pos` | Modul Point of Sale |
| `crm` | Modul Customer Relationship Management |
| `hr_payroll` | Modul HR & Payroll |
| `attendance` | Modul Absensi Karyawan |
| `inventory` | Modul Inventaris / Persediaan |
| `invoices` | Modul Invoice / Faktur |
| `projects` | Modul Manajemen Proyek |
| `manufacturing` | Modul Manufaktur / Produksi |
| `team_chat` | Fitur Team Chat |
| `email_marketing` | Modul Email Marketing |
| `whatsapp` | Integrasi WhatsApp |
| `analytics` | Modul Analitik & Laporan |
| `goal_tracking` | Fitur Goal Tracking |
| `documents` | Modul Manajemen Dokumen |
| `assets` | Modul Manajemen Aset |
| `appointments` | Modul Appointment / Janji |

### receipt\_width (CompanyPOSSettings / PrinterSettings)

| Nilai | Deskripsi | Penggunaan |
| - | - | - |
| `58mm` | Kertas kecil 58mm | Printer portable, struk ringkas |
| `80mm` | Kertas standar 80mm | Printer kasir standar (default) |

### font\_size (CompanyPOSSettings / PrinterSettings)

| Nilai | Deskripsi |
| - | - |
| `small` | Font kecil, lebih banyak isi per struk |
| `medium` / `normal` | Font sedang (default) |
| `large` | Font besar, mudah dibaca |

### encoding (PrinterSettings)

| Nilai | Deskripsi | Penggunaan |
| - | - | - |
| `UTF-8` | Unicode standar | Default, mendukung semua karakter |
| `GB18030` | Chinese Simplified | Printer dengan karakter Cina |
| `Big5` | Chinese Traditional | Printer dengan karakter Cina tradisional |
| `Shift_JIS` | Japanese | Printer dengan karakter Jepang |
| `EUC-KR` | Korean | Printer dengan karakter Korea |

### working\_days (Company / CompanyAttendanceSettings)

| Nilai | Hari |
| - | - |
| 1 | Senin |
| 2 | Selasa |
| 3 | Rabu |
| 4 | Kamis |
| 5 | Jumat |
| 6 | Sabtu |
| 7 | Minggu |

***

## RBAC Permission Table

Hak akses detail pada entitas `CompanyMember.permissions`:

| Permission | Owner | Admin | Supervisor | Store Admin | Stock Admin | Finance Admin | HR Admin | Transaction 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` | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |

***

## Company Settings Object (Nested)

Field `settings` pada entitas `Company` berisi sub-konfigurasi berikut:

| Field | Type | Default | Description |
| - | - | - | - |
| `settings.working_hours_start` | string | `09:00` | Jam mulai kerja perusahaan |
| `settings.working_hours_end` | string | `17:00` | Jam akhir kerja perusahaan |
| `settings.working_days` | array\[number] | `[1,2,3,4,5]` | Hari kerja (1=Senin, 7=Minggu) |
| `settings.leave_policy` | object | — | Kebijakan cuti karyawan |
| `settings.expiry_thresholds` | object | — | Ambang batas peringatan kedaluwarsa lot |
| `settings.expiry_thresholds.critical` | number | `7` | Hari sebelum kedaluwarsa untuk level kritis |
| `settings.expiry_thresholds.warning` | number | `30` | Hari sebelum kedaluwarsa untuk level warning |
| `settings.expiry_thresholds.info` | number | `90` | Hari sebelum kedaluwarsa untuk level info |
| `settings.batch_allocation_strategy` | string | `fifo` | Strategi alokasi batch untuk produksi (fifo / fefo) |
| `settings.tax.enabled` | boolean | `false` | Apakah pajak diaktifkan |
| `settings.tax.rate` | number | `11` | Tarif PPN dalam persen |
| `settings.tax.mode` | string | `inclusive` | Mode pajak (inclusive / exclusive) |
| `settings.tax.rounding` | string | `per_transaction` | Pembulatan pajak (per\_line / per\_transaction) |
| `settings.spoilage_default_treatment` | string | `absorbed_normal` | Default perlakuan spoilage produksi |

## Notification Settings (CompanyModuleSettings)

| Field | Type | Default | Description |
| - | - | - | - |
| `notification_settings.low_stock_alert` | boolean | `true` | Notifikasi saat stok mendekati minimum |
| `notification_settings.order_approval_required` | boolean | `false` | Notifikasi saat order butuh persetujuan |
| `notification_settings.production_complete` | boolean | `true` | Notifikasi saat produksi selesai |
| `notification_settings.invoice_overdue` | boolean | `true` | Notifikasi saat invoice jatuh tempo |
| `notification_settings.leave_approval` | boolean | `true` | Notifikasi saat ada pengajuan cuti |


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