# Architecture Overview

## Full System Diagram

```
┌───────────────────────────────────────────────────────────────────────────────────┐
│                              Orderbuddy Portal (Laravel 12)                         │
│                              https://icard.orderbuddy.tech                          │
│                                                                                    │
│  ┌──────────────────────────────────────────────────────────────────────────────┐ │
│  │                        ADMIN DASHBOARD (Restaurant Owners)                    │ │
│  │   Auth: Laravel Breeze (session + email verification)                         │ │
│  │   Model: App\Models\User                                                      │ │
│  │                                                                                │ │
│  │   /dashboard         — Overview + analytics                                    │ │
│  │   /live-orders       — Real-time cross-branch orders                           │ │
│  │   /reports           — X/Z/Sales reports (shareable)                           │ │
│  │   /brands            — Multi-brand management                                  │ │
│  │   /branches          — Branch CRUD + DB switching                              │ │
│  │   /staff             — Staff management                                        │ │
│  │   /stock/list        — Inventory view                                          │ │
│  │   /notifications     — Push notification management (FCM V1)                   │ │
│  │   /cardmachine/*     — Card terminal accounts + terminals                      │ │
│  └──────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                    │
│  ┌──────────────────────────────────────────────────────────────────────────────┐ │
│  │                     CUSTOMER PORTAL (Mobile App WebView)                       │ │
│  │   Auth: Firebase ID token → session (customer.auth middleware)                 │ │
│  │   Model: App\Models\Customer                                                   │ │
│  │                                                                                │ │
│  │   GET  /mobile/mobile-login.php   — Firebase token validation + session        │ │
│  │   POST /mobile/api/save_fcm_token.php — Device FCM token registration          │ │
│  │   POST /mobile/api/debug_log.php  — Mobile app diagnostics                     │ │
│  │   GET  /portal                    — Customer home (loyalty, features)           │ │
│  │   POST /portal/logout             — Sign out customer session                  │ │
│  └──────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                    │
│  ┌──────────────────────────────────────────────────────────────────────────────┐ │
│  │                         CARD MACHINE API (POS Payments)                        │ │
│  │   Auth: Custom HMAC-SHA256 JWT (12-hour expiry)                               │ │
│  │                                                                                │ │
│  │   POST /api/cardmachine/payment — Route-based dispatch (all operations)        │ │
│  └──────────────────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────────────┘
          │                         │                           │
          │                         │                           │
          ▼                         ▼                           ▼
┌─────────────────┐    ┌─────────────────────┐    ┌────────────────────────┐
│  PAX A920       │    │   Flutter Mobile     │    │   Firebase / Google    │
│  Terminal App   │    │   App (Customer)     │    │                        │
│                 │    │                      │    │  • Identity Toolkit    │
│  Pushy push ←──│    │  Firebase Auth ──────│───▶│  • FCM V1 API          │
│  libpositive   │    │  WebView → /portal   │    │  • Service Account JWT │
│  Card reader   │    │  FCM token register  │    │                        │
└─────────────────┘    └─────────────────────┘    └────────────────────────┘
```

---

## Authentication Architecture (Two Separate Systems)

| Aspect | Admin Dashboard | Customer Portal |
|--------|----------------|-----------------|
| **Users** | Restaurant owners/managers | Mobile app customers |
| **Auth method** | Laravel Breeze (email + password) | Firebase Auth (Google/Apple/email) |
| **Middleware** | `auth` + `verified` | `customer.auth` |
| **Model** | `App\Models\User` | `App\Models\Customer` |
| **Session key** | `login_web_*` (Laravel guard) | `customer_id` (custom session) |
| **DB table** | `users` | `customers` |
| **Isolation** | Completely independent — no cross-interference |

---

## Card Machine Payment Flow

```
┌─────────────────────┐       ┌──────────────────────────┐       ┌─────────────────────┐
│   POS / Checkout    │       │   Orderbuddy Portal      │       │  PAX A920 Terminal  │
│   (initiates tx)    │──────▶│   (Laravel Backend)      │──────▶│  (Android App)      │
│                     │  API  │                          │ Pushy │                     │
│                     │◀──────│  POST /api/payment       │  Push │  cutpay-pos-bridge  │
│                     │       │                          │       │                     │
└─────────────────────┘       └──────────────────────────┘       └─────────────────────┘
                                        │                                   │
                                        ▼                                   ▼
                              ┌──────────────────┐               ┌──────────────────┐
                              │    Database       │               │   libpositive    │
                              │  payment_account  │               │   (PAX SDK)      │
                              │  payment_terminal │               │   Card Reader    │
                              │  payment_transaction│             └──────────────────┘
                              └──────────────────┘
```

### Transaction Flow

1. **POS initiates payment** → `POST /api/payment` with `route=initiate_transaction`, amount, terminal
2. **Backend creates transaction** → inserts into `payment_transaction` with status `new`
3. **Backend sends push** → Pushy notification to terminal's `messaging_id`
4. **Terminal receives push** → `PushReceiver` broadcasts `com.new.transaction`
5. **Terminal processes** → `PosBridgeActivity` receives broadcast, calls `update_transaction_status("received")` then `("processing")`
6. **libpositive executes** → `TransactionHandler.normalTransaction()` triggers PAX card reader
7. **Result received** → `TransactionStatusReceiver` gets `TRANSACTION_RESULT_EVENT`
8. **Terminal reports back** → Sends `update_transaction_status("completed")`, `update_status_flow(events)`, `save_transaction_result(json)`, then `update_transaction_status("approved"/"failed")`
9. **POS polls result** → `get_status_flow` to check progress in real-time

### Terminal Setup Flow

1. **Login** → `get_token` with account credentials
2. **List terminals** → `get_terminals`
3. **Create terminal** → `register_terminal` / `create_terminal`
4. **Select terminal** → User taps terminal in list
5. **Register messaging ID** → `update_terminal` with Pushy device token
6. **Verify** → `send_verify_terminal` sends push with verification secret
7. **Confirmed** → Terminal receives `com.verification.success` broadcast → enters kiosk mode

---

## Push Notification System (FCM V1 — Admin to Customers)

```
Admin Dashboard                    Laravel Backend                  Firebase / Devices
─────────────────                  ──────────────                  ──────────────────
  Create Notification        →    NotificationController@store
  (title, message, target)         Saves to `notifications` table
                                   (status: draft)
                                   
  Click "Send"               →    NotificationController@send
                                   │
                                   ├─ target_type: all_customers
                                   │     → FCMNotificationService::sendToAllCustomers()
                                   │        Queries ALL active devices
                                   │
                                   └─ target_type: store_customers
                                         → FCMNotificationService::sendToStoreCustomers()
                                            Queries devices for specific store_app_id
                                   
                                   For each device:
                                   │
                                   ├─ getAccessToken()
                                   │     JWT assertion → Google OAuth2 endpoint
                                   │     → Bearer access token (service account)
                                   │
                                   ├─ POST fcm.googleapis.com/v1/projects/{id}/messages:send
                                   │     Payload includes:
                                   │     • notification (title + body)
                                   │     • data (notification_id, sent_at)
                                   │     • android (high priority, channel_id)
                                   │     • apns (priority 10, bundle_id topic)
                                   │
                                   ├─ On success → NotificationRecipient (status: sent)
                                   ├─ On 404    → Deactivate stale token
                                   └─ On error  → NotificationRecipient (status: failed)
                                   
                                   Update notification:
                                   (recipient_count, success_count, failed_count, status, sent_at)
```

### FCM Authentication Method

```php
// Service account JSON → JWT → Access Token
1. Load service_account.json (private key + client_email)
2. Build JWT: {iss: client_email, scope: firebase.messaging, aud: oauth2.googleapis.com/token}
3. Sign with RS256 (private key)
4. POST https://oauth2.googleapis.com/token (grant_type=jwt-bearer, assertion=JWT)
5. Response: {access_token: "ya29.xxx..."}
6. Use: Authorization: Bearer ya29.xxx...
```

---

## Mobile App Authentication Flow

```
Flutter App                        Laravel Backend                  Google Identity Toolkit
───────────                        ──────────────                  ──────────────────────
  1. User signs in (Firebase)
  2. Gets Firebase ID token
  
  3. POST /mobile/api/save_fcm_token.php  →  MobileApiController@registerDevice
     {firebase_uid, fcm_token,                  • Upserts Customer record
      device_type, store_app_id}                • Upserts CustomerDevice (FCM token)
                                                • Deactivates duplicate tokens
                                          ←  {success: true, token_saved_prefix: "..."}
  
  4. WebView loads:
     GET /mobile/mobile-login.php     →  MobileAuthController@loginBridge
     ?token=FIREBASE_ID_TOKEN              │
     &store_app_id=friezandburgz           ├─ Validates token format + store_app_id
                                           ├─ POST identitytoolkit.googleapis.com   →  Validates token
                                           │       /v1/accounts:lookup?key=API_KEY     Returns user data
                                           ├─ Upserts Customer (firebase_uid + store)
                                           ├─ Sets session: customer_id, firebase_uid,
                                           │                 store_app_id, customer_name
                                           └─ Redirect 302 → /portal
  
  5. WebView shows /portal           →  PortalHomeController@index
     (customer.auth middleware)             • Checks session(customer_id)
                                           • Loads Customer model
                                           • Renders mobile home view
```

---

## Key Components

### Backend (This Repo)

#### Admin Dashboard Controllers
| Controller | Purpose |
|-----------|---------|
| `DashboardController` | Main overview + analytics |
| `BrandController` | Multi-brand CRUD |
| `BranchController` | Branch CRUD + DB config |
| `NotificationController` | FCM push notification CRUD + send |
| `CardmachineAccountController` | Card machine account CRUD |
| `CardmachineTerminalController` | Terminal CRUD |
| `CardmachineLogController` | Log viewer |
| `ReportController` | X/Z/Sales reports |
| `StaffController` | Staff management |
| `StockController` | Inventory view |
| `LiveOrderController` | Real-time order monitoring |

#### Mobile/Customer Controllers
| Controller | Purpose |
|-----------|---------|
| `Mobile\MobileApiController` | Device registration + debug logs |
| `Mobile\MobileAuthController` | Firebase token → session bridge |
| `Mobile\PortalHomeController` | Customer-facing portal pages |

#### API Controllers
| Controller | Purpose |
|-----------|---------|
| `Api\CardmachineController` | Route-based card machine operations |

#### Services
| Service | Purpose |
|---------|---------|
| `FirebaseAuthService` | Validates Firebase ID tokens via Google API |
| `FCMNotificationService` | Sends push via FCM V1 API (OAuth2 service account) |
| `BranchConnectionManager` | Dynamic multi-database connection switching |
| `CogsCalculator` | Cost of goods calculations |

#### Middleware
| Middleware | Alias | Purpose |
|-----------|-------|---------|
| `SetLocale` | (web stack) | i18n language switching |
| `CustomerAuth` | `customer.auth` | Protects `/portal` routes via session |

### Diagnostics
- Web log viewer: `https://icard.orderbuddy.tech/cardmachine/logs`
- JSON endpoint: `https://icard.orderbuddy.tech/cardmachine/logs/api?date=YYYY-MM-DD&lines=200&filter=push`
- Mobile debug logs: `storage/logs/mobile-debug-{Y-m-d}.log`

### Android Terminal App (cutpay-pos-bridge-pax-A920)
- `Activities/LoginActivity` — Account authentication
- `Activities/TerminalsActivity` — Terminal selection
- `Activities/NewTerminalActivity` — Terminal registration
- `Activities/VerifyingActivity` — Push verification
- `Activities/PosBridgeActivity` — Main kiosk mode, transaction handling
- `API/PosBridgeAPI` — API client wrapper
- `API/ExecutorApiClient` — HTTP POST client (thread pool)
- `API/DeliveryQueue` — Retry queue for failed API calls
- `BroadcasrReceivers/PushReceiver` — Pushy push notification handler
- `Pax/Receiver/TransactionStatusReceiver` — libpositive result receiver
- `Utils/TransactionHandler` — libpositive transaction executor
- `Constants/API/Routes` — Endpoint URLs and secrets

---

## Database Schema

### Central Database (Portal)

| Table | Purpose | Key Fields |
|-------|---------|------------|
| `users` | Restaurant owners/managers | name, email, password |
| `brands` | Multi-brand entities | owner_user_id, name, default_db_* |
| `branches` | Store locations | brand_id, name, db_name, db_host |
| `user_branch_access` | User ↔ Branch pivot | user_id, branch_id |
| `customers` | Mobile app users (Firebase) | brand_id, firebase_uid, store_app_id, name, email, loyalty_points |
| `customer_devices` | FCM push tokens | customer_id, fcm_token, device_type, is_active |
| `notifications` | Push notification records | user_id, title, message, target_type, store_app_id, status |
| `notification_recipients` | Per-device delivery tracking | notification_id, customer_device_id, status, error_message |
| `payment_account` | Card machine accounts | account_id, user_id, password |
| `payment_terminal` | Card machine terminals | account_id, terminal_id, terminal_name, messaging_id |
| `payment_transaction` | Card payments | account_id, terminal_id, amount, status, result |
| `report_shares` | Shareable report tokens | token, user_id, report_type |

### Relationships

```
User ─┬─ hasMany → Brand (owner_user_id)
      ├─ belongsToMany → Branch (via user_branch_access)
      └─ hasMany → Notification (user_id)

Brand ─┬─ hasMany → Branch
       └─ hasMany → Customer (brand_id)

Customer ─── hasMany → CustomerDevice

Notification ─── hasMany → NotificationRecipient
NotificationRecipient ─── belongsTo → CustomerDevice
```

---

## Security Model

- **Admin Dashboard Auth**: Laravel Breeze session-based auth with email verification
- **Customer Portal Auth**: Firebase ID token validation → custom session (completely separate)
- **Card Machine API Auth**: Custom HMAC-SHA256 JWT (12-hour expiry)
- **Shared Secrets**: `API_SECRET` for login, `VERIFICATION_SECRET` for terminal verification push
- **Token Sources**: `Authorization: Bearer <token>` header (preferred) or legacy `params.token`
- **Push Notifications (Terminals)**: Pushy API key server-side only
- **Push Notifications (Customers)**: Firebase service account JSON (OAuth2 Bearer token)
- **FCM Token Hygiene**: Auto-deactivate stale tokens on HTTP 404 response from FCM

---

## Environment Variables

### Firebase & Mobile
```env
FIREBASE_PROJECT_ID=restaurant-loyalty-app-cdd0a
FIREBASE_WEB_API_KEY=AIzaSyBzQ7A-lyse6PQ4yFwFo7QWFeRrdzUgOSI
FIREBASE_IDENTITY_TOOLKIT_URL=https://identitytoolkit.googleapis.com/v1/accounts:lookup
FIREBASE_HTTP_TIMEOUT_SECONDS=10
FIREBASE_SERVICE_ACCOUNT_PATH=/path/to/service-account.json
FIREBASE_IOS_BUNDLE_ID=com.CutPay.FriezAndBurgz
MOBILE_PORTAL_DEFAULT_STORE=friezandburgz
```

### Card Machine
```env
CARDMACHINE_PUSHY_API_KEY=b312c...
CARDMACHINE_TOKEN_SECRET=acbeaf89-d3c4-43c1-b98a-cf95c711fd6d
CARDMACHINE_API_SECRET=adcbba30-e793-4b80-baf3-0f855a89c8c6
CARDMACHINE_VERIFICATION_SECRET=d7fc345d-61e3-4b63-89ca-986fe4dc9cf1
```
