feat: Implement Slack, Trello, and Courier (ShipLogic) integration

- Add 14 domain events for order lifecycle (OrderCreated, OrderPacked, ShipmentCreated, ParcelDelivered, etc.)
- Create SlackNotifierService with channels for orders, design, production, shipping, ops-alerts
- Create TrelloService to create cards, move cards between lists, attach files, check items
- Create CourierService to integrate with ShipLogic API for shipment creation and document retrieval
- Create PackingController to explicitly capture packing dimensions and weight
- Create ShippingController with multi-layer guards: packing validation, payment/approval verification, idempotency
- Create TrelloWebhookController to handle incoming Trello webhooks as intent signals
- Create CourierWebhookController to handle Shiplogic status updates
- Create event listeners for Slack notifications and Trello card updates
- Create EventServiceProvider to register all events and listeners
- Add database migration for packing, courier, and Trello data columns
- Create config files for slack, trello, and courier integration
- Update .env with integration secrets placeholders
- Add routes for /orders/{id}/pack, /orders/{id}/ship, /api/webhooks/trello, /api/webhooks/courier

Key architectural decisions:
- Packing is explicit ops action (not automatic from status)
- Shipment creation only after: Trello intent + packing confirmed + payment/approval rules met
- Courier API failures keep order in Ready to Ship state (safe retry)
- Trello and Slack are mirrors of backend state, not decision makers
- All side effects flow through event listeners, maintaining separation of concerns
This commit is contained in:
twotalesanimation
2026-01-02 13:47:31 +02:00
parent 4730f5770c
commit 12aadfd917
35 changed files with 1815 additions and 0 deletions
+8
View File
@@ -10,6 +10,8 @@ use App\Http\Controllers\CartController;
use App\Http\Controllers\OrderController;
use App\Http\Controllers\CustomOrderController;
use App\Http\Controllers\Auth\GoogleAuthController;
use App\Http\Controllers\PackingController;
use App\Http\Controllers\ShippingController;
Route::get('/', [HomeController::class, 'index'])->name('home');
Route::get('/wallpapers', [WallpapersController::class, 'index'])->name('wallpapers');
@@ -61,6 +63,12 @@ Route::middleware('auth')->group(function () {
Route::get('/custom-orders/{customOrder:uuid}', 'App\Http\Controllers\CustomOrderController@show')->name('custom-orders.show');
Route::post('/payment/yoco/custom/deposit', [CustomOrderController::class, 'depositPayment'])->name('yoco-custom-deposit');
Route::get('/payment/yoco/custom/deposit/success/{customOrder:uuid}', [CustomOrderController::class, 'depositSuccess'])->name('yoco-custom-deposit-success');
// Packing & Shipping routes (ops staff)
Route::post('/orders/{order:uuid}/pack', [PackingController::class, 'confirmPacked'])->name('orders.pack');
Route::post('/custom-orders/{customOrder:uuid}/pack', [PackingController::class, 'confirmPacked'])->name('custom-orders.pack');
Route::post('/orders/{order:uuid}/ship', [ShippingController::class, 'createShipment'])->name('orders.ship');
Route::post('/custom-orders/{customOrder:uuid}/ship', [ShippingController::class, 'createShipment'])->name('custom-orders.ship');
});
// use Illuminate\Support\Facades\Route;