# Flutter API Integration Plan
## POS Cashier App & Waiter App

---

> **SSOT (Single Source of Truth) Notice**
>
> Dokumentasi detail API endpoints **TIDAK** ada di file ini.
> Semua API documentation ada di **Swagger/OpenAPI**:
>
> | Resource | URL |
> |----------|-----|
> | **Swagger UI** | `{BASE_URL}/api/documentation` |
> | **OpenAPI JSON** | `{BASE_URL}/docs` |
>
> File ini hanya berisi:
> - Architecture & strategy overview
> - Implementation checklist
> - Flutter app structure
> - Offline-first strategy untuk POS Cashier
>
> Untuk detail request/response setiap endpoint, **selalu rujuk ke Swagger**.

---

## Overview

| App | Target User | Primary Features | Mode |
|-----|-------------|------------------|------|
| **POS Cashier App** | Kasir | Checkout, payment, transaction history | **Offline-First** |
| **Waiter App** | Pelayan | Table management, order taking, order status | **Online Required** |

### Connectivity Requirements

| App | Mode | Reason |
|-----|------|--------|
| **POS Cashier** | Offline-First | Transaksi harus tetap jalan walau internet mati. Sync menyusul ketika online. |
| **Waiter App** | Online Required | Real-time coordination dengan kitchen, table status harus sync antar device. |

### Tech Stack
- **Backend**: Laravel 12 + Sanctum API
- **Mobile**: Flutter
- **Real-time**: Laravel Reverb (untuk Waiter App & KDS)
- **Offline (POS only)**: SQLite + Queue sync

---

## Phase Overview

```
┌─────────────────────────────────────────────────────────────┐
│  PHASE A: API Foundation (Backend)                          │
│  - Laravel Sanctum authentication                           │
│  - API routes structure                                     │
│  - JSON Resources                                           │
│  - Response standardization                                 │
├─────────────────────────────────────────────────────────────┤
│  PHASE B: Core API Endpoints (Backend)                      │
│  - Auth API                                                 │
│  - Product & Category API                                   │
│  - Transaction API                                          │
│  - Customer API                                             │
│  - Payment & Discount API                                   │
│  - Session API                                              │
├─────────────────────────────────────────────────────────────┤
│  PHASE C: Table Management (Backend - NEW)                  │
│  - Floor & Table models                                     │
│  - Table status management                                  │
│  - Order-Table linking                                      │
├─────────────────────────────────────────────────────────────┤
│  PHASE D: Flutter POS Cashier App                           │
│  - Authentication flow                                      │
│  - Product catalog                                          │
│  - Cart & checkout                                          │
│  - Transaction history                                      │
├─────────────────────────────────────────────────────────────┤
│  PHASE E: Flutter Waiter App (Online Required)              │
│  - Table view & floor plan                                  │
│  - Order by table                                           │
│  - Order status tracking (real-time)                        │
│  - WebSocket for live updates                               │
├─────────────────────────────────────────────────────────────┤
│  PHASE F: KDS Integration (Later)                           │
│  - Kitchen stations                                         │
│  - Real-time order updates                                  │
│  - Order item status                                        │
└─────────────────────────────────────────────────────────────┘
```

---

# PHASE A: API Foundation

## A.1 Install & Configure Sanctum

```bash
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
```

### User Model Update
```php
// app/Models/User.php
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
```

### bootstrap/app.php
```php
->withMiddleware(function (Middleware $middleware) {
    $middleware->statefulApi();

    $middleware->alias([
        'auth.sanctum' => \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    ]);
})
```

## A.2 API Routes Structure

```
routes/
├── api.php              # Main API routes
└── api/
    ├── auth.php         # Authentication routes
    ├── pos.php          # POS operations
    ├── products.php     # Product catalog
    ├── tables.php       # Table management
    └── customers.php    # Customer management
```

## A.3 Standard API Response Format

```php
// Success Response
{
    "success": true,
    "message": "Operation successful",
    "data": { ... }
}

// Error Response
{
    "success": false,
    "message": "Error description",
    "errors": {
        "field": ["Error message"]
    }
}

// Paginated Response
{
    "success": true,
    "data": [ ... ],
    "meta": {
        "current_page": 1,
        "last_page": 10,
        "per_page": 20,
        "total": 200
    }
}
```

## A.4 API Versioning

All endpoints prefixed with `/api/v1/`

---

# PHASE B: Core API Endpoints

> **Lihat Swagger untuk detail lengkap**: `{BASE_URL}/api/documentation`
>
> Bagian ini hanya berisi ringkasan endpoints. Untuk request/response schemas,
> parameter details, dan contoh lengkap, **selalu rujuk ke Swagger**.

## API Endpoint Summary

| Group | Prefix | Controller | Status |
|-------|--------|------------|--------|
| **Authentication** | `/api/v1/auth` | `AuthController` | ✅ Complete |
| **Outlets** | `/api/v1/outlets` | `OutletController` | ✅ Complete |
| **Products** | `/api/v1/products` | `ProductController` | ✅ Complete |
| **Categories** | `/api/v1/categories` | `CategoryController` | ✅ Complete |
| **Transactions** | `/api/v1/transactions` | `TransactionController` | ✅ Complete |
| **Customers** | `/api/v1/customers` | `CustomerController` | ✅ Complete |
| **Payment Methods** | `/api/v1/payment-methods` | `PaymentMethodController` | ✅ Complete |
| **Discounts** | `/api/v1/discounts` | `DiscountController` | ✅ Complete |
| **Sessions** | `/api/v1/sessions` | `SessionController` | ✅ Complete |
| **Held Orders** | `/api/v1/held-orders` | `HeldOrderController` | ✅ Complete |
| **Authorization** | `/api/v1/authorize` | `AuthorizationController` | ✅ Complete |
| **Floors** | `/api/v1/floors` | `FloorController` | ✅ Complete |
| **Tables** | `/api/v1/tables` | `TableController` | ✅ Complete |
| **Mobile Sync** | `/api/v1/mobile-sync` | `MobileSyncController` | 🔄 Partial |

## Standard API Response Format

```json
// Success Response
{
    "success": true,
    "message": "Operation successful",
    "data": { ... }
}

// Error Response
{
    "success": false,
    "message": "Error description",
    "errors": {
        "field": ["Error message"]
    }
}

// Paginated Response
{
    "success": true,
    "data": [ ... ],
    "meta": {
        "current_page": 1,
        "last_page": 10,
        "per_page": 20,
        "total": 200
    }
}
```

## Authorization Action Types

| Action | Description | Default Requires Auth |
|--------|-------------|----------------------|
| `void` | Void Transaction | Yes |
| `refund` | Refund Transaction | Yes |
| `discount` | Manual Discount | Only if > threshold |
| `price_override` | Price Override | Yes |
| `no_sale` | No Sale / Cash Drawer | Yes |
| `reprint` | Reprint Receipt | No |
| `cancel_order` | Cancel Order | Yes |

---

# PHASE C: Table Management

> **Lihat Swagger untuk detail lengkap**: `{BASE_URL}/api/documentation`

## Database Schema (Reference Only)

```sql
-- Floors
CREATE TABLE floors (
    id UUID PRIMARY KEY,
    tenant_id UUID, outlet_id UUID,
    name VARCHAR(100), sort_order INT,
    is_active BOOLEAN DEFAULT TRUE
);

-- Tables
CREATE TABLE tables (
    id UUID PRIMARY KEY,
    tenant_id UUID, outlet_id UUID, floor_id UUID,
    number VARCHAR(20), name VARCHAR(100), capacity INT,
    position_x INT, position_y INT, width INT, height INT,
    shape VARCHAR(20), -- rectangle, circle, square
    status VARCHAR(20), -- available, occupied, reserved, dirty
    is_active BOOLEAN DEFAULT TRUE
);

-- Table Sessions
CREATE TABLE table_sessions (
    id UUID PRIMARY KEY,
    table_id UUID,
    opened_at TIMESTAMP, closed_at TIMESTAMP,
    guest_count INT, status VARCHAR(20)
);
```

## Table Status Flow

```
available → occupied (open session)
occupied → dirty (close session)
dirty → available (mark clean)
available → reserved (reservation)
reserved → occupied (guest arrives)
```

---

# PHASE D: Flutter POS Cashier App

## D.1 Features Checklist

### Authentication
- [ ] Login with email/password
- [ ] Login with PIN (quick switch)
- [ ] Remember device
- [ ] Auto logout on inactivity
- [ ] Outlet selection

### Dashboard
- [ ] Today's summary (sales, transactions)
- [ ] Quick actions
- [ ] Session status

### Product Catalog
- [ ] Category grid/list view
- [ ] Product search
- [ ] Barcode scanning
- [ ] Product detail with variants
- [ ] Modifier selection

### Cart Management
- [ ] Add to cart
- [ ] Edit quantity
- [ ] Remove item
- [ ] Item notes
- [ ] Clear cart
- [ ] Hold order
- [ ] Recall held order

### Checkout
- [ ] Customer selection/creation
- [ ] Discount application
- [ ] Points redemption
- [ ] Order type (dine-in/takeaway)
- [ ] Table selection (if dine-in)
- [ ] Payment processing (single/split)
- [ ] Change calculation
- [ ] Receipt printing/sharing

### Transaction History
- [ ] List transactions
- [ ] Search by invoice/date
- [ ] Transaction detail
- [ ] Reprint receipt
- [ ] Void transaction (with auth)
- [ ] Refund (with auth)

### Session Management
- [ ] Open session
- [ ] View current session
- [ ] Close session with cash count
- [ ] Session report

### Settings
- [ ] Profile settings
- [ ] PIN management
- [ ] Printer configuration
- [ ] Receipt preview

---

## D.2 Screens Structure

```
lib/
├── main.dart
├── app/
│   ├── routes.dart
│   └── theme.dart
├── core/
│   ├── api/
│   │   ├── api_client.dart
│   │   ├── api_exceptions.dart
│   │   └── endpoints.dart
│   ├── storage/
│   │   ├── local_storage.dart
│   │   └── secure_storage.dart
│   └── utils/
│       ├── currency_formatter.dart
│       └── date_formatter.dart
├── features/
│   ├── auth/
│   │   ├── data/
│   │   ├── domain/
│   │   └── presentation/
│   │       ├── login_screen.dart
│   │       ├── pin_login_screen.dart
│   │       └── outlet_selection_screen.dart
│   ├── products/
│   │   ├── data/
│   │   ├── domain/
│   │   └── presentation/
│   │       ├── product_catalog_screen.dart
│   │       ├── product_detail_screen.dart
│   │       └── widgets/
│   ├── cart/
│   │   ├── data/
│   │   ├── domain/
│   │   └── presentation/
│   │       ├── cart_screen.dart
│   │       └── widgets/
│   ├── checkout/
│   │   ├── data/
│   │   ├── domain/
│   │   └── presentation/
│   │       ├── checkout_screen.dart
│   │       ├── payment_screen.dart
│   │       └── receipt_screen.dart
│   ├── transactions/
│   │   ├── data/
│   │   ├── domain/
│   │   └── presentation/
│   │       ├── transaction_list_screen.dart
│   │       └── transaction_detail_screen.dart
│   ├── customers/
│   ├── session/
│   └── settings/
└── shared/
    ├── models/
    ├── providers/
    └── widgets/
```

---

# PHASE E: Flutter Waiter App (Online Required)

> **IMPORTANT**: Waiter App membutuhkan koneksi internet aktif untuk:
> - Real-time table status sync antar device
> - Koordinasi dengan Kitchen Display System
> - Live order updates

## E.1 Features Checklist

### Authentication
- [ ] Login with PIN (primary)
- [ ] Login with email (fallback)
- [ ] Auto-assign to outlet

### Connectivity
- [ ] Network status indicator
- [ ] Auto-reconnect WebSocket
- [ ] Block actions when offline (show warning)
- [ ] Graceful degradation (read-only mode when offline)

### Floor Plan View
- [ ] Visual floor layout
- [ ] Table status colors (real-time update)
- [ ] Tap to select table
- [ ] Table details popup
- [ ] Swipe between floors

### Table Operations
- [ ] Open table (set guest count)
- [ ] View table orders
- [ ] Add order to table
- [ ] Close table / request bill
- [ ] Transfer table
- [ ] Mark table as dirty/clean

### Order Taking
- [ ] Quick product selection
- [ ] Category browsing
- [ ] Variant/modifier selection
- [ ] Order notes
- [ ] Send to kitchen (real-time)
- [ ] Order status tracking (live from KDS)

### Order Management
- [ ] View active orders
- [ ] Cancel item (with auth)
- [ ] Modify item
- [ ] Print to kitchen

### Real-time Notifications (WebSocket)
- [ ] Order ready notification (from KDS)
- [ ] Table status changed (from other waiters)
- [ ] New order on table (from QR Order)
- [ ] Kitchen delay alert

---

## E.2 Screens Structure

```
lib/
├── main.dart
├── features/
│   ├── auth/
│   │   └── presentation/
│   │       └── pin_login_screen.dart
│   ├── floor_plan/
│   │   └── presentation/
│   │       ├── floor_plan_screen.dart
│   │       ├── table_detail_bottom_sheet.dart
│   │       └── widgets/
│   │           ├── floor_selector.dart
│   │           ├── table_widget.dart
│   │           └── table_status_legend.dart
│   ├── tables/
│   │   └── presentation/
│   │       ├── table_orders_screen.dart
│   │       ├── open_table_dialog.dart
│   │       └── close_table_screen.dart
│   ├── orders/
│   │   └── presentation/
│   │       ├── new_order_screen.dart
│   │       ├── order_detail_screen.dart
│   │       └── widgets/
│   ├── products/
│   │   └── presentation/
│   │       ├── product_grid_screen.dart
│   │       └── product_customize_sheet.dart
│   └── notifications/
│       └── presentation/
│           └── notification_list_screen.dart
└── shared/
    ├── realtime/
    │   ├── websocket_service.dart
    │   └── event_handlers.dart
    └── widgets/
        └── connectivity_indicator.dart
```

---

# Implementation Checklist

## Backend Tasks

### Phase A: Foundation
- [x] A.1 Install Laravel Sanctum ✅
- [x] A.2 Create `routes/api.php` ✅
- [x] A.3 Create `ApiResponse` trait/helper ✅
- [x] A.4 Create base API controller ✅
- [x] A.5 Configure CORS for mobile ✅
- [x] A.6 Setup rate limiting ✅
- [x] A.7 Add `HasApiTokens` to User model ✅

### Phase B: Core API
- [x] B.1 Create `Api/AuthController` ✅
- [x] B.2 Create `Api/OutletController` ✅
- [x] B.3 Create `Api/ProductController` ✅
- [x] B.4 Create `Api/CategoryController` ✅
- [x] B.5 Create `Api/TransactionController` ✅
- [x] B.6 Create `Api/CustomerController` ✅
- [x] B.7 Create `Api/PaymentMethodController` ✅ (with OpenAPI, calculate-charge, types)
- [x] B.8 Create `Api/DiscountController` ✅
- [x] B.9 Create `Api/SessionController` ✅
- [x] B.10 Create `Api/HeldOrderController` ✅ (with OpenAPI docs)
- [x] B.11 Create `Api/AuthorizationController` ✅ (with OpenAPI, check, managers, settings, logs)

### Phase B: Resources
- [ ] B.12 Create `UserResource`
- [ ] B.13 Create `OutletResource`
- [ ] B.14 Create `ProductResource`
- [ ] B.15 Create `ProductCollection`
- [ ] B.16 Create `CategoryResource`
- [ ] B.17 Create `TransactionResource`
- [ ] B.18 Create `CustomerResource`
- [ ] B.19 Create `PaymentMethodResource`
- [ ] B.20 Create `DiscountResource`
- [ ] B.21 Create `SessionResource`

### Phase C: Table Management
- [x] C.1 Create `floors` migration ✅
- [x] C.2 Create `tables` migration ✅
- [x] C.3 Create `table_sessions` migration ✅
- [x] C.4 Add `table_id` to transactions migration ✅
- [x] C.5 Create `Floor` model ✅
- [x] C.6 Create `Table` model ✅
- [x] C.7 Create `TableSession` model ✅
- [x] C.8 Create `Api/FloorController` ✅ (with OpenAPI docs)
- [x] C.9 Create `Api/TableController` ✅ (with OpenAPI docs)
- [ ] C.10 Create `FloorResource`
- [ ] C.11 Create `TableResource`
- [ ] C.12 Create `TableSessionResource`
- [x] C.13 Implement table status management ✅
- [x] C.14 Implement table move/transfer ✅
- [ ] C.15 Implement bill splitting

### Phase B: Tests
- [ ] B.22 Auth API tests
- [ ] B.23 Product API tests
- [ ] B.24 Transaction API tests
- [ ] B.25 Customer API tests
- [ ] B.26 Table API tests

---

## Flutter Tasks

### POS Cashier App (Offline-First)
- [ ] D.1 Project setup & architecture
- [ ] D.2 API client implementation
- [ ] D.3 Auth module
- [ ] D.4 Product catalog module
- [ ] D.5 Cart module
- [ ] D.6 Checkout module
- [ ] D.7 Transaction history module
- [ ] D.8 Session management module
- [ ] D.9 Settings module
- [ ] D.10 Printer integration
- [ ] D.11 **SQLite local database setup**
- [ ] D.12 **Offline queue service**
- [ ] D.13 **Sync service (master data + transactions)**
- [ ] D.14 **Transaction number generator (offline)**
- [ ] D.15 **Conflict resolution handling**

### Waiter App (Online Required)
- [ ] E.1 Project setup (shared core with POS)
- [ ] E.2 Floor plan UI
- [ ] E.3 Table management module
- [ ] E.4 Order taking module
- [ ] E.5 **WebSocket service (real-time)**
- [ ] E.6 **Connectivity indicator & offline warning**
- [ ] E.7 Push notifications

---

# API Response Codes

| Code | Meaning |
|------|---------|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 422 | Validation Error |
| 429 | Too Many Requests |
| 500 | Server Error |

---

# Security Considerations

1. **Token Expiration**: Tokens expire after 24 hours
2. **PIN Login**: Only works after initial email login on device
3. **Sensitive Actions**: Void, refund, large discounts require manager PIN
4. **Rate Limiting**: 60 requests/minute for general, 5/minute for auth
5. **Device Tracking**: Track device_name for token management
6. **Tenant Isolation**: All queries scoped to user's tenant

---

# OFFLINE-FIRST STRATEGY (POS Cashier App Only)

> **APPLIES TO**: POS Cashier App only
> **NOT FOR**: Waiter App (requires real-time online connection)

## Overview

```
┌─────────────────────────────────────────────────────────────────┐
│           OFFLINE-FIRST ARCHITECTURE (POS CASHIER)               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌─────────────┐      ┌─────────────┐      ┌─────────────┐    │
│   │  POS CASHIER│ ───► │   SQLite    │ ───► │    SYNC     │    │
│   │     APP     │      │   (Local)   │      │   SERVICE   │    │
│   └─────────────┘      └─────────────┘      └──────┬──────┘    │
│                                                     │           │
│                                                     ▼           │
│                                              ┌─────────────┐    │
│                                              │  LARAVEL    │    │
│                                              │    API      │    │
│                                              └─────────────┘    │
│                                                                  │
│   Principle: "Local First, Sync Later"                          │
│   - Transaksi tetap jalan walau internet mati                   │
│   - All reads from local SQLite                                 │
│   - All writes to local first, then queue for sync              │
│   - Background sync when online                                 │
│                                                                  │
│   Why POS needs offline:                                         │
│   - Kasir tidak boleh berhenti melayani customer                │
│   - Internet putus = bisnis tetap jalan                         │
│   - Sync bisa menyusul setelah koneksi pulih                    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

---

## Sync Triggers

| Event | Sync Action |
|-------|-------------|
| **Login** | Full master data sync |
| **Open Shift** | Delta sync master data + upload pending transactions |
| **Close Shift** | Upload all pending transactions + session report |
| **Periodic (5-15 min)** | Delta sync + upload pending |
| **Manual Refresh** | Force full sync |
| **Network Restored** | Upload pending transactions |

---

## 1. MASTER DATA (Cache Locally)

### 1.1 Data Categories & Sync Strategy

| Category | Data | Sync Strategy | Priority |
|----------|------|---------------|----------|
| **Static** | Categories, Variant Groups, Modifier Groups | On open shift, daily delta | Low |
| **Semi-Static** | Products, Variants, Modifiers, Combos | On open shift, hourly delta | Medium |
| **Dynamic** | Prices, Discounts, **Stock Levels** | On open shift, every 5-15 min | High |
| **Table Data** | Floors, Tables, Table Status | On open shift, every 1-5 min | High |
| **Customers** | Customer list, Points | **Lazy load on search** | On-demand |

### 1.2 Sync Strategy Decisions

| Data | Strategy | Reason |
|------|----------|--------|
| **Customers** | **Lazy Load** | Data besar, search online lalu cache hasil |
| **Tables** | **Full Sync** | POS Cashier bisa gantiin Waiter App |
| **Stock Levels** | **Full Sync** | Warning "out of stock" di POS |

### 1.3 Open Shift Sync - Data yang Di-download

```
┌─────────────────────────────────────────────────────────────────┐
│                 OPEN SHIFT - MASTER DATA SYNC                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ALWAYS SYNC (Required):                                         │
│  ────────────────────────                                        │
│  1. Outlet & Tenant Config                                       │
│     └── tax, service_charge, receipt settings                   │
│                                                                  │
│  2. User & Permissions                                           │
│     └── roles, permissions, feature access                      │
│                                                                  │
│  3. Product Catalog                                              │
│     ├── Categories (hierarchy)                                   │
│     ├── Variant Groups & Options                                 │
│     ├── Modifier Groups & Modifiers                              │
│     ├── Products (single, variant, combo)                        │
│     ├── Product Variants                                         │
│     ├── Combos & Combo Items                                     │
│     └── Product Outlet Overrides (pricing)                       │
│                                                                  │
│  4. Pricing & Rules                                              │
│     ├── Discounts (active/valid)                                 │
│     └── Payment Methods                                          │
│                                                                  │
│  5. Stock Levels                                                 │
│     └── Current stock per product/variant (for out-of-stock)    │
│                                                                  │
│  6. Tables & Floors                                              │
│     ├── Floors (areas)                                           │
│     └── Tables (with current status)                             │
│                                                                  │
│  LAZY LOAD (On Demand):                                          │
│  ──────────────────────                                          │
│  • Customers → Search online, cache hasil locally                │
│    └── Ketika cashier search customer, hit API lalu simpan      │
│    └── Cache expire setelah 24 jam atau manual refresh           │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

### 1.4 Estimated Data Size (Open Shift Sync)

| Data | Typical Count | Size | Notes |
|------|---------------|------|-------|
| Outlet config | 1 | ~2KB | |
| User + permissions | 1 | ~5KB | |
| Categories | 20-100 | ~50KB | |
| Products + Variants | 500-2000 | **2-5MB** | Biggest chunk |
| Modifiers | 200-500 | ~250KB | |
| Combos | 50-200 | ~200KB | |
| Discounts | 10-50 | ~50KB | |
| Payment Methods | 5-15 | ~10KB | |
| Stock Levels | 500-2000 | ~500KB | Per product/variant |
| Floors + Tables | 5 floors, 50 tables | ~100KB | |
| **Total Initial Sync** | - | **3-7MB** | |
| **Delta Sync** | - | **100KB-1MB** | Only changed records |

### 1.5 Customer Lazy Load Flow

```
┌─────────────────────────────────────────────────────────────────┐
│                   CUSTOMER LAZY LOAD FLOW                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Cashier types "John" in customer search                         │
│     │                                                            │
│     ▼                                                            │
│  Check local cache first                                         │
│     │                                                            │
│     ├── Found in cache? ──► Show results                         │
│     │                                                            │
│     ├── Not found / cache expired?                               │
│     │       │                                                    │
│     │       ▼                                                    │
│     │   Online? ──► API search: GET /customers/search?q=John    │
│     │       │                                                    │
│     │       ▼                                                    │
│     │   Save results to local cache                              │
│     │       │                                                    │
│     │       ▼                                                    │
│     │   Show results                                             │
│     │                                                            │
│     └── Offline & not in cache? ──► Show "Search requires       │
│                                       internet connection"       │
│                                                                  │
│  On checkout with customer:                                      │
│     └── Customer data already in local cache (from search)      │
│     └── Points calculation done locally                          │
│     └── Points update queued for sync                            │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

### 1.6 Master Data Sync Order (Dependencies)

```
1. Outlet & Tenant Config (foundational)
   └── tax_percentage, service_charge, receipt settings

2. User & Permissions (access control)
   └── roles, permissions, accessible outlets

3. Product Categories (hierarchy)
   └── parent_id relationships

4. Variant Groups & Options
   └── for product variants

5. Modifier Groups & Modifiers
   └── for product customization

6. Products (all types)
   └── category_id, recipe_id links

7. Product Variants
   └── product_id, option_ids

8. Combos & Combo Items
   └── product_id links

9. Product Outlet Overrides
   └── outlet-specific pricing

10. Stock Levels
    └── current stock per product/variant

11. Discounts
    └── with eligibility rules

12. Payment Methods
    └── for checkout

13. Floors & Tables
    └── with current status
```

### 1.3 SQLite Schema (Flutter Local DB)

```sql
-- =====================================================
-- MASTER DATA TABLES
-- =====================================================

-- Outlet configuration
CREATE TABLE outlets (
    id TEXT PRIMARY KEY,
    code TEXT NOT NULL,
    name TEXT NOT NULL,
    address TEXT,
    phone TEXT,
    tax_percentage REAL DEFAULT 11.0,
    service_charge_percentage REAL DEFAULT 0,
    receipt_header TEXT,
    receipt_footer TEXT,
    opening_time TEXT,
    closing_time TEXT,
    synced_at INTEGER
);

-- Product categories (hierarchical)
CREATE TABLE categories (
    id TEXT PRIMARY KEY,
    parent_id TEXT,
    name TEXT NOT NULL,
    slug TEXT,
    image TEXT,
    color TEXT,
    icon TEXT,
    sort_order INTEGER DEFAULT 0,
    show_in_pos INTEGER DEFAULT 1,
    is_active INTEGER DEFAULT 1,
    synced_at INTEGER,
    FOREIGN KEY (parent_id) REFERENCES categories(id)
);

-- Products
CREATE TABLE products (
    id TEXT PRIMARY KEY,
    category_id TEXT,
    sku TEXT,
    barcode TEXT,
    name TEXT NOT NULL,
    description TEXT,
    image TEXT,
    base_price REAL NOT NULL DEFAULT 0,
    cost_price REAL DEFAULT 0,
    product_type TEXT DEFAULT 'single', -- single, variant, combo
    is_taxable INTEGER DEFAULT 1,
    is_service_charge INTEGER DEFAULT 1,
    show_in_pos INTEGER DEFAULT 1,
    is_active INTEGER DEFAULT 1,
    is_available INTEGER DEFAULT 1,
    prep_time_minutes INTEGER DEFAULT 0,
    allow_notes INTEGER DEFAULT 1,
    synced_at INTEGER,
    FOREIGN KEY (category_id) REFERENCES categories(id)
);
CREATE INDEX idx_products_barcode ON products(barcode);
CREATE INDEX idx_products_category ON products(category_id);
CREATE INDEX idx_products_active ON products(is_active, show_in_pos);

-- Variant groups
CREATE TABLE variant_groups (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL,
    display_name TEXT,
    display_type TEXT DEFAULT 'button', -- button, dropdown, color, image
    is_required INTEGER DEFAULT 0,
    sort_order INTEGER DEFAULT 0,
    synced_at INTEGER
);

-- Variant options
CREATE TABLE variant_options (
    id TEXT PRIMARY KEY,
    variant_group_id TEXT NOT NULL,
    name TEXT NOT NULL,
    value TEXT,
    image TEXT,
    color TEXT,
    sort_order INTEGER DEFAULT 0,
    synced_at INTEGER,
    FOREIGN KEY (variant_group_id) REFERENCES variant_groups(id)
);

-- Product variant groups (pivot)
CREATE TABLE product_variant_groups (
    product_id TEXT NOT NULL,
    variant_group_id TEXT NOT NULL,
    is_required INTEGER DEFAULT 0,
    sort_order INTEGER DEFAULT 0,
    PRIMARY KEY (product_id, variant_group_id)
);

-- Product variants
CREATE TABLE product_variants (
    id TEXT PRIMARY KEY,
    product_id TEXT NOT NULL,
    sku TEXT,
    barcode TEXT,
    name TEXT NOT NULL,
    price REAL NOT NULL DEFAULT 0,
    cost_price REAL DEFAULT 0,
    option_ids TEXT, -- JSON array of variant_option IDs
    image TEXT,
    is_active INTEGER DEFAULT 1,
    synced_at INTEGER,
    FOREIGN KEY (product_id) REFERENCES products(id)
);
CREATE INDEX idx_variants_product ON product_variants(product_id);
CREATE INDEX idx_variants_barcode ON product_variants(barcode);

-- Modifier groups
CREATE TABLE modifier_groups (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL,
    display_name TEXT,
    selection_type TEXT DEFAULT 'multiple', -- single, multiple
    min_selections INTEGER DEFAULT 0,
    max_selections INTEGER,
    is_required INTEGER DEFAULT 0,
    sort_order INTEGER DEFAULT 0,
    synced_at INTEGER
);

-- Modifiers
CREATE TABLE modifiers (
    id TEXT PRIMARY KEY,
    modifier_group_id TEXT NOT NULL,
    name TEXT NOT NULL,
    display_name TEXT,
    price REAL DEFAULT 0,
    cost_price REAL DEFAULT 0,
    is_default INTEGER DEFAULT 0,
    sort_order INTEGER DEFAULT 0,
    synced_at INTEGER,
    FOREIGN KEY (modifier_group_id) REFERENCES modifier_groups(id)
);

-- Product modifier groups (pivot)
CREATE TABLE product_modifier_groups (
    product_id TEXT NOT NULL,
    modifier_group_id TEXT NOT NULL,
    is_required INTEGER DEFAULT 0,
    sort_order INTEGER DEFAULT 0,
    PRIMARY KEY (product_id, modifier_group_id)
);

-- Combos
CREATE TABLE combos (
    id TEXT PRIMARY KEY,
    product_id TEXT NOT NULL,
    min_items INTEGER DEFAULT 1,
    max_items INTEGER,
    pricing_type TEXT DEFAULT 'fixed', -- fixed, sum, discount_percent, discount_amount
    discount_value REAL DEFAULT 0,
    allow_substitutions INTEGER DEFAULT 0,
    synced_at INTEGER,
    FOREIGN KEY (product_id) REFERENCES products(id)
);

-- Combo items
CREATE TABLE combo_items (
    id TEXT PRIMARY KEY,
    combo_id TEXT NOT NULL,
    product_id TEXT,
    category_id TEXT,
    quantity INTEGER DEFAULT 1,
    price_adjustment REAL DEFAULT 0,
    is_required INTEGER DEFAULT 1,
    allow_variant_selection INTEGER DEFAULT 1,
    sort_order INTEGER DEFAULT 0,
    synced_at INTEGER,
    FOREIGN KEY (combo_id) REFERENCES combos(id)
);

-- Product outlet overrides
CREATE TABLE product_outlets (
    product_id TEXT NOT NULL,
    outlet_id TEXT NOT NULL,
    custom_price REAL,
    is_available INTEGER DEFAULT 1,
    is_featured INTEGER DEFAULT 0,
    sort_order INTEGER DEFAULT 0,
    synced_at INTEGER,
    PRIMARY KEY (product_id, outlet_id)
);

-- Discounts
CREATE TABLE discounts (
    id TEXT PRIMARY KEY,
    code TEXT,
    name TEXT NOT NULL,
    description TEXT,
    type TEXT NOT NULL, -- percentage, fixed_amount, buy_x_get_y
    value REAL NOT NULL,
    scope TEXT DEFAULT 'order', -- order, item
    min_purchase REAL DEFAULT 0,
    min_qty INTEGER DEFAULT 1,
    max_discount REAL,
    valid_from INTEGER,
    valid_until INTEGER,
    member_only INTEGER DEFAULT 0,
    membership_levels TEXT, -- JSON array
    applicable_items TEXT, -- JSON array of product IDs
    applicable_outlets TEXT, -- JSON array of outlet IDs
    is_auto_apply INTEGER DEFAULT 0,
    is_active INTEGER DEFAULT 1,
    synced_at INTEGER
);

-- Payment methods
CREATE TABLE payment_methods (
    id TEXT PRIMARY KEY,
    code TEXT NOT NULL,
    name TEXT NOT NULL,
    type TEXT NOT NULL, -- cash, card, digital_wallet, transfer
    provider TEXT,
    charge_percentage REAL DEFAULT 0,
    charge_fixed REAL DEFAULT 0,
    requires_reference INTEGER DEFAULT 0,
    opens_cash_drawer INTEGER DEFAULT 0,
    is_active INTEGER DEFAULT 1,
    sort_order INTEGER DEFAULT 0,
    synced_at INTEGER
);

-- Stock Levels (for out-of-stock warning)
CREATE TABLE stock_levels (
    id TEXT PRIMARY KEY,
    outlet_id TEXT NOT NULL,
    product_id TEXT,
    product_variant_id TEXT,
    inventory_item_id TEXT,
    current_stock REAL DEFAULT 0,
    min_stock REAL DEFAULT 0,
    is_track_stock INTEGER DEFAULT 1,
    is_available INTEGER DEFAULT 1, -- computed: current_stock > 0 OR !is_track_stock
    synced_at INTEGER
);
CREATE INDEX idx_stock_product ON stock_levels(product_id);
CREATE INDEX idx_stock_variant ON stock_levels(product_variant_id);
CREATE INDEX idx_stock_outlet ON stock_levels(outlet_id);

-- Customers (LAZY LOAD - cached from search results)
CREATE TABLE customers (
    id TEXT PRIMARY KEY,
    code TEXT,
    name TEXT NOT NULL,
    phone TEXT,
    email TEXT,
    address TEXT,
    birth_date TEXT,
    gender TEXT,
    membership_level TEXT DEFAULT 'regular',
    membership_expires_at INTEGER,
    total_points REAL DEFAULT 0,
    total_spent REAL DEFAULT 0,
    total_visits INTEGER DEFAULT 0,
    is_active INTEGER DEFAULT 1,
    synced_at INTEGER,
    cached_at INTEGER -- when this customer was cached from search
);
CREATE INDEX idx_customers_phone ON customers(phone);
CREATE INDEX idx_customers_email ON customers(email);
CREATE INDEX idx_customers_cached ON customers(cached_at);

-- Floors (F&B)
CREATE TABLE floors (
    id TEXT PRIMARY KEY,
    outlet_id TEXT NOT NULL,
    name TEXT NOT NULL,
    description TEXT,
    sort_order INTEGER DEFAULT 0,
    is_active INTEGER DEFAULT 1,
    synced_at INTEGER
);

-- Tables (F&B)
CREATE TABLE tables (
    id TEXT PRIMARY KEY,
    floor_id TEXT NOT NULL,
    outlet_id TEXT NOT NULL,
    number TEXT NOT NULL,
    name TEXT,
    capacity INTEGER DEFAULT 4,
    position_x INTEGER DEFAULT 0,
    position_y INTEGER DEFAULT 0,
    width INTEGER DEFAULT 100,
    height INTEGER DEFAULT 100,
    shape TEXT DEFAULT 'rectangle',
    status TEXT DEFAULT 'available', -- available, occupied, reserved, dirty
    is_active INTEGER DEFAULT 1,
    synced_at INTEGER,
    FOREIGN KEY (floor_id) REFERENCES floors(id)
);

-- User permissions (cached)
CREATE TABLE user_permissions (
    permission_slug TEXT PRIMARY KEY,
    synced_at INTEGER
);

-- =====================================================
-- SYNC METADATA
-- =====================================================

CREATE TABLE sync_metadata (
    key TEXT PRIMARY KEY,
    value TEXT,
    updated_at INTEGER
);

-- Track last sync timestamps per entity type
-- key: 'last_sync_products', 'last_sync_customers', etc.
```

---

## 2. TRANSACTIONAL DATA (Queue for Sync)

### 2.1 Offline Queue Schema

```sql
-- =====================================================
-- OFFLINE TRANSACTION QUEUE
-- =====================================================

-- Main transaction queue
CREATE TABLE offline_transactions (
    id TEXT PRIMARY KEY, -- Client-generated UUID
    server_id TEXT, -- Assigned after sync
    outlet_id TEXT NOT NULL,
    pos_session_id TEXT,
    table_id TEXT,
    table_session_id TEXT,
    order_type TEXT DEFAULT 'dine_in',
    customer_id TEXT,
    user_id TEXT NOT NULL,

    transaction_number TEXT NOT NULL,
    type TEXT DEFAULT 'sale', -- sale, refund, void
    original_transaction_id TEXT,

    subtotal REAL NOT NULL,
    discount_amount REAL DEFAULT 0,
    tax_amount REAL DEFAULT 0,
    tax_percentage REAL,
    service_charge_amount REAL DEFAULT 0,
    service_charge_percentage REAL,
    rounding REAL DEFAULT 0,
    grand_total REAL NOT NULL,
    payment_amount REAL NOT NULL,
    change_amount REAL DEFAULT 0,

    points_earned REAL DEFAULT 0,
    points_redeemed REAL DEFAULT 0,

    notes TEXT,
    status TEXT DEFAULT 'pending_sync', -- pending_sync, synced, sync_error
    sync_error TEXT,
    retry_count INTEGER DEFAULT 0,

    created_at INTEGER NOT NULL,
    completed_at INTEGER,
    synced_at INTEGER
);
CREATE INDEX idx_offline_txn_status ON offline_transactions(status);
CREATE INDEX idx_offline_txn_outlet ON offline_transactions(outlet_id);

-- Transaction items
CREATE TABLE offline_transaction_items (
    id TEXT PRIMARY KEY,
    offline_transaction_id TEXT NOT NULL,
    product_id TEXT NOT NULL,
    product_variant_id TEXT,

    item_name TEXT NOT NULL, -- Snapshot
    item_sku TEXT,

    quantity REAL NOT NULL,
    unit_name TEXT,
    unit_price REAL NOT NULL,
    base_price REAL NOT NULL,
    variant_price_adjustment REAL DEFAULT 0,

    modifiers TEXT, -- JSON array
    modifiers_total REAL DEFAULT 0,

    cost_price REAL DEFAULT 0,
    discount_amount REAL DEFAULT 0,
    subtotal REAL NOT NULL,
    notes TEXT,

    FOREIGN KEY (offline_transaction_id) REFERENCES offline_transactions(id)
);
CREATE INDEX idx_offline_items_txn ON offline_transaction_items(offline_transaction_id);

-- Transaction payments
CREATE TABLE offline_transaction_payments (
    id TEXT PRIMARY KEY,
    offline_transaction_id TEXT NOT NULL,
    payment_method_id TEXT NOT NULL,
    payment_method_name TEXT NOT NULL, -- Snapshot
    amount REAL NOT NULL,
    charge_amount REAL DEFAULT 0,
    reference_number TEXT,
    approval_code TEXT,

    FOREIGN KEY (offline_transaction_id) REFERENCES offline_transactions(id)
);

-- Transaction discounts
CREATE TABLE offline_transaction_discounts (
    id TEXT PRIMARY KEY,
    offline_transaction_id TEXT NOT NULL,
    discount_id TEXT,
    discount_name TEXT NOT NULL,
    type TEXT NOT NULL,
    value REAL NOT NULL,
    amount REAL NOT NULL,
    transaction_item_id TEXT, -- NULL = order-level

    FOREIGN KEY (offline_transaction_id) REFERENCES offline_transactions(id)
);

-- Held orders (draft)
CREATE TABLE offline_held_orders (
    id TEXT PRIMARY KEY,
    server_id TEXT,
    outlet_id TEXT NOT NULL,
    table_id TEXT,
    customer_id TEXT,
    user_id TEXT NOT NULL,

    name TEXT, -- "Table A1" or "Customer Name"
    items TEXT NOT NULL, -- JSON array
    notes TEXT,

    status TEXT DEFAULT 'pending_sync',
    created_at INTEGER NOT NULL,
    synced_at INTEGER
);

-- POS Sessions
CREATE TABLE offline_sessions (
    id TEXT PRIMARY KEY,
    server_id TEXT,
    outlet_id TEXT NOT NULL,
    user_id TEXT NOT NULL,
    session_number TEXT,

    opening_cash REAL DEFAULT 0,
    closing_cash REAL,
    expected_cash REAL,
    cash_difference REAL,

    opened_at INTEGER NOT NULL,
    closed_at INTEGER,

    status TEXT DEFAULT 'open', -- open, closed
    sync_status TEXT DEFAULT 'pending_sync',
    synced_at INTEGER
);

-- Table sessions (F&B)
CREATE TABLE offline_table_sessions (
    id TEXT PRIMARY KEY,
    server_id TEXT,
    table_id TEXT NOT NULL,

    guest_count INTEGER DEFAULT 1,
    opened_at INTEGER NOT NULL,
    closed_at INTEGER,

    status TEXT DEFAULT 'active',
    sync_status TEXT DEFAULT 'pending_sync',
    synced_at INTEGER
);

-- Customer points changes (queue)
CREATE TABLE offline_customer_points (
    id TEXT PRIMARY KEY,
    customer_id TEXT NOT NULL,
    transaction_id TEXT,
    type TEXT NOT NULL, -- earned, redeemed
    points REAL NOT NULL,
    balance_before REAL,
    balance_after REAL,
    created_at INTEGER NOT NULL,
    sync_status TEXT DEFAULT 'pending_sync',
    synced_at INTEGER
);
```

### 2.2 Transaction Number Generation (Offline)

```dart
// Format: {outlet_code}-{YYMMDD}-{sequence}-{device_suffix}
// Example: OUT01-240115-0001-A

String generateOfflineTransactionNumber(String outletCode) {
  final date = DateTime.now();
  final dateStr = DateFormat('yyMMdd').format(date);

  // Get next sequence from local storage
  final sequence = _getNextSequence(outletCode, dateStr);

  // Device suffix to avoid collision between devices
  final deviceSuffix = _getDeviceSuffix(); // A, B, C, etc.

  return '$outletCode-$dateStr-${sequence.toString().padLeft(4, '0')}-$deviceSuffix';
}
```

---

## 3. SYNC API ENDPOINTS

### 3.1 Master Data Sync

```
GET /api/v1/mobile/sync/master
```

**Request:**
```json
{
    "outlet_id": "uuid",
    "last_sync": null // or ISO timestamp for delta
}
```

**Response:**
```json
{
    "success": true,
    "data": {
        "outlet": {
            "id": "uuid",
            "code": "OUT01",
            "name": "Outlet Pusat",
            "tax_percentage": 11,
            "service_charge_percentage": 5,
            "receipt_header": "...",
            "receipt_footer": "..."
        },
        "user": {
            "id": "uuid",
            "name": "John Cashier",
            "permissions": ["pos.access", "orders.create", "discounts.apply", ...]
        },
        "categories": [ ... ],
        "products": [ ... ],
        "product_variants": [ ... ],
        "variant_groups": [ ... ],
        "variant_options": [ ... ],
        "modifier_groups": [ ... ],
        "modifiers": [ ... ],
        "combos": [ ... ],
        "combo_items": [ ... ],
        "product_outlets": [ ... ],
        "stock_levels": [
            {
                "id": "uuid",
                "product_id": "uuid",
                "product_variant_id": null,
                "current_stock": 50,
                "min_stock": 10,
                "is_track_stock": true,
                "is_available": true
            }
        ],
        "discounts": [ ... ],
        "payment_methods": [ ... ],
        "floors": [ ... ],
        "tables": [ ... ]
    },
    "meta": {
        "sync_timestamp": "2024-01-15T10:00:00Z",
        "total_products": 500,
        "total_stock_items": 600
    }
}
```

> **Note**: `customers` tidak di-include dalam master sync. Customer di-fetch via lazy load saat search.

### 3.2 Delta Sync (Incremental)

```
GET /api/v1/mobile/sync/delta
```

**Request:**
```json
{
    "outlet_id": "uuid",
    "last_sync": "2024-01-15T10:00:00Z"
}
```

**Response:** Same structure, but only records with `updated_at > last_sync`

### 3.3 Customer Search (Lazy Load)

```
GET /api/v1/mobile/customers/search?q={query}
```

**Request:**
```
GET /api/v1/mobile/customers/search?q=john&phone=0812
```

**Response:**
```json
{
    "success": true,
    "data": [
        {
            "id": "uuid",
            "code": "CUST001",
            "name": "John Doe",
            "phone": "081234567890",
            "email": "john@email.com",
            "membership_level": "gold",
            "total_points": 5000,
            "total_spent": 2500000,
            "total_visits": 25
        }
    ],
    "meta": {
        "total": 3,
        "cached_until": "2024-01-16T10:00:00Z"
    }
}
```

> **Offline Behavior**:
> - Online: Search API, cache results locally
> - Offline: Search dari local cache saja
> - Cache expire: 24 jam (configurable)

### 3.4 Transaction Bulk Upload

```
POST /api/v1/mobile/transactions/bulk
```

**Request:**
```json
{
    "transactions": [
        {
            "client_id": "uuid",
            "outlet_id": "uuid",
            "pos_session_id": "uuid",
            "table_id": "uuid",
            "order_type": "dine_in",
            "customer_id": "uuid",
            "transaction_number": "OUT01-240115-0001-A",
            "type": "sale",

            "subtotal": 100000,
            "discount_amount": 10000,
            "tax_amount": 9900,
            "tax_percentage": 11,
            "service_charge_amount": 4500,
            "service_charge_percentage": 5,
            "grand_total": 104400,
            "payment_amount": 110000,
            "change_amount": 5600,

            "points_earned": 104,
            "points_redeemed": 0,

            "completed_at": "2024-01-15T10:30:00Z",

            "items": [
                {
                    "client_id": "uuid",
                    "product_id": "uuid",
                    "product_variant_id": "uuid",
                    "item_name": "Kopi Susu - Large",
                    "item_sku": "KOPI-001-L",
                    "quantity": 2,
                    "unit_price": 30000,
                    "base_price": 25000,
                    "variant_price_adjustment": 5000,
                    "modifiers": [
                        {"id": "uuid", "name": "Boba", "price": 5000}
                    ],
                    "modifiers_total": 5000,
                    "cost_price": 8000,
                    "subtotal": 70000
                }
            ],

            "payments": [
                {
                    "client_id": "uuid",
                    "payment_method_id": "uuid",
                    "amount": 110000,
                    "charge_amount": 0
                }
            ],

            "discounts": [
                {
                    "client_id": "uuid",
                    "discount_id": "uuid",
                    "discount_name": "Member 10%",
                    "type": "percentage",
                    "value": 10,
                    "amount": 10000
                }
            ]
        }
    ]
}
```

**Response:**
```json
{
    "success": true,
    "data": {
        "synced": [
            {
                "client_id": "uuid",
                "server_id": "uuid",
                "transaction_number": "OUT01-240115-0001"
            }
        ],
        "failed": [
            {
                "client_id": "uuid",
                "error": "Discount no longer valid",
                "code": "DISCOUNT_EXPIRED",
                "recoverable": true
            }
        ]
    },
    "meta": {
        "total": 1,
        "synced": 1,
        "failed": 0
    }
}
```

### 3.4 Session Sync

```
POST /api/v1/mobile/sessions/sync
```

**Request:**
```json
{
    "client_id": "uuid",
    "outlet_id": "uuid",
    "session_number": "SES-240115-001",
    "opening_cash": 500000,
    "closing_cash": 1500000,
    "opened_at": "2024-01-15T08:00:00Z",
    "closed_at": "2024-01-15T16:00:00Z",
    "status": "closed"
}
```

### 3.5 Table Status Sync

```
POST /api/v1/mobile/tables/status
```

**Request:**
```json
{
    "table_id": "uuid",
    "status": "occupied",
    "session": {
        "client_id": "uuid",
        "guest_count": 4,
        "opened_at": "2024-01-15T12:00:00Z"
    }
}
```

### 3.6 Customer Points Sync

```
POST /api/v1/mobile/customers/points/bulk
```

---

## 4. SYNC FLOW DIAGRAMS

### 4.1 Login Flow with Master Sync

```
┌──────────┐                    ┌──────────┐                    ┌──────────┐
│  Flutter │                    │  SQLite  │                    │  Laravel │
│   App    │                    │  Local   │                    │   API    │
└────┬─────┘                    └────┬─────┘                    └────┬─────┘
     │                               │                               │
     │  1. Login Request             │                               │
     │───────────────────────────────┼──────────────────────────────►│
     │                               │                               │
     │  2. Token + User Data         │                               │
     │◄──────────────────────────────┼───────────────────────────────│
     │                               │                               │
     │  3. Store Token               │                               │
     │──────────────────────────────►│                               │
     │                               │                               │
     │  4. Request Master Sync       │                               │
     │───────────────────────────────┼──────────────────────────────►│
     │                               │                               │
     │  5. Master Data               │                               │
     │◄──────────────────────────────┼───────────────────────────────│
     │                               │                               │
     │  6. Store Master Data         │                               │
     │──────────────────────────────►│                               │
     │                               │                               │
     │  7. Navigate to POS           │                               │
     │                               │                               │
```

### 4.2 Offline Transaction Flow

```
┌──────────┐                    ┌──────────┐                    ┌──────────┐
│  Flutter │                    │  SQLite  │                    │  Laravel │
│   App    │                    │  Local   │                    │   API    │
└────┬─────┘                    └────┬─────┘                    └────┬─────┘
     │                               │                               │
     │  1. Create Transaction        │                               │
     │──────────────────────────────►│                               │
     │                               │                               │
     │  2. Generate UUID + TxnNumber │                               │
     │◄──────────────────────────────│                               │
     │                               │                               │
     │  3. Store with status         │                               │
     │     'pending_sync'            │                               │
     │──────────────────────────────►│                               │
     │                               │                               │
     │  4. Print Receipt (offline)   │                               │
     │                               │                               │
     │  ═══════ LATER (Online) ═══════                               │
     │                               │                               │
     │  5. Check pending sync        │                               │
     │◄──────────────────────────────│                               │
     │                               │                               │
     │  6. Bulk upload               │                               │
     │───────────────────────────────┼──────────────────────────────►│
     │                               │                               │
     │  7. Server IDs                │                               │
     │◄──────────────────────────────┼───────────────────────────────│
     │                               │                               │
     │  8. Update status 'synced'    │                               │
     │     + store server_id         │                               │
     │──────────────────────────────►│                               │
     │                               │                               │
```

### 4.3 Shift Change Flow

```
┌──────────────────────────────────────────────────────────────────────┐
│                         CLOSE SHIFT FLOW                              │
├──────────────────────────────────────────────────────────────────────┤
│                                                                       │
│  1. User clicks "Close Shift"                                        │
│     │                                                                 │
│     ▼                                                                 │
│  2. Check pending transactions                                        │
│     │                                                                 │
│     ├── Has pending? ─────► Show warning: "X transactions pending"   │
│     │                                                                 │
│     ▼                                                                 │
│  3. Calculate session report                                          │
│     • Total sales                                                     │
│     • By payment method                                               │
│     • Expected cash                                                   │
│     │                                                                 │
│     ▼                                                                 │
│  4. Input closing cash                                                │
│     │                                                                 │
│     ▼                                                                 │
│  5. Force sync all pending                                            │
│     │                                                                 │
│     ├── Online? ─────────► Upload transactions                       │
│     │                       Upload session close                      │
│     │                       Delta sync master data                    │
│     │                                                                 │
│     ├── Offline? ────────► Queue session close                       │
│     │                       Show offline indicator                    │
│     │                                                                 │
│     ▼                                                                 │
│  6. Clear current session locally                                     │
│     │                                                                 │
│     ▼                                                                 │
│  7. Navigate to login or new shift                                    │
│                                                                       │
└──────────────────────────────────────────────────────────────────────┘
```

---

## 5. CONFLICT RESOLUTION

### 5.1 Transaction Number Collision

```dart
// Server validates uniqueness, client handles collision
// Strategy: Server assigns final number, client uses temporary

// Client-side:
String tempNumber = generateOfflineTransactionNumber();

// Server-side response may include:
{
    "client_id": "uuid",
    "server_id": "uuid",
    "assigned_number": "OUT01-240115-0042" // Server's authoritative number
}

// Client updates local record with server's number
```

### 5.2 Customer Points Reconciliation

```dart
// Store balance_before and balance_after for each operation
// Server validates and may adjust

// Conflict scenario:
// - Offline: Customer redeems 100 points (balance 500 → 400)
// - Meanwhile: Server-side redemption (balance 500 → 450)
// - Sync: Server detects balance_before mismatch

// Resolution:
{
    "client_id": "uuid",
    "status": "conflict",
    "action": "recalculate",
    "server_balance": 350, // 450 - 100
    "adjustment_applied": true
}
```

### 5.3 Discount Validation

```dart
// Server re-validates discounts on sync
// May reject if:
// - Discount expired
// - Usage limit exceeded
// - Conditions not met

// Response for failed validation:
{
    "client_id": "uuid",
    "status": "failed",
    "error": "DISCOUNT_EXPIRED",
    "message": "Discount 'PROMO10' has expired",
    "recoverable": false,
    "action": "remove_discount_and_recalculate"
}
```

---

## 6. DATA SIZE & PERFORMANCE

### 6.1 Estimated Data Sizes

| Data Type | Typical Count | Size/Record | Total |
|-----------|---------------|-------------|-------|
| Products | 500-2000 | ~2KB | 1-4MB |
| Variants | 1000-5000 | ~1KB | 1-5MB |
| Modifiers | 200-500 | ~0.5KB | 100-250KB |
| Categories | 20-100 | ~0.5KB | 10-50KB |
| Customers | 1000-10000 | ~0.5KB | 0.5-5MB |
| Discounts | 10-50 | ~1KB | 10-50KB |
| Tables | 20-100 | ~0.5KB | 10-50KB |
| **Total Initial** | - | - | **3-15MB** |

### 6.2 Optimization Strategies

```dart
// 1. Compress JSON payload (gzip)
// - Reduces 10MB to ~2MB

// 2. Pagination for large datasets
GET /api/v1/mobile/sync/customers?page=1&per_page=500

// 3. Selective sync by date
GET /api/v1/mobile/sync/delta?since=2024-01-15T00:00:00Z

// 4. Image lazy loading
// - Don't include images in sync
// - Load on-demand with caching

// 5. SQLite indices
// - Barcode lookup: O(log n)
// - Category filter: O(log n)
// - Search: FTS5 for full-text
```

### 6.3 Sync Performance Targets

| Operation | Target | Max Acceptable |
|-----------|--------|----------------|
| Initial full sync | 10-30s | 60s |
| Delta sync | 2-5s | 15s |
| Transaction upload | 1-2s | 5s |
| Batch upload (10 txns) | 3-5s | 15s |
| Product search (local) | <50ms | 100ms |
| Barcode lookup (local) | <20ms | 50ms |

---

## 7. ERROR HANDLING & RETRY

### 7.1 Retry Strategy

```dart
class SyncRetryStrategy {
  static const maxRetries = 5;
  static const baseDelay = Duration(seconds: 1);

  static Duration getDelay(int attempt) {
    // Exponential backoff: 1s, 2s, 4s, 8s, 16s (max 60s)
    final seconds = min(pow(2, attempt).toInt(), 60);
    return Duration(seconds: seconds);
  }

  static bool shouldRetry(SyncError error) {
    return error.isRecoverable && error.retryCount < maxRetries;
  }
}
```

### 7.2 Error Types

| Error Code | Description | Recoverable | Action |
|------------|-------------|-------------|--------|
| `NETWORK_ERROR` | No connection | Yes | Retry on reconnect |
| `AUTH_EXPIRED` | Token expired | Yes | Refresh token, retry |
| `VALIDATION_ERROR` | Invalid data | No | Show user, fix data |
| `DISCOUNT_EXPIRED` | Discount invalid | No | Remove, recalculate |
| `STOCK_UNAVAILABLE` | Out of stock | No | Show user alert |
| `SERVER_ERROR` | 500 error | Yes | Retry with backoff |
| `CONFLICT` | Data conflict | Partial | Apply resolution |

### 7.3 User Feedback

```dart
// Sync status indicator in UI
enum SyncStatus {
  synced,      // ✓ Green dot
  syncing,     // ↻ Blue spinner
  pending,     // ● Yellow dot (has pending)
  error,       // ✕ Red dot (sync failed)
  offline,     // ○ Gray dot (no connection)
}

// Show pending count
"3 transactions pending sync"

// Error notification
"Sync failed: Network error. Will retry automatically."
```

---

## 8. IMPLEMENTATION CHECKLIST

### Backend (Laravel) - POS Offline Support

- [ ] Create `MobileSyncController`
- [ ] Implement `/sync/master` endpoint
- [ ] Implement `/sync/delta` endpoint
- [ ] Implement `/transactions/bulk` endpoint
- [ ] Implement `/sessions/sync` endpoint
- [ ] Implement `/customers/points/bulk` endpoint
- [ ] Add `synced_at` to all master data models
- [ ] Add `updated_at` index for delta queries
- [ ] Implement conflict resolution logic
- [ ] Add transaction number validation
- [ ] Add gzip compression middleware

### Backend (Laravel) - Waiter App Real-time

- [ ] Setup Laravel Reverb / Pusher
- [ ] Create WebSocket events for table status
- [ ] Create WebSocket events for order updates
- [ ] Create WebSocket events for KDS notifications
- [ ] Implement `/tables/status` endpoint (REST + broadcast)

### Flutter POS - Offline Infrastructure

- [ ] Setup SQLite database (sqflite/drift)
- [ ] Create all local tables schemas
- [ ] Implement `SyncService`
- [ ] Implement `OfflineQueueService`
- [ ] Implement `TransactionNumberGenerator`
- [ ] Create sync status provider
- [ ] Implement retry strategy
- [ ] Add connectivity monitoring
- [ ] Create background sync worker
- [ ] Implement conflict resolution UI
- [ ] Add sync progress indicator
- [ ] Implement data migration system

### Flutter Waiter - Real-time Infrastructure

- [ ] Setup WebSocket client (web_socket_channel)
- [ ] Implement auto-reconnect logic
- [ ] Create event handlers for table updates
- [ ] Create event handlers for order status
- [ ] Implement connectivity indicator UI
- [ ] Show offline warning/block actions

---

# IMPLEMENTATION STATUS

## Backend API Status (Laravel)

| Phase | Component | Status | Notes |
|-------|-----------|--------|-------|
| A | Foundation | ✅ Complete | Sanctum, Routes, Base Controller |
| B.1 | Auth API | ✅ Complete | Login, PIN Login, Logout, Profile |
| B.2 | Outlet API | ✅ Complete | List, Switch |
| B.3 | Product API | ✅ Complete | List, Search, Barcode, Detail |
| B.4 | Category API | ✅ Complete | List, Products |
| B.5 | Transaction API | ✅ Complete | Calculate, Checkout, Void, Refund |
| B.6 | Customer API | ✅ Complete | CRUD, Search, Transactions |
| B.7 | Payment Method API | ✅ Complete | List, Types, Calculate Charge |
| B.8 | Discount API | ✅ Complete | List, Validate |
| B.9 | Session API | ✅ Complete | Open, Close, Report |
| B.10 | Held Order API | ✅ Complete | CRUD, Restore with OpenAPI |
| B.11 | Authorization API | ✅ Complete | PIN verify, Check, Managers, Settings, Logs |
| C | Table Management | ✅ Complete | Floors, Tables, Sessions, Move |
| D | Mobile Sync API | 🔄 Partial | Master sync exists |

## API Documentation (SSOT)

> **PENTING: Single Source of Truth**
>
> | Resource | URL |
> |----------|-----|
> | **Swagger UI** | `{BASE_URL}/api/documentation` |
> | **OpenAPI JSON** | `{BASE_URL}/docs` |
>
> Semua API documentation ada di Swagger. File ini hanya berisi:
> - Architecture overview
> - Implementation checklist
> - Offline-first strategy

All APIs include comprehensive OpenAPI 3.0 annotations (PHP 8 attributes).

## Next Steps

1. **Mobile Sync API Enhancement** - Delta sync, bulk upload optimization
2. **Real-time Integration** - Laravel Reverb for Waiter App
3. **Flutter POS App** - Start mobile development
4. **KDS Integration** - Kitchen Display System

---

*Document Version: 4.0 (SSOT Update)*
*Last Updated: February 2026*
*POS: Offline-First | Waiter: Online Required*
*API Docs: Swagger `{BASE_URL}/api/documentation`*
