Portal quản lý bằng cách tải các đơn hàng từ các Woocommerce store định kỳ mỗi x giờ thông qua API. Gồm toàn bộ đơn hàng của hệ thống Wordpress và Lunar

Chi tiết tài liệu cho end user Portal tại: https://portal-docs-9jp.pages.dev/

Hiện tại có 3 instance (được gọi là team, cấu hình trong file .env) của Portal đang được sử dụng:

  1. TDA
  2. KDDA
  3. NDA

Backoffice TDA: https://app.woocommerceinvoice.com/backoffice Repo: https://github.com/swebvn/portal

Architecture & Design

Tech stack

Laravel 9 Laravel Nova v3 (admin)

CI/CI

  • CD đang được quản lý bởi FlashPanel, push lên main branch sẽ trigger deploy tự động

Core Components

1. Application Layer (Actions)

Uses Laravel Actions pattern for reusable, testable business logic:

// Example: Actions are single-purpose classes
app/Actions/
├── Orders/
   ├── SaveOrderFromData.php
   ├── FetchOrdersFromStore.php
   └── UpdateOrderStatus.php
├── Invoices/
   ├── FetchInvoicesFromEnvoice.php
   └── PairInvoiceWithOrder.php
├── Products/
   └── FetchProductsFromStore.php
└── Shopify/
    ├── PushOrderToShopify.php
    └── SyncProductToShopify.php

Benefits:

  • Single Responsibility Principle
  • Easy to test in isolation
  • Reusable across jobs, controllers, and commands
  • Can be dispatched as jobs or HTTP controllers

2. Admin Panel (Laravel Nova)

Docs: https://github.com/laravel/nova-orion-docs/blob/main/3.x

Custom Nova resources provide a powerful admin interface:

app/Nova/
├── Order.php              # Order management
├── Orders/
│   ├── PendingOrder.php   # Pending orders view
│   ├── ProcessingOrder.php
│   └── ShippedOrder.php
├── Product.php
├── Invoice.php
├── Store.php
└── Filters/               # Custom filters

Data Flow & Request Lifecycle

1. Order Processing Flow

graph TD
    A[Schedule every x hours] --> B[Sync orders]
    B --> C[SaveOrderFromData Action]
    C --> D[Store in Database]
    D --> E{Has Invoice?}
    E -->|No| F[Queue: Fetch Invoice]
    E -->|Yes| G[Pair Invoice]
    G --> H[Send Confirmation Email]
    F --> G
    H --> I{Shopify Enabled?}
    I -->|Yes| J[Queue: Push to Shopify]
    I -->|No| K[Complete]
    J --> K

2. Invoice Reconciliation Flow (For Envoice)

graph TD
    A[Scheduled Job] --> B[Fetch Invoices from Envoice]
    B --> C[For Each Invoice]
    C --> D{Match Order?}
    D -->|Found| E[Pair Invoice with Order]
    D -->|Not Found| F[Log for Manual Review]
    E --> G[Update Order Status]
    G --> H[Send Customer Email]

3. Shopify Sync Flow

graph TD
    A[Order Marked Paid] --> B{Shopify Enabled?}
    B -->|Yes| C[Queue: PushOrderToShopify]
    B -->|No| Z[End]
    C --> D[Create Shopify Order]
    D --> E{Success?}
    E -->|Yes| F[Save shopify_id]
    E -->|No| G[Alert to Telegram]
    F --> H[Sync Line Items]
    H --> I[Sync Product Images]

Technology Stack

Backend

TechnologyVersionPurpose
PHP8.1+Primary language
Laravel9.xWeb framework
MySQL8.0+Primary database
Redis6.xCache & queues

Frontend

TechnologyPurpose
Laravel NovaAdmin panel UI

Third-Party Services

ServicePurpose
AWS SESTransactional emails
BunnyCDNImage storage & CDN
Telegram Bot APINotifications
WooCommerce REST APIStore integration
Shopify APIStore sync
Envoice APIInvoice processing

Key Laravel Packages

{
  "laravel/nova": "Admin panel",
  "laravel/horizon": "Queue monitoring",
  "spatie/laravel-activitylog": "Audit logging",
  "spatie/laravel-backup": "Database backups",
  "spatie/laravel-webhook-client": "Webhook handling",
  "lorisleiva/laravel-actions": "Action pattern",
  "bensampo/laravel-enum": "Type-safe enums",
  "signifly/laravel-shopify": "Shopify SDK",
  "maatwebsite/laravel-nova-excel": "Excel exports"
}

Design Patterns

1. Action Pattern

Single-purpose classes for business logic:

class SaveOrderFromData extends Action
{
    public function handle(array $data, Store $store): Order
    {
        return Order::updateOrCreate(
            ['wp_id' => $data['id'], 'store_id' => $store->id],
            $this->transformData($data)
        );
    }
}

2. Enum Pattern

Type-safe status values:

use App\Enums\OrderStatus;
 
$order->status = OrderStatus::Processing;
$order->status->is(OrderStatus::Shipped); // true/false

Scalability Considerations

Current Architecture

  • Horizontal Scaling - Stateless application servers
  • Queue Workers - Multiple workers for background processing

Monitoring & Observability

Logging

  • Application Logs - storage/logs/laravel.log
  • Activity Logs - Database-based with spatie/laravel-activitylog
  • Queue Metrics - Laravel Horizon dashboard

Alerts

  • Telegram Notifications - Critical errors and events
  • Failed Jobs - Automatic retry with exponential backoff
  • API Health Checks - Store API status monitoring