Modular-Monolith-with-DDD
More actions
====================================================================
editMODULAR MONOLITH WITH DOMAIN-DRIVEN DESIGN (DDD) Comprehensive Repository & Architecture Review (kgrzybek/modular-monolith-with-ddd)
====================================================================
edit[ENGLISH SECTION - LTR]
====================================================================
edit1. INTRODUCTION & PURPOSE OF THE REPOSITORY
The repository "kgrzybek/modular-monolith-with-ddd" by Kamil Grzybek is widely regarded as one of the definitive architectural references in the software engineering community. It bridges the gap between traditional monolithic systems and distributed microservice architectures.
Key Objectives:
- Demonstrating how to design and build a maintainable, extensible enterprise .NET
application using a Modular Monolith architecture.
- Realizing the benefits of microservices (clear bounded contexts, domain autonomy,
independent data schemas, team boundaries) without taking on operational complexities (network latency, distributed transaction coordination, eventual consistency headaches, and heavy CI/CD infrastructure).
- Providing a production-ready, non-trivial application reference rather than a basic
proof of concept (PoC).
- Implementing Domain-Driven Design (DDD) tactical patterns and Testable Design principles.
2. DOMAIN DESCRIPTION: MEETUP PLATFORM
The application models a comprehensive real-world domain: an event/meeting management platform similar to Meetup.com.
Domain Concepts & Business Rules:
- Meeting Groups: Members can propose new meeting groups. Each group proposal requires
administrative review and approval before becoming active.
- Subscriptions: Each Meeting Group must have an Organizer with an active subscription.
A single subscription covers up to 3 Meeting Groups.
- Meetings: Only an Organizer of an active Meeting Group can create meetings. A meeting
has attendees, non-attendees (members explicitly declining), and a waitlist.
- Quotas & Limits: Meetings can enforce attendee limits. When the limit is reached, new
sign-ups automatically queue into the waitlist.
- Roles: Attendees can hold roles (Attendee or Host). Every meeting requires at least
one Host who has privileges to modify meeting details and attendee rosters.
- Event Fees & Guests: Organizers can configure mandatory event fees. Attendees can invite
guests if allowed, paying the required fees on behalf of their guests.
- Comments: Members can write comments, reply to existing comments, and like comments,
governed by meeting configuration rules.
3. ARCHITECTURAL BLUEPRINT & C4 MODEL STRUCTURE
The repository employs Simon Brown's C4 model (System Context, Container, Component, and Code) documented via PlantUML (diagrams-as-code).
The architecture consists of the following distinct modules / bounded contexts:
1. API (Host Container):
- Ultra-thin ASP.NET Core Web API layer.
- Responsibilities: accept HTTP requests, delegate authentication/authorization
via the UserAccess module, dispatch commands and queries to internal modules,
and return HTTP responses.
- Contains ZERO business or application logic.
2. UserAccess Module:
- Manages user identity, registration validation, authentication, JWT token issuance,
roles, and fine-grained permissions.
3. Registrations Module:
- Handles the user onboarding pipeline: registration requests, confirmation email
flows, and registration verification state machines.
4. Meetings Module (Core Domain):
- The heart of the business domain: creation and lifecycle of Meeting Groups, Meetings,
Attendees, Waitlists, and Comment threads.
5. Administration Module:
- Dedicated workflows for back-office administrators: reviewing, approving, or
rejecting meeting group proposals and auditing platform policies.
6. Payments Module:
- Financial workflows: subscription fee payments, event entry fees, payer records,
and payment confirmation state handling.
4. TACTICAL DDD PATTERNS & INTERNAL MODULE ANATOMY
Each module is designed with strict boundaries and zero unauthorized coupling:
- High Level of Encapsulation:
All internal domain entities, repository implementations, command handlers, and database models are marked with C# 'internal' access modifiers. External callers only interact with a very small, public facade interface (e.g., IMeetingsModule).
- Rich Domain Models (Persistence Ignorance):
Domain entities are pure POCOs without EF Core or infrastructure dependencies. All business invariants and rules are strictly encapsulated inside Aggregate Roots.
- Combating Primitive Obsession:
Strong Value Objects are used throughout (e.g., MeetingId, MemberId, Money, MeetingLimits) instead of raw strings, integers, or GUIDs.
- CQRS (Command Query Responsibility Segregation):
- Command Pipeline (Write): Domain-driven mutation handled through MediatR/handlers and Entity Framework Core with strict repository patterns. - Query Pipeline (Read): High-performance, read-only SQL queries projected directly into DTOs using Dapper, completely bypassing domain models and change tracking.
- Asynchronous Inter-Module Communication:
Modules NEVER make direct database calls or synchronous method invocations across module boundaries. Inter-module communication is 100% asynchronous, mediated by an Event Bus.
- Reliability: Transactional Outbox & Inbox Patterns:
- Outbox Pattern: Integration events are saved into an Outbox table within the SAME local database transaction that mutates aggregate state. A background worker (Quartz.NET) polls the Outbox and dispatches events to the in-memory event bus. - Inbox Pattern: Receiving modules store incoming messages into an Inbox table to guarantee exactly/at-least-once processing and prevent duplicate side-effects.
- Internal Commands:
Enables deferred or background execution of internal tasks within a module (e.g., sending notification emails or expiring waitlist holds) with automated retry and error handling.
5. TESTING & ARCHITECTURAL GOVERNANCE
The project features a rigorous, multi-tier testing strategy:
- Unit Tests: Pure domain model testing focusing on invariant logic, free from mock
overhead or database dependencies.
- Integration Tests: End-to-end command/query execution tested against a real database
environment to ensure queries, mappings, and Outbox dispatchers execute flawlessly.
- Architecture Tests (NetArchTest): Automated architecture tests that run on build.
They enforce modular encapsulation, preventing developers from accidentally adding unauthorized dependencies across module layers.
====================================================================
edit[بخش فارسی - راست به چپ (RTL)]
====================================================================
edit۱. مقدمه و هدف مخزن (Introduction & Purpose)
ریپوزیتوری «kgrzybek/modular-monolith-with-ddd» اثر کمیل گژبک (Kamil Grzybek)، یکی از برجستهترین و استانداردترین مراجع معماری نرمافزار در جامعه توسعهدهندگان داتنت (.NET) و کل اکوسیستم مهندسی نرمافزار به شمار میرود.
اهداف بنیادین پروژه: • ارائه الگویی عملی برای پیادهسازی یک معماری یکپارچه ماژولار (Modular Monolith)
با کیفیت آماده برای محیط عملیاتی (Production-Ready) بهجای یک اثبات ایده (PoC) ساده.
• بهرهمندی از تمام مزایای میکروسرویسها (نظیر مرزبندی شفاف دامین، استقلال پایگاهداده،
کاهش وابستگیها و استقلال تیمها) بدون مواجهه با چالشها و هزینههای گزاف توزیعشدگی (تأخیر شبکه، پیچیدگی تراکنشهای توزیعشده، ناهماهنگی دادهها و زیرساخت پیچیده).
• نمایش پیادهسازی حرفهای الگوهای تاکتیکی طراحی دامینمحور (Domain-Driven Design) و
طراحی با قابلیت تستپذیری حداکثری (Testable Design).
۲. شرح دامنه تجاری: پلتفرم مدیریت رویدادها (Meetup Domain)
این پروژه برای نشان دادن الگوها در شرایط دنیای واقعی، دامنهای ملموس و دارای چالشهای کسبوکاری یعنی «سیستم مدیریت رویداد و همایش» (شبیه به پلتفرم بینالمللی Meetup) را پیادهسازی کرده است:
قوانین و مفاهیم بیزینس: • گروههای رویداد (Meeting Groups): اعضا میتوانند پیشنهاد تشکیل گروه جدید ثبت کنند؛
اما این پیشنهاد تا زمان بازبینی و تأیید توسط مدیران ارشد سیستم فعال نمیشود.
• اشتراکها (Subscriptions): هر گروه باید دارای برگزارکنندهای با اشتراک معتبر باشد.
هر اشتراک فعال حداکثر ۳ گروه همایش را پوشش میدهد.
• جلسات و رویدادها (Meetings): فقط سازماندهنده گروه میتواند جلسه جدید تعریف کند.
هر جلسه شامل شرکتکنندگان قطعی، انصرافدهندگان و لیست انتظار (Waitlist) است.
• ظرفیت و سهمیهها: جلسات میتوانند سقف ظرفیت داشته باشند؛ پس از پر شدن ظرفیت، ثبتنامها
بهطور خودکار به لیست انتظار منتقل میشوند.
• نقشهای جلسه: هر شرکتکننده میتواند نقش عادی یا میزبان (Host) داشته باشد. وجود حداقل
یک میزبان برای ویرایش جزئیات و مدیریت لیست افراد الزامی است.
• هزینهها و مهمانان: امکان تعیین هزینه ورودی برای جلسات وجود دارد و اعضا میتوانند
مهمان همراه بیاورند و هزینه آنها را شخصاً متقبل شوند.
• نظرات (Comments): ثبت نظر، پاسخ و لایککردن دیدگاهها با توجه به تنظیمات جلسه مدیریت میشود.
۳. ساختار و تفکیک ماژولها بر اساس مدل C4 (Architecture & Modules)
سیستم با پیروی از متدولوژی مستندسازی C4 (سطوح کانتینر، کامپوننت و کد) و با نمودارهای PlantUML مستندسازی شده و دارای تفکیک لایهای زیر است:
۱. ماژول API (لایه وب و میزبانی):
- یک لایه بسیار نازک بر بستر ASP.NET Core Web API.
- وظایف: دریافت درخواستهای HTTP، اعتبارسنجی احراز هویت با ماژول دسترسی، ارسال
فرمانها و پرسوجوها به ماژولهای داخلی و بازگرداندن پاسخ.
- فاقد هرگونه لاجیک تجاری و محاسباتی.
۲. ماژول UserAccess:
- مدیریت هویت کاربری، صدور توکنهای JWT، نقشها (Roles) و مجوزهای ریزدانه (Permissions).
۳. ماژول Registrations:
- مدیریت چرخه ثبتنام، تایید ایمیل و ماشین وضعیت اعتبارسنجی ثبتنام کاربران.
۴. ماژول Meetings (هسته مرکزی دامین):
- پیادهسازی هسته بیزینس: گروهها، جلسات، ظرفیتها، لیستهای انتظار و کامنتها.
۵. ماژول Administration:
- جریانهای کاری اختصاصی مدیران پلتفرم جهت بررسی، تأیید یا رد پیشنهادات گروهها.
۶. ماژول Payments:
- جریانهای مالی: پرداخت حق اشتراک برگزارکنندگان و هزینههای ورودی رویدادها.
۴. الگوهای تاکتیکی DDD و معماری داخلی ماژولها (Tactical DDD & Mechanics)
هر ماژول به عنوان یک واحد خودمختار با رعایت مرزهای نفوذناپذیر طراحی شده است:
• کپسولهسازی حداکثری (Strict Encapsulation):
تمامی موجودیتهای دامین، کلاسهای EF Core، هندلرها و ریپازیتوریها با سطح دسترسی internal تعریف شدهاند. دنیای خارج فقط از طریق یک اینترفیس پابلیک بسیار کوچک (مانند IMeetingsModule) با ماژول ارتباط برقرار میکند.
• مدلهای غنی دامنه و بیخبری از ذخیرهسازی (Persistence Ignorance):
موجودیتهای دامین کلاسهای خالص (POCO) هستند و هیچ وابستگی به زیرساخت یا پایگاهداده ندارند. تمام اینوریانتها (Invariants) و قوانین درون ریشههای تجمیع (Aggregate Roots) حفظ میشوند.
• مقابله با وسواس نوعهای بدوی (Primitive Obsession):
استفاده گسترده از Value Objectها بهجای انواع دادهای خام نظیر string یا Guid.
• تفکیک دستورات و پرسوجوها (CQRS):
- مسیر تغییرات (Write): با بهرهگیری از MediatR و Entity Framework Core برای تضمین صحت کامل دادهها. - مسیر خواندن (Read): با اجرای مستقیم کوئریهای خام و با بازدهی بسیار بالای SQL توسط Dapper مستقیماً روی DTOها، بدون درگیر کردن دامین مدل یا Change Tracker.
• ارتباط ناهمگام میان ماژولها (Asynchronous Communication):
هیچ ماژولی حق فراخوانی مستقیم متدها یا پایگاهداده ماژول دیگر را ندارد. کلیه تبادلات منحصراً از طریق انتشار رویداد روی Event Bus صورت میپذیرد.
• تضمین تراکنشها با الگوهای Outbox و Inbox:
- الگوی Outbox: رویدادهای یکپارچهسازی در همان تراکنش محلی دیتابیس در جدول Outbox ذخیره میشوند و پردازشگر پسزمینه (Quartz.NET) آنها را بدون از دست رفتن اطلاعات منتشر میکند. - الگوی Inbox: دریافت پیامها در جدول Inbox ذخیره میشود تا از پردازش تکراری رویدادها جلوگیری شده و ضمانت پردازش حداقل یکباره (At-Least-Once) حاصل شود.
• فرمانهای داخلی (Internal Commands):
انجام پردازشهای زمانبندیشده، ارسال ایمیلها یا کارهای پسزمینه درون هر ماژول به شکل مطمئن با قابلیت تلاش مجدد (Retry) خودکار.
۵. استراتژی تست و نظارت خودکار بر معماری (Testing & Arch Tests)
• تستهای واحد (Unit Tests): متمرکز بر اعتبارسنجی لاجیک خالص دامین مدل، بدون وابستگی به دیتابیس
یا شبیهسازیهای زائد (Mocking).
• تستهای یکپارچگی (Integration Tests): تست تراکنشهای واقعی، دیتابیس و اجرای کامل فرآیندها. • تستهای خودکار معماری (NetArchTest): آزمونهای کدی که نقض قوانین ماژولار، وابستگیهای غیرمجاز و
نشت کپسولهسازی را در زمان Build شناسایی و رد میکنند.