# 15. Checklist Fitur & Modul — Status Implementasi

Dokumen ini memetakan **seluruh fitur dan modul** dari blueprint & roadmap ke status implementasi: **Sudah Jadi**, **Sebagian**, atau **Belum**.

**Legenda:**
- ✅ **Sudah** — Implementasi selesai dan dipakai
- 🟡 **Sebagian** — Sebagian fitur ada, sisanya belum
- ⬜ **Belum** — Belum dikerjakan

---

## Posisi phase saat ini

| Phase | Status | Ringkas |
|-------|--------|--------|
| **Phase 1** | ✅ Selesai | Foundation: login, outlet, menu, POS, order, report |
| **Phase 2** | ✅ Selesai | Operational: KDS, inventory, promo (voucher + Buy X Get Y + jadwal tanggal), customer, delivery, loyalty. |
| **Phase 3** | ✅ Selesai (fondasi) | API doc + OpenAPI (termasuk Reports), rate limit, cache menu, queue report, consolidated, feature toggle, plan + limit fitur, API key + UI, billing dasar, **notifikasi in-app** (bell, stok rendah, order). **Gateway pembayaran Midtrans (QRIS) sudah aktif.** |
| **Phase 4** | ⬜ Belum | Enterprise & AI (roadmap 12+ bulan) |

**Jawaban singkat:** Sampai **Phase 3** (Scale & SaaS). Phase 1 & 2 selesai; Phase 3 fondasi selesai termasuk billing dasar dan **integrasi Midtrans (QRIS)** untuk pembayaran online di POS.

### Pemeriksaan Phase 1 & 2 — item yang belum / opsional

| Modul | Item | Status | Catatan |
|-------|------|--------|--------|
| **Phase 1** | Semua exit criteria | ✅ | Login → buka shift → order → bayar → tutup shift → laporan: sudah jalan. Item ⬜ di Modul 3 (harga dinamis, Event ProductUpdated) dan Modul 4 (QR Order, split/merge) sengaja **Phase lanjut**, bukan syarat Phase 1. |
| **Phase 2 — Promo** | PromotionRule (buy X get Y) | ✅ | Sudah: aturan promo Buy X Get Y, item gratis otomatis di cart; CRUD Aturan Promo. |
| **Phase 2 — Promo** | Scheduler promo | 🟡 | Valid dari/sampai (tanggal) sudah di Voucher & PromotionRule; jadwal per jam (happy hour) opsional Phase lanjut. |
| **Phase 2 — POS** | CashDrawer (entitas terpisah) | ✅ | Cash In/Out transaction di `pos_sessions` & `transactions` (type: cash_in/out). |
| **Phase 2+ / lanjut** | Offline-first, Gateway EDC, Settlement/Refund, dll | ⬜ | Sengaja di luar exit criteria Phase 2. |

**Kesimpulan:** Phase 1 **selesai**. Phase 2 **selesai**: PromotionRule Buy X Get Y dan scheduler (valid_from/valid_until) sudah; CashDrawer tabel terpisah opsional. (Exit criteria: KDS, stok, promo, pelanggan, delivery.)
---

## 1. Ringkasan per Phase

| Phase | Target | Status | Keterangan |
|-------|--------|--------|------------|
| **Phase 1** | Foundation (bisa jual & operasional dasar) | ✅ Sudah | Login → Outlet → Menu → POS → Order → Report |
| **Phase 2** | Operational power (KDS, Inventory, Promo, Customer, Delivery) | ✅ Sudah | Customer + KDS + Inventory + Promo (Voucher) + Delivery + Loyalty (points & tier dasar) |
| **Phase 3** | Scale & SaaS (multi-outlet kuat, API public, billing) | ✅ Selesai | Prioritas 1–7 + API key + UI + limits + billing & subscription management (Starter/Pro/Enterprise) + Midtrans QRIS + User Mgmt + Settings. |
| **Phase 4** | Enterprise & AI (microservice, AI, franchise, marketplace) | ⬜ Belum | Roadmap 12+ bulan |

---

## 2. Checklist per Modul (Blueprint)

### 🔹 Modul 1: Auth & User

| Item | Status | Catatan |
|------|--------|--------|
| Login (email/password, session) | ✅ Sudah | `modules/Auth`, `LoginController`, route `login` |
| Logout | ✅ Sudah | `POST /logout` |
| Tabel `users`, `roles`, `permissions`, `user_outlets` | ✅ Sudah | Migrasi + seeder |
| Role & Permission (RBAC) | ✅ Sudah | `User::hasPermission()`, middleware `permission` |
| Multi-outlet access (user ↔ outlet) | ✅ Sudah | `User::outlets()`, `defaultOutlet()` |
| Redirect role-based setelah login | ✅ Sudah | Kasir → POS (outlet default); selain itu → dashboard; intended URL dihormati |
| API: GET /me, GET /permissions, GET /outlets | ✅ Sudah | GET /api/me, /api/permissions, /api/outlets (auth session, JSON) |
| CRUD User (User Management) | ✅ Sudah | UserController, users/*; UserPolicy; permission user.manage; sidebar "Manajemen User"; cegah hapus diri sendiri |
| Event: UserLoggedIn, OrderCreated, OrderPaid, POSSessionOpened, PaymentCompleted | ✅ Sudah | Event + listener (log); dispatch di login, createOrder, addPayment (saat lunas), openSession, addPayment (tiap bayar) |
| SSO / forgot password | ✅ Sudah | Lupa kata sandi: GET/POST password/forgot, GET/POST password/reset (ForgotPasswordController, ResetPasswordController); link dari halaman login; view forgot-password & reset-password; token via email (Laravel Password::sendResetLink) |

---

### 🔹 Modul 2: Outlet & Branch

| Item | Status | Catatan |
|------|--------|--------|
| CRUD Outlet (nama, kode, alamat, telepon) | ✅ Sudah | `OutletController`, view outlets/*; OutletPolicy + filter index by user outlet |
| Timezone & currency per outlet | ✅ Sudah | Kolom `timezone`, `currency` |
| Pajak & service charge (%) | ✅ Sudah | Kolom `tax_percent`, `service_charge_percent` |
| Jam operasional | ✅ Sudah | Tabel `outlet_opening_hours` (day_of_week, open_time, close_time); form di outlet edit (Senin–Minggu); OutletController simpan jam |
| Printer & device mapping (OutletDevice) | ✅ Sudah | Tabel `outlet_devices` (type: printer/kds/display, name, config JSON); CRUD OutletDeviceController; filter outlet & tipe; permission outlet.manage |
| OutletSetting (key-value) | ✅ Sudah | Tabel `outlet_settings` (outlet_id, key, value); model OutletSetting; Outlet::getSetting($key), Outlet::setSetting($key, $value); relasi Outlet::settings() |
| Tempat / lantai per outlet (OutletFloor) | ✅ Sudah | Tabel `outlet_floors` (outlet_id, name, sort_order, floor_plan_width/height); satu outlet bisa banyak tempat (Teras, Lantai 1, Lantai 2); CRUD via OutletFloorController; ensureFloors() buat "Utama" jika belum ada |
| Peta meja (OutletTable) | ✅ Sudah | Tabel `outlet_tables` (outlet_id, outlet_floor_id, name, shape, x, y, w, h, grid_row/col, capacity); CRUD + pengaturan grid; sidebar Peta Meja (outlet.manage) |
| Editor tata letak (drag-drop, bentuk meja) | ✅ Sudah | Layout editor: canvas floor plan, drag & drop meja, resize handle, bentuk rectangle/circle/ellipse; tambah meja via AJAX; double-click rename; simpan tata letak; ukuran canvas per tempat |

---

### 🔹 Modul 3: Menu & Product

| Item | Status | Catatan |
|------|--------|--------|
| CRUD Category (per outlet) | ✅ Sudah | `CategoryController`, menu/categories/*; CategoryPolicy + filter by user outlet |
| CRUD Product (per kategori, outlet) | ✅ Sudah | `ProductController`, menu/products/*; ProductPolicy + filter by user outlet |
| Harga dasar & is_available | ✅ Sudah | Kolom `price`, `is_available` |
| Tabel & model Modifier + UI CRUD (per produk) | ✅ Sudah | ModifierController, section modifier di menu/products/edit |
| Recipe mapping (Product ↔ Ingredient) | ✅ Sudah | Tabel `recipes` (product_id, ingredient_id, quantity); model Recipe; section Resep di edit produk (pilih bahan + qty per porsi) |
| Harga dinamis / schedule price | ⬜ Belum | Phase lanjut |
| Event ProductUpdated (cache) | ✅ Sudah | Event ProductUpdated dispatch di ProductController (store/update/destroy); listener InvalidateMenuCacheOnProductUpdate invalidasi cache menu outlet. |
| API: list by outlet, price list | ✅ Sudah | GET /api/categories?outlet_id=, GET /api/products?outlet_id= (category_id, available_only); Api\MenuController; permission menu.manage |

---

### 🔹 Modul 4: Order (CORE)

| Item | Status | Catatan |
|------|--------|--------|
| Create order (dine-in / takeaway / delivery) | ✅ Sudah | `OrderService::createOrder()`, POS form; delivery: alamat, HP, ongkir (manual), delivery_status (preparing → on_the_way → delivered) |
| Order number unik per outlet/hari | ✅ Sudah | `OrderService::generateOrderNumber()` |
| OrderItem (product, qty, unit_price, total, modifiers JSON) | ✅ Sudah | `OrderService::addItem()`, tabel `order_items` |
| Lifecycle: created → confirmed → cooking → ready → completed | ✅ Sudah | Konstanta + status log; update status dari UI (orders/show) |
| Subtotal, tax, service charge, discount, poin, ongkir, total (auto) | ✅ Sudah | `OrderService::recalculateOrder()` (termasuk shipping_cost, points_discount_amount) |
| OrderPayment (method, amount, paid_at) | ✅ Sudah | `OrderService::addPayment()`, tabel `order_payments` |
| OrderStatusLog | ✅ Sudah | Tabel + `OrderService::logStatus()` |
| List order (filter outlet, status, date) | ✅ Sudah | `OrderController::index`, orders/index |
| Detail order | ✅ Sudah | `OrderController::show`, orders/show |
| Soft delete order | ✅ Sudah | Model `Order` SoftDeletes |
| QR Order (customer scan & order) | ✅ Sudah | Publik tanpa login: GET /qr-order/{outletCode}/{tableName?} → tampil menu + form order; POST submit → order dibuat; halaman sukses + nomor order; QR code per meja di Peta Meja (Google Charts QR API). |
| Split & merge order | 🟡 Sebagian | Backend service & controller sudah (`OrderActionController`, `OrderService::splitOrder/mergeOrders`); UI belum. |
| API: list, create, show, update status (JSON) | ✅ Sudah | GET/POST /api/orders (index, store, show, update-status); auth session; doc: 16-API-ORDER-REFERENCE.md |
| Event: OrderCreated, OrderPaid (listener log) | ✅ Sudah | OrderCreated, OrderPaid; UserLoggedIn di Auth |
| Status CANCELLED (flow + UI) | ✅ Sudah | Tombol Batalkan di orders/show |
| Status REFUNDED (flow + UI) | ✅ Sudah | Dari completed → Refund; tombol Refund di orders/show; API update-status terima refunded |

---

### 🔹 Modul 5: POS

| Item | Status | Catatan |
|------|--------|--------|
| Buka shift (opening cash) | ✅ Sudah | `POSController::openSession`, form di pos/index |
| Tutup shift (closing cash) | ✅ Sudah | `POSController::closeSession` |
| POSSession, PaymentMethod, Transaction (tabel) | ✅ Sudah | Migrasi + model |
| Link order ke session (pos_session_id) | ✅ Sudah | Saat create order |
| Payment method per outlet (cash, transfer) | ✅ Sudah | Seeder + `PaymentMethod` |
| Split payment (bayar bertahap) | ✅ Sudah | Beberapa kali `addPayment` sampai lunas |
| UI POS: grid produk, cart, bayar + pilih modifier | ✅ Sudah | pos/index: produk dengan modifier buka modal add-on; keranjang & struk tampilkan nama modifier |
| Peta meja di POS (per tempat) | ✅ Sudah | Pilih tempat (Teras/Lantai 1/dll); peta meja floor plan atau grid per tempat; klik meja untuk order baru atau buka order aktif; link preserve floor_id |
| POS: bar info (shift, pendapatan hari ini, order hari ini) | ✅ Sudah | Bar info di pos/index: shift dibuka, pendapatan hari ini, order hari ini, pilih outlet, tutup shift |
| Receipt / print | ✅ Sudah | orders/receipt.blade.php, tombol Cetak Struk di orders/show, @media print |
| Offline-first / sync | ⬜ Belum | Phase 2+ |
| CashDrawer (entitas terpisah) | ✅ Sudah | Implemented: input Cash In/Out di POS, masuk tabel `transactions` linked ke session. |
| Event: POSSessionOpened, PaymentCompleted | ✅ Sudah | POSSessionOpened saat buka shift; PaymentCompleted tiap addPayment; listener Log* menulis ke Log |

---

### 🔹 Modul 6: Kitchen (KDS)

| Item | Status | Catatan |
|------|--------|--------|
| KitchenStation, KitchenOrder, CookingLog | ✅ Sudah | Migrasi + model; Product.kitchen_station_id (opsional); seeder station "Dapur Utama" |
| Display order by station, timer, status | ✅ Sudah | GET /kitchen?station_id=; kartu order dengan timer (elapsed); filter pending/cooking |
| UI Kitchen Display (fullscreen/touch) | ✅ Sudah | kitchen/index: pilih station, kartu order, tombol Mulai Masak / Siap / Re-fire |
| Re-fire order | ✅ Sudah | KitchenService::refire; POST kitchen/orders/{id}/refire |
| Kirim order ke dapur saat konfirmasi | ✅ Sudah | OrderService::updateStatus(CONFIRMED) → KitchenService::sendOrderToKitchen |

---

### 🔹 Modul 7: Inventory

| Item | Status | Catatan |
|------|--------|--------|
| Ingredient, Stock, StockMovement | ✅ Sudah | Migrasi ingredients, stocks, stock_movements; model + StockService; CRUD bahan, filter outlet & stok minimum |
| Supplier, PurchaseOrder | ✅ Sudah | Tabel suppliers (outlet, name, phone, email, address); purchase_orders (outlet, supplier, po_number, status draft/ordered/received/cancelled); purchase_order_items (ingredient, quantity, unit_price, received_quantity); CRUD Supplier & PO; Terima PO → StockService addMovement (ref_type purchase_order); sidebar Supplier & Purchase Order; permission inventory.manage |
| Auto deduction dari recipe | ✅ Sudah | Saat order status → completed (dari lunas di POS atau ubah status di UI): StockService::deductForOrder (agregat per ingredient dari recipe × qty item); ref_type order, ref_id order.id; kolom orders.inventory_deducted_at agar tidak dobel; LoyaltyService onOrderCompleted tetap idempotent |
| Alert stok minimum, UI stok | ✅ Sudah | Filter "Stok minimum", badge "Stok rendah", halaman detail + form masuk/keluar/koreksi/waste |

---

### 🔹 Modul 8: Customer & Loyalty

| Item | Status | Catatan |
|------|--------|--------|
| Customer (nama, phone, email) | ✅ Sudah | Phase 2: tabel `customers`, model Customer, CRUD + CustomerPolicy, sidebar Pelanggan (permission customer.manage); OrderService createOrder terima customer_id |
| LoyaltyPoint, LoyaltyTier | ✅ Sudah | customers.points_balance; loyalty_tiers (outlet, name, min_points); loyalty_point_logs (earn/redeem/adjust); earn saat order completed, redeem di POS; CRUD Tier (loyalty-tiers.*); assign tier di edit pelanggan |
| Riwayat transaksi per customer | ✅ Sudah | Halaman Pelanggan (show): detail + daftar order dengan filter status; link ke orders.show |
| CustomerFeedback | ✅ Sudah | Tabel customer_feedbacks (customer_id, order_id nullable, rating 1–5, comment); model CustomerFeedback; form di order show (setelah selesai, ada pelanggan) & di customer show; POST feedback.store; authorize via CustomerPolicy::view |

---

### 🔹 Modul 9: Promotion

| Item | Status | Catatan |
|------|--------|--------|
| Voucher (kode, nominal/percent, valid date) | ✅ Sudah | Tabel vouchers; CRUD VoucherController; min_order, valid_from/until, max_use; permission promo.manage |
| PromotionRule (min order, buy X get Y) | ✅ Sudah | Tabel promotion_rules (buy_product_id, buy_quantity, get_product_id, get_quantity, valid_from/until); PromotionRuleService::applyToOrder; item gratis ditambah otomatis di cart; CRUD Aturan Promo (promotion-rules.*); feature promo_rules |
| Apply voucher di order | ✅ Sudah | VoucherService::applyToOrder; POS form kode voucher + Hapus voucher; order.discount_amount, total = subtotal+tax+service-discount |
| Scheduler promo | 🟡 Sebagian | Valid dari/sampai (valid_from, valid_until) sudah di Voucher & PromotionRule = jadwal tanggal. Jadwal per jam (happy hour) belum — Phase lanjut jika perlu. |

---

### 🔹 Modul 10: Payment

| Item | Status | Catatan |
|------|--------|--------|
| Payment per order (method, amount, log) | ✅ Sudah | OrderPayment, OrderService::addPayment |
| Payment method master (outlet) | ✅ Sudah | PaymentMethod, seeder |
| Gateway Midtrans (QRIS / Snap) | ✅ Sudah | MidtransService + MidtransController; Snap popup di POS; webhook callback otomatis; feature toggle `midtrans` per outlet; docs: 18-PAYMENT-GATEWAY-INTEGRATION.md |
| Gateway lain (EDC, Xendit, DOKU) | ⬜ Belum | Arsitektur sudah modular, tinggal tambah service baru |
| Settlement, Refund (entitas + flow) | ⬜ Belum | Phase lanjut |
| Payment log / audit | ✅ Sudah | Riwayat Pembayaran: GET reports/payments (filter outlet, date_from, date_to); daftar order_payments dengan order, outlet, metode, jumlah; permission report.view |

---

### 🔹 Modul 11: Report & Analytics

| Item | Status | Catatan |
|------|--------|--------|
| Sales summary (per hari/outlet) | ✅ Sudah | `ReportController::sales`, reports/sales; cek permission report.view |
| Filter date, outlet | ✅ Sudah | Form filter di view |
| Export CSV | ✅ Sudah | Query param `export=csv` |
| Profit & margin, cost summary | ✅ Selesai | Laporan Pembelian (nilai PO diterima per periode, filter outlet & tanggal, export CSV); profit/margin penuh butuh COGS per penjualan (Phase lanjut) |
| Staff performance, perbandingan outlet | ✅ Sudah | Laporan Performa Staf: reports/staff — penjualan per user (order completed dengan pos_session); group by user & outlet; filter tanggal & outlet; export CSV; hanya order yang punya pos_session (kasir) |
| ReportSnapshot (materialized) | ⬜ Belum | Phase lanjut |
| API report (JSON) | ✅ Sudah | GET /api/reports/sales, GET /api/reports/consolidated (query: date_from, date_to, outlet_id untuk sales); auth API key + permission report.view |

---

### 🔹 Modul 12: System & Config

| Item | Status | Catatan |
|------|--------|--------|
| Global config (SystemConfig) | ✅ Sudah | Tabel `site_settings` & Model `SiteSetting`; controller `SaaSSettingController`. |
| Audit log | ✅ Sudah | Tercover oleh ActivityLog (login, order actions, sensitive data changes). |
| Activity log | ✅ Sudah | Tabel activity_logs (user_id, action, subject_type, subject_id, description, properties); model ActivityLog::log(); log di order.created, order.completed, po.received, user.login; halaman Log Aktivitas (filter aksi & tanggal); permission report.view; ActivityLogPolicy |
| Feature toggle | ✅ Sudah | config/features.php (global default); App\Services\Feature::enabled($key, $outlet) dengan override per outlet (outlet_settings key feature_*); dipakai di POS (loyalty, voucher, delivery) |
| Notifikasi in-app | ✅ Sudah | Tabel notifications (user_id, type, title, body, url, read_at); model Notification::send/sendToMany; bell icon di header (dropdown 8 terbaru, badge unread, polling 60 dtk); halaman /notifications; tandai dibaca per notif / semua; trigger: OrderCreated (semua user outlet), OrderPaid (admin outlet), stok rendah (user outlet); type: order, stock, billing, system |
| Paket / plan (subscription dasar) | ✅ Sudah | Tabel `plans`, `outlets.plan_id`; PlanSeeder Starter/Pro/Enterprise; assign plan di edit outlet. **Limit fitur per plan:** config/features.php plan_limits; Feature::enabled() cek plan. **Billing dasar:** tabel `subscription_invoices`; buat invoice (outlet, periode, jumlah), daftar filter outlet/status, detail + tandai lunas; permission billing.manage; sidebar Billing / Langganan. Gateway pembayaran (Stripe/Midtrans) Phase lanjut. |

---

## 3. Checklist per Milestone (Roadmap Phase 1)

### Milestone 1.1 – Setup & Auth

| Deliverable | Status | Implementasi |
|-------------|--------|--------------|
| Struktur modul (folder modules/, autoload) | ✅ | `composer.json` PSR-4 Modules, `modules/Auth/Routes/web.php` |
| Auth & User (login, session, tabel) | ✅ | Migrasi roles, permissions, user_outlets; LoginController; seeder admin |
| RBAC (middleware, policy outlet) | ✅ | Middleware `permission`, `guest`; User::hasPermission() |
| Landing & Login UI | ✅ | welcome.blade.php, auth/login.blade.php (design system) |

### Milestone 1.2 – Outlet & Menu

| Deliverable | Status | Implementasi |
|-------------|--------|--------------|
| Outlet CRUD | ✅ | OutletController, outlets/index|create|edit |
| Menu: Category CRUD | ✅ | CategoryController, menu/categories/* |
| Menu: Product CRUD | ✅ | ProductController, menu/products/* |
| Menu: Modifier (tabel + model + UI CRUD) | ✅ | ModifierController, section modifier di edit produk |
| Harga & is_available | ✅ | Kolom product, form create/edit |
| UI Admin (list + form) | ✅ | Semua CRUD dengan tabel + form, design system |

### Milestone 1.3 – Order & POS

| Deliverable | Status | Implementasi |
|-------------|--------|--------------|
| Order lifecycle (create, item, status) | ✅ | OrderService, Order model, status log |
| POS session (open/close shift) | ✅ | POSSession, openSession, closeSession |
| Payment (cash + transfer, log) | ✅ | OrderPayment, PaymentMethod, addPayment |
| API Order (create, list, update status) | ✅ | GET/POST /api/orders, show, update-status; doc 16-API-ORDER-REFERENCE.md |
| UI POS (grid, cart, payment) | ✅ | pos/index: kategori, produk, keranjang, form bayar; produk dengan modifier buka modal pilih add-on |
| Update status order dari UI | ✅ | orders/show: tombol Konfirmasi/Mulai Masak/Siap Saji/Selesai/Batalkan → POST orders/{id}/status |
| Receipt / print | ✅ | orders/receipt, Cetak Struk, window.print + @media print |

### Milestone 1.4 – Basic Report

| Deliverable | Status | Implementasi |
|-------------|--------|--------------|
| Sales summary (per hari/outlet) | ✅ | ReportController::sales, join orders+outlets |
| Export CSV | ✅ | exportSalesCsv(), link Export CSV |
| UI Report (filter date & outlet) | ✅ | reports/sales.blade.php |

---

## 4. Fitur UI/UX (Design System)

| Item | Status | Catatan |
|------|--------|--------|
| Design tokens (warna, radius, shadow) | ✅ Sudah | resources/css/app.css @theme |
| Layout App (sidebar + top bar) | ✅ Sudah | layouts/app.blade.php |
| Layout Guest (login) | ✅ Sudah | layouts/guest.blade.php |
| Landing page | ✅ Sudah | welcome.blade.php |
| Dashboard (ringkasan + quick action) | ✅ Sudah | dashboard.blade.php, data real; layout per role (kasir: fokus POS + 3 kartu; admin: 4 kartu + grafik penjualan 7 hari [Chart.js bar+line] + link Peta Meja) |
| Tabel (header, row, hover, pagination) | ✅ Sudah | Di outlets, categories, products, orders, reports |
| Form (input, select, validasi inline) | ✅ Sudah | Semua create/edit |
| Button primary/secondary | ✅ Sudah | Konsisten di seluruh halaman |
| Sidebar navigasi (aktif state + by permission) | ✅ Sudah | + inventory.manage (Stok) |
| Responsive (breakpoint) | ✅ Sudah | Grid & flex; sidebar fixed; drawer mobile: tombol hamburger di header (< lg), overlay, klik link/overlay tutup drawer; main content full width di mobile |
| Dark mode | ✅ Done | Variabel CSS `[data-theme="dark"]` di `resources/css/app.css`, toggle di header layout app, inisialisasi + simpan preferensi di localStorage, ikuti `prefers-color-scheme` bila belum ada pilihan. |

---

## 5. Infrastruktur & Kualitas

| Item | Status | Catatan |
|------|--------|--------|
| Migrasi (Phase 1 + Phase 2) | ✅ Sudah | orders, customers, kitchen, ingredients, stocks, stock_movements, vouchers+discount, delivery fields, loyalty (tiers, point_logs, columns), outlet_opening_hours, recipes, outlet_devices, outlet_settings, orders.inventory_deducted_at, customer_feedbacks, suppliers, purchase_orders, purchase_order_items, activity_logs |
| Seeder (role, permission, admin, outlet, payment method) | ✅ Sudah | RolePermissionSeeder |
| Policy untuk aksi sensitif | ✅ Sudah | OrderPolicy, OutletPolicy, OutletDevicePolicy, CategoryPolicy, ProductPolicy, ModifierPolicy, CustomerPolicy, CustomerPolicy (view), KitchenOrderPolicy, IngredientPolicy, VoucherPolicy, LoyaltyTierPolicy; route middleware (customer.manage, kds.view, inventory.manage, promo.manage, outlet.manage, dll) |
| Feature test / unit test | ✅ Sudah | Feature: LoginTest (5), OrderTest (4), ReportTest (3), OutletTest (4), POSTest (4), DashboardTest (3), ApiOrderTest (5), CustomerTest (4). Unit: OrderServiceTest (5) |
| API documentation (OpenAPI/Postman) | ✅ Sudah | OpenAPI 3 spec `docs/openapi.yaml`; Swagger UI di GET /api-docs; spec mencakup Auth, Menu, Orders |
| Rate limit API | ✅ Sudah | 60 req/menit per user (atau IP); middleware throttle:api; response 429 + Retry-After |
| API key (auth Bearer) | ✅ Sudah | Tabel api_clients; middleware AuthenticateApiKey; artisan api-key:create; **UI:** menu API Key (list, buat, revoke), key ditampilkan sekali setelah buat |
| Cache menu (API) | ✅ Sudah | MenuCache 5 menit per outlet; GET /api/categories & /api/products pakai cache; invalidate saat CRUD Category/Product (MenuCache::clearForOutlet) |
| Queue / cache (Redis) | 🟡 Sebagian | Export laporan via queue (ExportReportJob, report_exports); job jalan dengan `php artisan queue:work`; sync driver tetap bisa (job jalan di request) |
| Queue report berat (export CSV) | ✅ Sudah | POST reports/queue-export (type, date_from, date_to, outlet_id); job ExportReportJob; GET reports/exports & reports/exports/{id}/download |

---

## 6. Rute & Halaman (Referensi Cepat)

| Rute | Halaman / Aksi | Status |
|------|----------------|--------|
| GET / | Landing | ✅ |
| GET /login | Form login | ✅ |
| POST /login | Proses login | ✅ |
| POST /logout | Logout | ✅ |
| GET /password/forgot | Form lupa kata sandi | ✅ |
| POST /password/forgot | Kirim tautan reset ke email | ✅ |
| GET /password/reset/{token} | Form atur ulang kata sandi | ✅ |
| POST /password/reset | Proses atur ulang kata sandi | ✅ |
| GET /dashboard | Dashboard (ringkasan) | ✅ |
| GET/POST /outlets/* | CRUD Outlet | ✅ |
| GET/POST /outlet-devices/* | CRUD Perangkat Outlet (printer, KDS, display) | ✅ |
| POST /outlet-floors | Tambah tempat (Teras, Lantai 1, dll) | ✅ |
| PUT /outlet-floors/{id} | Ubah nama tempat | ✅ |
| DELETE /outlet-floors/{id} | Hapus tempat (hanya jika belum ada meja) | ✅ |
| GET /outlet-tables | Peta Meja — daftar meja per tempat (?outlet_id=, ?floor_id=) | ✅ |
| GET /outlet-tables/create | Form tambah meja (grid) | ✅ |
| POST /outlet-tables | Simpan meja (grid/floor) | ✅ |
| GET /outlet-tables/layout-editor | Editor tata letak (drag-drop, ?floor_id=) | ✅ |
| POST /outlet-tables/update-layout | Simpan posisi & ukuran meja (AJAX) | ✅ |
| POST /outlet-tables/store-from-editor | Tambah meja dari editor (AJAX) | ✅ |
| POST /outlet-tables/save-canvas-size | Simpan ukuran canvas (per tempat) | ✅ |
| PATCH /outlet-tables/{id}/rename | Rename meja (AJAX, double-click di editor) | ✅ |
| GET/POST /categories/* | CRUD Kategori | ✅ |
| GET/POST /products/* | CRUD Produk | ✅ |
| GET /pos | POS (buka shift / order / cart / bayar) | ✅ |
| POST /pos/open-session | Buka shift | ✅ |
| POST /pos/close-session | Tutup shift | ✅ |
| POST /pos/order | Buat order baru | ✅ |
| POST /pos/add-item | Tambah item ke order | ✅ |
| POST /pos/remove-item | Hapus item | ✅ |
| POST /pos/pay | Bayar (split payment) | ✅ |
| GET /pos/orders/{id}/snap-token | Request Snap token Midtrans (QRIS) | ✅ |
| POST /midtrans/callback | Webhook callback Midtrans (settlement/expire/cancel) | ✅ |
| GET /orders | Daftar order (filter) | ✅ |
| GET /orders/{id} | Detail order | ✅ |
| POST /orders/{id}/status | Update status order | ✅ |
| POST /orders/{id}/delivery-status | Update status pengiriman (delivery: preparing → on_the_way → delivered) | ✅ |
| GET /orders/{id}/receipt | Struk order (print) | ✅ |
| GET /kitchen | Dapur (KDS) — pilih station, daftar order | ✅ |
| POST /kitchen/orders/{id}/start | KDS: mulai masak | ✅ |
| POST /kitchen/orders/{id}/ready | KDS: tandai siap | ✅ |
| POST /kitchen/orders/{id}/refire | KDS: re-fire | ✅ |
| GET /reports/consolidated | Ringkasan gabungan (revenue & order per outlet + total, filter periode) | ✅ |
| GET /reports/sales | Laporan penjualan (filter + export CSV) | ✅ |
| GET /api/me | API data user login (JSON) | ✅ |
| GET /api/permissions | API daftar permission user (JSON) | ✅ |
| GET /api/outlets | API daftar outlet user (JSON) | ✅ |
| GET /api/categories | API daftar kategori per outlet (JSON, ?outlet_id=) | ✅ |
| GET /api/products | API price list per outlet (JSON, ?outlet_id=, ?category_id=, ?available_only=) | ✅ |
| GET /api/orders | API daftar order (JSON, filter) | ✅ |
| POST /api/orders | API buat order + items (JSON) | ✅ |
| GET /api/orders/{id} | API detail order (JSON) | ✅ |
| POST /api/orders/{id}/status | API ubah status order (JSON) | ✅ |
| GET/POST /customers/* | CRUD Pelanggan + detail (riwayat order) | ✅ |
| GET/POST /loyalty-tiers/* | CRUD Tier Loyalty (per outlet) | ✅ |
| GET/POST /ingredients/* | CRUD Bahan baku + detail stok | ✅ |
| POST /ingredients/{id}/movement | Catat pergerakan stok (in/out/adjust/waste) | ✅ |
| GET/POST /vouchers/* | CRUD Voucher (kode, nominal/percent, valid, min order) | ✅ |
| GET/POST /promotion-rules/* | CRUD Aturan Promo (Buy X Get Y) | ✅ |
| GET /billing | Daftar invoice langganan (filter outlet, status) | ✅ |
| GET /billing/create | Form buat invoice | ✅ |
| POST /billing | Simpan invoice (outlet, periode, jumlah, due_date) | ✅ |
| GET /billing/{id} | Detail invoice | ✅ |
| POST /billing/{id}/mark-as-paid | Tandai invoice lunas | ✅ |
| POST /pos/apply-voucher | Terapkan kode voucher ke order (POS) | ✅ |
| POST /pos/remove-voucher | Hapus voucher dari order (POS) | ✅ |
| POST /pos/apply-points | Tukar poin ke diskon (POS, order punya pelanggan) | ✅ |
| POST /pos/remove-points | Hapus tukar poin dari order (POS) | ✅ |
| POST /feedback | Simpan feedback pelanggan (rating, comment, customer_id, order_id opsional) | ✅ |
| GET/POST /suppliers/* | CRUD Supplier (per outlet) | ✅ |
| GET/POST /purchase-orders/* | CRUD Purchase Order + item | ✅ |
| POST /purchase-orders/{id}/mark-ordered | Tandai PO sudah dipesan | ✅ |
| POST /purchase-orders/{id}/receive | Terima PO & tambah stok (StockMovement) | ✅ |
| GET /activity-logs | Log aktivitas (filter action, date) | ✅ |
| GET /reports/purchases | Laporan pembelian (PO diterima, nilai, export CSV) | ✅ |
| GET /reports/payments | Riwayat pembayaran (filter outlet, tanggal) | ✅ |
| GET /reports/staff | Performa staf (penjualan per user, export CSV) | ✅ |
| GET /reports/exports | Daftar export saya (antrian export) | ✅ |
| POST /reports/queue-export | Masukkan export ke antrian (type, date_from, date_to, outlet_id) | ✅ |
| GET /reports/exports/{id}/download | Unduh file export (jika selesai) | ✅ |
| GET /api-keys | Daftar API key saya (UI) | ✅ |
| POST /api-keys | Buat API key (nama); key ditampilkan sekali | ✅ |
| DELETE /api-keys/{id} | Revoke API key | ✅ |
| GET /qr-order/{outletCode}/{tableName?} | Menu publik QR order (tanpa login) | ✅ |
| POST /qr-order/{outletCode} | Submit order via QR (tanpa login) | ✅ |
| GET /qr-order/{outletCode}/success/{order} | Halaman sukses setelah QR order | ✅ |
| GET /notifications | Daftar notifikasi user | ✅ |
| GET /notifications/latest | JSON notifikasi terbaru (polling bell) | ✅ |
| POST /notifications/{id}/read | Tandai notifikasi dibaca + redirect | ✅ |
| POST /notifications/mark-all-read | Tandai semua notifikasi dibaca | ✅ |
| GET /api/reports/sales | API laporan penjualan (JSON) | ✅ |
| GET /api/reports/consolidated | API ringkasan gabungan (JSON) | ✅ |

---

## 7. Kesimpulan

- **Phase 1** secara fungsional **sudah selesai**: satu outlet bisa dipakai penuh (login → buka shift → order → bayar → tutup shift → laporan). Termasuk: UI CRUD Modifier di edit produk, update status order dari halaman detail order, receipt/print, API Order (list, create, show, update status); doc: docs/16-API-ORDER-REFERENCE.md.
- **Modul Customer (awal Phase 2)** sudah: CRUD pelanggan (per outlet), POS pilih pelanggan opsional, tampilan nama pelanggan di order/receipt; permission customer.manage; feature test CustomerTest (4).
- **Modul Kitchen (KDS)** sudah: KitchenStation, KitchenOrder, CookingLog; order dikirim ke dapur saat status CONFIRMED; UI Dapur; Product assign station dapur; permission kds.view; KitchenOrderPolicy.
- **Modul Inventory (dasar)** sudah: Ingredient, Stock, StockMovement; CRUD bahan baku per outlet; stok masuk/keluar/koreksi/waste; alert stok minimum; permission inventory.manage; IngredientPolicy.
- **Modul Promotion (Voucher)** sudah: CRUD voucher, apply/hapus di POS, discount di order & receipt; permission promo.manage.
- **Modul Delivery** sudah: Order tipe delivery di POS (alamat, no. HP, ongkir); total order termasuk ongkir; status pengiriman (Disiapkan → Dalam perjalanan → Sampai) di halaman order; receipt tampil alamat & ongkir; API Order store terima delivery_address, delivery_phone, shipping_cost.
- **Modul Loyalty** sudah: Poin (customers.points_balance); earn saat order completed (1 poin per X Rp, setting per outlet); redeem di POS (tukar poin → diskon); loyalty_point_logs (earn/redeem/adjust); CRUD Tier Loyalty (loyalty-tiers index/create/edit/destroy); assign tier di edit pelanggan; setting outlet: points_per_amount, redeem_value_per_point; tampilan poin di daftar & edit pelanggan; order/receipt tampil diskon poin.
- **Riwayat transaksi per pelanggan:** Halaman Pelanggan (show) menampilkan detail pelanggan + daftar order dengan filter status; link ke detail order.
- **API Auth:** GET /api/me (user + role + outlets), GET /api/permissions (slug permission), GET /api/outlets (daftar outlet); auth session.
- **Jam operasional:** Tabel outlet_opening_hours (per hari); form buka/tutup di edit outlet; outlet baru dapat 7 baris default.
- **Recipe mapping:** Tabel recipes (product_id, ingredient_id, quantity); section Resep di edit produk (bahan + qty per porsi); siap untuk auto deduction stok nanti.
- **Event:** UserLoggedIn (login), OrderCreated (create order), OrderPaid (order lunas), POSSessionOpened (buka shift), PaymentCompleted (tiap pembayaran); listener Log* menulis ke Log.
- **Lupa kata sandi:** Form lupa kata sandi (link dari login), kirim tautan reset ke email (Laravel Password broker), form atur ulang kata sandi dengan token; rute password.request, password.email, password.reset, password.update.
- **OutletDevice:** Tabel outlet_devices (outlet_id, type, name, config, sort_order, is_active); CRUD Perangkat Outlet (index/create/edit/destroy); tipe printer, kds, display; config (driver, ip, port); sidebar "Perangkat Outlet".
- **Status REFUNDED:** Order bisa diubah dari completed → refunded (tombol Refund di orders/show); API update-status mendukung refunded; flow sederhana tanpa reversal payment otomatis.
- **OutletSetting:** Tabel outlet_settings (outlet_id, key, value); Outlet::getSetting/setSetting untuk konfig opsional per outlet.
- **Auto deduction dari recipe:** Saat order completed (lunas di POS atau ubah status Selesai di UI), stok bahan dikurangi otomatis dari resep (StockService::deductForOrder); movement ref_type order; kolom inventory_deducted_at mencegah dobel.
- **CustomerFeedback:** Tabel customer_feedbacks (customer_id, order_id nullable, rating 1–5, comment); form "Beri rating" di order show (jika selesai + pelanggan + belum ada feedback) dan form + daftar feedback di customer show; POST /feedback; permission customer.manage.
- **Supplier & PurchaseOrder:** CRUD Supplier (per outlet); CRUD Purchase Order dengan item (bahan + qty + harga); status draft → ordered → received; aksi "Terima PO" menambah stok (StockMovement ref_type purchase_order); po_number unik per outlet/hari; sidebar Supplier & Purchase Order; SupplierPolicy, PurchaseOrderPolicy; permission inventory.manage.
- **Activity log:** Tabel activity_logs (user_id, action, subject_type, subject_id, description, properties); ActivityLog::log() dipanggil di order.created, order.completed (lunas & ubah status), po.received, user.login; halaman Log Aktivitas dengan filter aksi & tanggal; permission report.view; sidebar "Log Aktivitas".
- **Laporan Pembelian:** reports/purchases — PO dengan status received dalam periode; total nilai (qty × unit_price per item); filter outlet & tanggal; export CSV; tab navigasi ke Penjualan / Riwayat Pembayaran.
- **Riwayat Pembayaran:** reports/payments — daftar order_payments dengan order, outlet, metode, jumlah; filter outlet & tanggal; paginasi; melengkapi Payment log / audit.
- **Performa Staf:** reports/staff — penjualan per user (order completed yang punya pos_session); group by user & outlet; filter tanggal & outlet; export CSV; tab di laporan.
- **Peta Meja & banyak tempat:** Tabel outlet_floors (tempat: Teras, Lantai 1, dll) dan outlet_tables (outlet_floor_id, shape, x, y, w, h); CRUD tempat; editor tata letak (drag-drop, resize, bentuk persegi/bulat/ellips, double-click rename); POS pilih tempat lalu peta meja per tempat; dashboard per role (kasir vs admin).
- **Grafik penjualan dashboard:** Untuk role non-kasir, grafik 7 hari terakhir (pendapatan bar + jumlah order line) dengan Chart.js; data dari order completed per hari sesuai outlet user.
- **Panduan operator Peta Meja:** docs/17-PETA-MEJA-DAN-TEMPAT.md — cara konfigurasi tempat, meja, editor tata letak, dan penggunaan di POS.
- **Integrasi Midtrans (QRIS):** MidtransService + MidtransController; Snap popup di POS; webhook callback; feature toggle `midtrans`; docs: 18-PAYMENT-GATEWAY-INTEGRATION.md.
- **Dokumentasi tambahan:** 18-PAYMENT-GATEWAY-INTEGRATION, 19-MULTI-TENANT-SAAS, 20-LOKALISASI-INDONESIA, 21-CHANGELOG, 22-COMPETITIVE-ANALYSIS.

**Phase 2 lengkap:** Customer, KDS, Inventory, Promo (Voucher), Delivery, Loyalty (points + tier), Riwayat transaksi pelanggan, CRUD Tier, API Auth, API Menu (categories & products by outlet), Jam operasional, Recipe mapping, Event (UserLoggedIn, OrderCreated, OrderPaid, POSSessionOpened, PaymentCompleted), OutletDevice, Status REFUNDED, OutletSetting (key-value), Auto deduction stok dari recipe saat order completed, CustomerFeedback (rating & komentar per pelanggan/order), Supplier & PurchaseOrder (CRUD + terima PO → stok), Activity log (order/PO/login), Laporan Performa Staf.

**Phase 3 — Sudah (prioritas 1–7 + API key + billing dasar + Midtrans + User Mgmt):** OpenAPI spec + Swagger UI; rate limit API 60/menit; cache menu per outlet; queue export laporan; laporan ringkasan gabungan; feature toggle; fondasi paket/plan + limit fitur per plan; API key per client + UI kelola; **billing dasar** (invoice langganan: buat, daftar, tandai lunas; permission billing.manage); **Midtrans (QRIS)** integrasi pembayaran online di POS; **User Management** (CRUD User + permission user.manage) dan **Settings Profile Update**.

Untuk update berkala, edit file ini dan ubah status (✅ / 🟡 / ⬜) beserta catatan sesuai perkembangan development.
