# Triển khai Kiến trúc Pub/Sub & Transactional Outbox

- [x] 1. Cập nhật Database Schema
  - [x] Thêm bảng `erp_outbox_events` (id, event_type, payload, status, created_at, processed_at)
  - [x] Thêm cột `processed_invoice_ids` (hoặc bảng track) vào module Dự án để đảm bảo tính Lũy đẳng (Idempotency).
- [x] 2. Xây dựng Event Bus & Outbox Worker
  - [x] Sửa `app/core/module_framework/registry.py` hoặc tạo module mới `event_bus.py`
  - [x] Viết background task (worker) đọc `erp_outbox_events` và dispatch tới các listener.
- [x] 3. Tích hợp Publish tại Module Hóa đơn
  - [x] Sửa API / Service gán Hóa đơn vào Dự án (WBS Matching) để ghi vào `erp_outbox_events` trong cùng một Transaction.
- [x] 4. Tích hợp Subscribe tại Module Dự án
  - [x] Khai báo listener trong `app/modules/projects/application/cost_sync_listener.py`
  - [x] Cập nhật chi phí WBS thực tế một cách lũy đẳng (Idempotent).
- [x] 5. Kiểm thử Tích hợp
  - [x] Viết test `pytest tests/test_event_bus.py` mô phỏng luồng Pub/Sub.
