{"id":47237174,"url":"https://github.com/malikad778/nexus-inventory","last_synced_at":"2026-03-13T23:18:29.259Z","repository":{"id":339372290,"uuid":"1161642948","full_name":"malikad778/nexus-inventory","owner":"malikad778","description":"The ultimate Laravel package for multi-channel inventory synchronization. Connect Shopify, WooCommerce, Amazon, and Etsy to Laravel with real-time webhooks, job queues, and a unified API.","archived":false,"fork":false,"pushed_at":"2026-02-24T05:56:11.000Z","size":73,"stargazers_count":11,"open_issues_count":0,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-24T11:54:57.625Z","etag":null,"topics":["amazon-sp-api","dropshipping","ecommerce","etsy-api","inventory-managemen","laravel","laravel-package","marketplace","multi-channel","package","php","queue-jobs","shopify","synchronization","woocommerce"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/malikad778.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"vendor_name"}},"created_at":"2026-02-19T10:51:22.000Z","updated_at":"2026-02-24T10:43:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/malikad778/nexus-inventory","commit_stats":null,"previous_names":["malikad778/laravel-nexus","malikad778/nexus-inventory"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/malikad778/nexus-inventory","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malikad778%2Fnexus-inventory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malikad778%2Fnexus-inventory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malikad778%2Fnexus-inventory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malikad778%2Fnexus-inventory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/malikad778","download_url":"https://codeload.github.com/malikad778/nexus-inventory/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malikad778%2Fnexus-inventory/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30479134,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-13T20:45:58.186Z","status":"ssl_error","status_checked_at":"2026-03-13T20:45:20.133Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amazon-sp-api","dropshipping","ecommerce","etsy-api","inventory-managemen","laravel","laravel-package","marketplace","multi-channel","package","php","queue-jobs","shopify","synchronization","woocommerce"],"created_at":"2026-03-13T23:18:26.897Z","updated_at":"2026-03-13T23:18:29.254Z","avatar_url":"https://github.com/malikad778.png","language":"PHP","funding_links":["https://github.com/sponsors/vendor_name"],"categories":[],"sub_categories":[],"readme":"# Nexus Inventory\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/malikad778/nexus-inventory.svg?style=flat-square)](https://packagist.org/packages/malikad778/nexus-inventory)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/malikad778/nexus-inventory/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/malikad778/nexus-inventory/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/malikad778/nexus-inventory/fix-php-code-style-issues.yml?branch=main\u0026label=code%20style\u0026style=flat-square)](https://github.com/malikad778/nexus-inventory/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/malikad778/nexus-inventory.svg?style=flat-square)](https://packagist.org/packages/malikad778/nexus-inventory)\n[![License](https://img.shields.io/packagist/l/malikad778/nexus-inventory.svg?style=flat-square)](LICENSE.md)\n\n**A unified, driver-based Laravel package for synchronizing products and inventory across multiple e-commerce channels — Shopify, WooCommerce, Amazon SP-API, and Etsy.**\n\nNexus Inventory is not a SaaS platform. It is a drop-in Composer package that lives inside your Laravel application, giving you full code-level control over every sync, every webhook, and every rate limit — for free.\n\n---\n\n## Why Nexus Inventory?\n\nThe multi-channel commerce problem is real and expensive. When a product sells on Amazon, your Shopify stock must decrement in seconds — not minutes. Every channel has its own API, its own authentication scheme, its own rate limits, and its own webhook signature format. Solving this from scratch takes months.\n\nThe existing options leave developers stuck:\n\n| Option | Problem |\n|---|---|\n| **SaaS (Cin7, Linnworks)** | $300–$500/month, no code control, no custom sync logic |\n| **DIY integrations** | 6–12 weeks per channel, brittle, non-reusable |\n| **Channel-specific packages** | Siloed — no unified DTO, no cross-channel orchestration |\n\n**Nexus Inventory fills the gap.** It provides a production-grade, extensible foundation — a unified driver interface, a fluent API, distributed rate limiting, secure webhook handling, job batching, and a real-time dashboard — all installable in minutes via Composer.\n\n---\n\n## Features\n\n### 🔌 Driver-Based Architecture\nEvery channel implements the same `InventoryDriver` interface. Your application code never touches a channel SDK directly. Add support for a new channel (eBay, TikTok Shop, Walmart) by implementing one interface and registering one class — zero changes to the core.\n\n```php\n// Identical API regardless of channel\nNexus::driver('shopify')-\u003efetchProduct($remoteId);\nNexus::driver('amazon')-\u003eupdateInventory($remoteId, 42);\nNexus::driver('woocommerce')-\u003egetProducts(now()-\u003esubHours(24));\n```\n\n### 🔄 Fluent Sync API\nA clean, chainable builder API for common sync operations:\n\n```php\n// Push a single inventory update to specific channels\nNexus::product($product)\n    -\u003eupdateInventory(quantity: 42)\n    -\u003esync(['shopify', 'amazon']);\n\n// Bulk sync your entire catalog across all channels\n$batch = Nexus::catalog($products)-\u003esyncAll();\n\n// Monitor batch progress\n$status = Nexus::batch($batchId)-\u003estatus();\n```\n\n### ⚡ Distributed Rate Limiting\nEach channel enforces API rate limits at the key level — not the server level. Run 10 queue workers and a naive implementation blows through your API quota in seconds. Nexus solves this with a **Token Bucket algorithm backed by atomic Redis Lua scripting**, race-condition-free across any number of concurrent workers.\n\n| Channel | Rate Limit | Burst Capacity |\n|---|---|---|\n| Shopify | 2 req/sec | 40 tokens |\n| WooCommerce | 25 req/sec | 100 tokens |\n| Amazon SP-API | 1 req/sec | 10 tokens |\n| Etsy | 10 req/sec | 50 tokens |\n\n### 📦 Three-Layer Job Architecture\nSyncing 10,000 SKUs across 4 channels means 40,000 API calls. Nexus handles this with a structured job hierarchy using Laravel's `Bus::batch()`:\n\n- **`CatalogSyncJob`** — Orchestrator. Partitions the catalog, creates the batch, registers `then()` and `catch()` callbacks.\n- **`ChannelSyncBatchJob`** — Channel executor. Acquires rate limit tokens, dispatches push jobs, fires lifecycle events.\n- **`PushInventoryJob`** — Atomic unit per SKU/channel pair. Implements `ShouldBeUnique` to prevent duplicate in-flight jobs.\n\n### 🔒 Secure Unified Webhook Receiver\nA single route handles all four channels. Every request is cryptographically verified before processing:\n\n- **Shopify** — `X-Shopify-Hmac-Sha256` — HMAC-SHA256 (base64)\n- **WooCommerce** — `X-WC-Webhook-Signature` — HMAC-SHA256 (base64)\n- **Amazon** — `X-AMZ-SNS-Signature` — RSA-SHA1 via AWS SNS (certificate downloaded, domain-validated, cached)\n- **Etsy** — `X-Etsy-Signature` — HMAC-SHA256 (hex)\n\n```\nPOST https://your-app.com/nexus/webhooks/shopify\nPOST https://your-app.com/nexus/webhooks/woocommerce\nPOST https://your-app.com/nexus/webhooks/amazon\nPOST https://your-app.com/nexus/webhooks/etsy\n```\n\n### 📡 Standardized Event System\nOnce a webhook is verified, a single `InventoryUpdated` event fires — regardless of which channel triggered it. Write one listener to handle all channels:\n\n```php\nclass PropagateInventoryToOtherChannels\n{\n    public function handle(InventoryUpdated $event): void\n    {\n        $others = ['shopify', 'amazon', 'woocommerce', 'etsy'];\n\n        Nexus::product($event-\u003eproduct)\n            -\u003eupdateInventory($event-\u003enewQuantity)\n            -\u003esync(array_diff($others, [$event-\u003echannel]));\n    }\n}\n```\n\nFull lifecycle hooks at every stage of the pipeline:\n\n| Event | Fires When |\n|---|---|\n| `BeforeInventorySync` | Before each channel push — ideal for safety stock rules |\n| `AfterInventorySync` | On success — notify WMS, trigger downstream workflows |\n| `InventorySyncFailed` | On permanent failure after retries — alert Slack, PagerDuty |\n| `InventoryUpdated` | After every verified webhook |\n| `WebhookReceived` | Before processing — full audit logging |\n| `ChannelThrottled` | When a channel API is throttling — broadcasts via Laravel Reverb |\n| `ProductImported` | When a product is fetched from a channel during catalog import |\n\n### 🗄️ Polymorphic Channel Mapping\nAny Eloquent model becomes syncable with one trait — no schema changes to your existing tables:\n\n```php\nuse Malikad778\\\\LaravelNexus\\Traits\\Syncable;\n\nclass Product extends Model\n{\n    use Syncable;\n    // Adds: $product-\u003echannelMappings(), $product-\u003esyncTo('shopify')\n}\n```\n\nThe `nexus_channel_mappings` table stores each channel's remote ID against your local model using a polymorphic relationship with a composite unique index, preventing duplicate mappings.\n\n### 💀 Dead Letter Queue\nJobs that exhaust all retries are written to `nexus_dead_letter_queue` with their full serialized payload and exception detail. No silent failures. From the dashboard you can replay individual jobs or bulk-replay after an API outage — no artisan required.\n\n### 📊 Real-Time Livewire Dashboard\nA Livewire 3 dashboard at `/nexus` with wire:poll.3s real-time updates:\n\n- **Channel Status Cards** — Connected / Throttled / Disconnected, with live token bucket fill level per channel\n- **Sync Job Monitor** — Active `Bus::batch()` instances with per-job progress\n- **Webhook Event Log** — Paginated, searchable log of every inbound webhook with verification status and processing duration\n- **Dead Letter Queue Manager** — Replay or resolve failed jobs with one click\n- **Real-Time Alerts** — `ChannelThrottled` broadcasts via Laravel Reverb when rate limiting is detected\n\n### 🔧 Extensible Driver System\nRegister community-contributed or internal channel drivers without touching the package core:\n\n```php\n// In AppServiceProvider::boot()\nNexus::extend('ebay', function ($app) {\n    return new EbayInventoryDriver(\n        config: $app['config']['nexus.channels.ebay'],\n        client: $app-\u003emake(EbayApiClient::class)\n    );\n});\n\n// eBay is now a first-class channel\nNexus::product($product)-\u003eupdateInventory(10)-\u003esync(['shopify', 'ebay']);\n```\n\n### 🧩 Normalized Product DTOs\nChannel-specific product structures are normalized into a single `NexusProduct` DTO, eliminating transformation logic from your application:\n\n```php\nNexusProduct::fromShopify($payload);     // variants[], inventory_item_id, barcode\nNexusProduct::fromWooCommerce($payload); // stock_quantity, variations[]\nNexusProduct::fromAmazon($payload);      // ASIN, seller_sku, quantity\nNexusProduct::fromEtsy($payload);        // listing_id, skus[], price divisor\n```\n\nThe `channelMeta` field preserves the raw channel payload so channel-specific data (Amazon FBA routing, Etsy listing state) is never permanently discarded.\n\n---\n\n## Requirements\n\n- PHP 8.2+\n- Laravel 12+\n- Redis (for rate limiting and queues)\n- MySQL 8+ or PostgreSQL\n\n---\n\n## Installation\n\n```bash\ncomposer require malikad778/nexus-inventory\n```\n\nPublish the config file and migrations:\n\n```bash\nphp artisan vendor:publish --tag=\"nexus-config\"\nphp artisan vendor:publish --tag=\"nexus-migrations\"\nphp artisan migrate\n```\n\n---\n\n## Configuration\n\nAdd channel credentials to your `.env`:\n\n```dotenv\n# Shopify\nSHOPIFY_SHOP_URL=your-shop.myshopify.com\nSHOPIFY_ACCESS_TOKEN=shpat_...\nSHOPIFY_WEBHOOK_SECRET=whsec_...\nSHOPIFY_LOCATION_ID=...\n\n# WooCommerce\nWOOCOMMERCE_STORE_URL=https://your-store.com\nWOOCOMMERCE_CONSUMER_KEY=ck_...\nWOOCOMMERCE_CONSUMER_SECRET=cs_...\nWOOCOMMERCE_WEBHOOK_SECRET=...\n\n# Amazon SP-API\nAMAZON_CLIENT_ID=amzn1.application-oa2-client...\nAMAZON_CLIENT_SECRET=...\nAMAZON_REFRESH_TOKEN=Atzr|...\nAMAZON_SELLER_ID=...\nAMAZON_ACCESS_KEY_ID=...\nAMAZON_SECRET_ACCESS_KEY=...\nAMAZON_REGION=us-east-1\n\n# Etsy\nETSY_KEYSTRING=...\nETSY_SHARED_SECRET=...\nETSY_SHOP_ID=...\nETSY_WEBHOOK_SECRET=...\n```\n\nSee `config/nexus.php` for rate limit overrides, dashboard middleware, and queue configuration.\n\n---\n\n## Usage\n\n### Sync a Single Product\n\n```php\nuse Malikad778\\\\LaravelNexus\\Facades\\Nexus;\n\n// All configured channels\nNexus::product($product)-\u003eupdateInventory(quantity: 42)-\u003esync();\n\n// Specific channels only\nNexus::product($product)-\u003eupdateInventory(quantity: 42)-\u003esync(['shopify', 'amazon']);\n```\n\n### Bulk Catalog Sync\n\n```php\n$batch = Nexus::catalog($products)-\u003esyncAll();\n```\n\n### Access Drivers Directly\n\n```php\n$product  = Nexus::driver('shopify')-\u003efetchProduct('gid://shopify/Product/789');\n$products = Nexus::driver('woocommerce')-\u003egetProducts(now()-\u003esubHours(24));\n$success  = Nexus::driver('etsy')-\u003epushInventory($nexusInventoryUpdate);\n```\n\n### Listen to Events\n\n```php\n// In EventServiceProvider\nprotected $listen = [\n    \\Malikad778\\\\LaravelNexus\\Events\\InventoryUpdated::class =\u003e [\n        PropagateInventoryToOtherChannels::class,\n    ],\n    \\Malikad778\\\\LaravelNexus\\Events\\BeforeInventorySync::class =\u003e [\n        EnforceSafetyStockListener::class,\n    ],\n    \\Malikad778\\\\LaravelNexus\\Events\\InventorySyncFailed::class =\u003e [\n        AlertOpsTeamListener::class,\n    ],\n    \\Malikad778\\\\LaravelNexus\\Events\\ProductImported::class =\u003e [\n        CreateLocalProductListener::class,\n    ],\n];\n```\n\n### Make Your Model Syncable\n\n```php\nuse Malikad778\\\\LaravelNexus\\Traits\\Syncable;\n\nclass Product extends Model\n{\n    use Syncable;\n}\n\n// Access channel mappings\n$shopifyId = $product-\u003echannelMappings()-\u003ewhere('channel', 'shopify')-\u003evalue('remote_id');\n```\n\n### Dashboard\n\nVisit `/nexus`. Secure it in `config/nexus.php`:\n\n```php\n'dashboard_middleware' =\u003e ['web', 'auth'],\n```\n\n### Queue Workers\n\n```bash\nphp artisan queue:work redis --queue=nexus,default\n```\n\n---\n\n## Architecture Overview\n\n```mermaid\ngraph TD\n    A[Your Application] --\u003e|Nexus::product / catalog| B(InventoryManager)\n    B --\u003e C{InventoryDriver}\n    C --\u003e|REST + HMAC| D[ShopifyDriver]\n    C --\u003e|REST v3 + Basic Auth| E[WooCommerceDriver]\n    C --\u003e|SP-API + AWS SigV4| F[AmazonDriver]\n    C --\u003e|OAuth2 PKCE| G[EtsyDriver]\n\n    H[Inbound Webhooks] --\u003e|Signed Payload| I[VerifyNexusWebhookSignature]\n    I --\u003e|Verified| J[WebhookController]\n    J --\u003e|InventoryUpdated event| K[Your Listeners]\n    K --\u003e|Nexus::product| B\n\n    L[CatalogSyncJob] --\u003e|Bus::batch| M[ChannelSyncBatchJob × channels]\n    M --\u003e|Token acquired| N[PushInventoryJob × SKUs]\n    N --\u003e|Exhausted retries| O[(nexus_dead_letter_queue)]\n\n    P[TokenBucket] --\u003e|Lua atomic eval| Q[(Redis)]\n    M --\u003e P\n```\n\n---\n\n## Database Tables\n\n| Table | Purpose |\n|---|---|\n| `nexus_channel_mappings` | Polymorphic map between local models and remote channel IDs |\n| `nexus_sync_jobs` | Active and historical job tracking with batch IDs and status |\n| `nexus_dead_letter_queue` | Permanently failed jobs with full payload for one-click replay |\n| `nexus_webhook_logs` | Audit log of every inbound webhook with verification status |\n| `nexus_rate_limit_logs` | Per-channel rate limit event tracking for dashboard visibility |\n\n---\n\n## Testing\n\n```bash\ncomposer test\n```\n\n---\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for recent changes.\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalikad778%2Fnexus-inventory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmalikad778%2Fnexus-inventory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalikad778%2Fnexus-inventory/lists"}