# معماری

## تصمیم اصلی

شروع پروژه Modular Monolith است. یک توسعه‌دهنده می‌تواند تراکنش‌ها، migrationها
و refactorهای بین دامنه‌ای را بدون هزینهٔ هماهنگی شبکه و استقرارهای متعدد انجام
دهد، در حالی‌که مرزهای کد برای جداسازی آینده حفظ می‌شوند. API مالک منطق دامنه
است؛ Web فقط مصرف‌کنندهٔ SDK، Realtime مسئول اتصال و fan-out، و Worker مسئول
کارهای کند و قابل‌تکرار است.

هر دامنه Contract، Model، Repository، Service، Controller و Module خودش را
دارد. دامنه A حق نوشتن مستقیم در جدول دامنه B را ندارد. تعامل هم‌زمان از طریق
Service داخلی و تعامل غیرهم‌زمان از طریق Domain Event و Transactional Outbox
انجام می‌شود. جدول‌های عمومی با پیشوند `platform_` و جدول‌های دامنه با نام دامنه
مشخص می‌شوند.

## جریان Outbox

تغییر aggregate و درج Outbox باید در یک تراکنش PostgreSQL انجام شوند. Worker
رکوردهای آماده را با `FOR UPDATE SKIP LOCKED` claim می‌کند، شناسهٔ پردازش‌شده را
برای idempotency ثبت می‌کند، و نتیجه را processed یا با backoff دوباره pending
می‌کند. Payload رویداد نسخه‌دار است و مصرف‌کننده نباید به جدول تولیدکننده وصل
شود.

## مسیر تکامل

- NATS JetStream فقط وقتی اضافه می‌شود که چند سرویس مستقل، fan-out پایدار یا
  نگهداری طولانی رویداد لازم شود. Interface آن در `packages/events` آماده است.
- OpenSearch وقتی اضافه می‌شود که PostgreSQL FTS/`pg_trgm` پاسخ‌گوی relevance،
  typo tolerance یا حجم ایندکس نباشد.
- ClickHouse وقتی اضافه می‌شود که analytics تبلیغات و eventهای حجیم، بار
  عملیاتی PostgreSQL را مختل کنند. PostgreSQL تا آن زمان منبع حقیقت است.
- Kubernetes فقط پس از نیاز واقعی به چند محیط/replica و اتوماسیون عملیاتی وارد
  می‌شود؛ Compose قرارداد توسعهٔ فعلی است.

استخراج هر دامنه زمانی مجاز است که مالکیت داده، قرارداد API/event، الگوی بار و
نیاز استقرار مستقل روشن شده باشد. ابتدا Adapter داخلی با transport جایگزین
می‌شود؛ سپس schema/داده با migration کنترل‌شده منتقل می‌شوند.
