This project aims to build a modern wedding website using Domain-Driven Design (DDD) principles.
🚧 Currently under construction. 🚧
What is Domain-Driven Design? ...
Domain-Driven Design (DDD) is a software development approach that emphasizes understanding and modeling the core business domain, ensuring that the software accurately reflects the real-world concepts and logic. Instead of focusing solely on technical concerns, DDD prioritizes aligning the software's design with the business domain, leading to a more maintainable, flexible, and understandable codebase.
While DDD is typically recommended for larger, complex projects with multiple teams and stakeholders, this project serves as a personal learning exercise and a fun application of DDD concepts in a real-world scenario.
Mantra: The tendecy towards perfectionism underminds attempts to do good design.
This wedding website aims to provide a seamless and interactive experience for guests, encompassing features such as:
- RSVP Page 📅: Guests can RSVP via an API integrated with Google Sheets.
- About Us 💑: Detailed information about the couple and their story.
- Wedding Party 👰🤵: Introductions and pictures of the wedding party.
- Guest Accommodations 🛌: Links and information about hotels and lodging options.
- Venue 📍: Venue address, timings, and map integration.
- Contact Information 📞: Easy access to contact details for the couple.
- Gift Registry 🎁: Links to gift registry services.
- Post-Wedding 🎉: Thank you message, photo gallery, and video links.
- Chatbot 🤖: An AI-powered chatbot (using Azure OpenAI) to answer guest questions about various aspects of the wedding.
- Frontend 🎨: React with MUI - Material UI. This choice leverages the popularity and component-based structure of React, combined with the aesthetic and accessibility benefits of Material Design.
- Backend ☁️: Serverless architecture on Azure, using Azure Functions for their event-driven nature, scalability, and cost-effectiveness.
- Database 📈: Google Sheets will store RSVP data due to its ease of use and integration capabilities, allowing for quick setup and data management. Other website data might be stored in Cosmos DB, taking advantage of its scalability and integration with the Azure ecosystem.
- CI/CD 🚀: GitHub Actions will automate the build, testing, and deployment processes, streamlining the development workflow and ensuring code quality.
- Chatbot 🤖: Azure OpenAI, with its advanced natural language processing capabilities, will power the chatbot functionality, providing guests with intelligent and relevant responses to their queries.
This project uses DDD to structure the codebase, enhance maintainability, and align the software design with the business logic of a wedding website. Below are the core DDD concepts being implemented:
The core domain of this project is the Wedding Event 💍. This is because every feature and piece of functionality revolves around providing information about this event, managing guest interactions related to it, and ultimately, celebrating the big day. For instance, the RSVP system exists to track who will be attending the Wedding Event. The Venue information is crucial for guests to locate the Wedding Event. Even the Chatbot, which exists as a supporting subdomain, is there to answer questions and provide information directly related to the Wedding Event. By identifying the Wedding Event as the core domain, we can prioritize our development efforts and ensure that our software model accurately reflects the essential aspects of a real-world wedding. Other features, like the chatbot, photo gallery, or guest accommodation links, are supporting subdomains. They enhance the user experience but are not central to the core domain. |
We do not have multiple subdomains but can still use bounded context to manage complexity and maintain a clear separation of concerns. Each bounded context represents a specific area of the application with its own domain model, ensuring that changes within one context have minimal impact on others. Our bounded context use a shared kernel which means they share the same language and their models when interacting with a different bound context in the same domain. Here are examples of bounded contexts within our wedding website:
|
Aligning our language between developers and domain experts (in this case, those involved in planning the wedding) is crucial for DDD's success. We'll establish a ubiquitous language to ensure everyone uses the same terminology when discussing the project, from design meetings to code comments. For example, instead of using technical jargon like "database record" or "API endpoint," we'll use terms like "Guest," "RSVP," and "Wedding Event," reflecting the language used in the wedding planning domain. This shared vocabulary reduces misunderstandings and makes the codebase more accessible and easier to maintain. Here's how our ubiquitous language looks in practice: |
Aggregates help us manage data consistency and integrity by grouping related objects. Within our wedding website, we'll define aggregates to encapsulate related data and ensure that operations on this data happen in a controlled manner. Here are two primary aggregates we'll implement:
|
Distinguishing between entities and value objects allows us to model our domain more accurately. Entities have a unique identity and a lifecycle, meaning they can change over time but are still recognizable as the same entity. Value objects, on the other hand, are defined by their attributes and are considered immutable—once created, their values don't change. Here's how we'll apply entities and value objects:
|
Services help us encapsulate business logic that doesn't naturally fit within entities or value objects. They typically represent actions or operations within our domain. Here are some examples of services we'll use:
|
This project will follow a modular structure aligned with the principles of DDD. This approach enhances code organization and maintainability, making it easier to navigate and understand different parts of the application.
We'll have separate modules or directories for each bounded context:
wedding-information
: Containing all components related to managing and displaying core wedding details, including the Wedding Event Aggregate and related entities and value objects.rsvp-management
: Housing the logic for RSVP processing, the Google Sheets API integration, and the Guest Aggregate.guest-communication
: Containing the Chatbot Service and any other components related to guest interaction, like potential email notification services.
This structure promotes a clear separation of concerns. Each module focuses on a specific aspect of the domain, minimizing dependencies between modules and making it easier to make changes and add features without impacting other parts of the application.
Visual models help us understand the project's structure and the relationships between different components. Here are some key models for this wedding website:
This diagram provides a high-level view of the wedding website's architecture and its interactions with external systems.
C4Context
title Wedding Website Context Diagram
Person(customer, "Customer", "Wedding Guest")
System(weddingWebsite, "Wedding Website", "Provides wedding information and RSVP functionality")
System_Ext(googleSheets, "Google Sheets", "RSVP data storage")
System_Ext(azureOpenAI, "Azure OpenAI", "Chatbot AI service")
System_Ext(azureStorage, "Azure Storage", "Website assets, data storage")
System_Ext(azureCosmoDB, "Azure Cosmo DB", "Website semi-structured data")
System_Ext(azureFunctions, "Azure Functions", "Serverless backend for website logic")
Rel_D(customer, weddingWebsite, "", "HTTPS")
UpdateRelStyle(customer, weddingWebsite, $textColor="blue", $offsetX="-40", $offsetY="-20")
Rel_D(weddingWebsite, azureStorage, "", "External API")
UpdateRelStyle(weddingWebsite, azureStorage, $textColor="red", $offsetY="-40")
Rel_D(azureFunctions, azureCosmoDB, "", "External API")
UpdateRelStyle(azureFunctions, azureCosmoDB, $textColor="red", $offsetX="-30", $offsetY="-10")
Rel_D(weddingWebsite, azureFunctions, "", "Internal")
UpdateRelStyle(weddingWebsite, azureFunctions, $textColor="yellow", $offsetY="-20", $offsetX="-40")
Rel_D(azureFunctions, googleSheets, "", "Externl API")
UpdateRelStyle(azureFunctions, googleSheets, $textColor="red", $offsetY="-40", $offsetX="-40")
Rel_D(azureFunctions, azureOpenAI, "", "External API")
UpdateRelStyle(azureFunctions, azureOpenAI, $textColor="red", $offsetX="-100")
The ER diagram visualizes the core entities of our domain and their relationships. It helps understand how we store and structure data.
erDiagram
RSVP }|--|| WEDDING_EVENT : contains
WEDDING_EVENT ||--|{ VENUE : has
WEDDING_EVENT ||--|{ GUEST : has
RSVP {
GUEST guest
boolean attending
string(nullable) plusOne
string(nullable) dietaryRestrictions
string(nullable) comment
RSVPStatus rsvpStatus
}
VENUE {
UUID id
string name
Address address
URL link
}
GUEST {
UUID id
string name
string email
string(nullable) phoneNumber
Address(nullable) address
}
WEDDING_EVENT {
UUID id
string title
string description
date date
VENUE venue
}
The flowchart illustrates the primary workflows within the wedding website, showing how data flows between different components.
flowchart TB
Start --- subGraph0
Start --- subGraph1
Start --- subGraph2
subgraph Wedding Information
WeddingEvent --> VENUE("VENUE")
WeddingEvent --> GUEST("GUEST")
RSVP("RSVP") --> WeddingEvent
VENUE --> VenueDetails("Venue Details")
GUEST --> GuestDetails("Guest Details")
RSVPForm("RSVP Form") --> RSVP
RSVP ~~~ VENUE
RSVP ~~~ GUEST
end
subgraph Guest Communication
Chatbot("Chatbot") <-.-> OpenAI("Azure Open AI")
end
subgraph RSVP Management
RSVPAPI("RSVP API") <-.-> GoogleSheets("Googe Sheets")
end
subgraph Wedding Website
subGraph0
subGraph1
subGraph2
end
This state diagram visualizes the different states the chatbot can be in and how it transitions between those states based on guest interactions.
stateDiagram-v2
[*] --> Initializing
Initializing --> Ready : Initialized
Ready --> Responding : Guest interacts
Responding --> Ready : Response provided
Responding --> Error : Error handling
Error --> Ready : Error resolved
For a visual representation of the website's design and layout, please refer to the Mockups Document.
While DDD offers numerous benefits, applying it to a relatively simple project like this wedding website comes with some considerations:
- Overhead vs. Simplicity: DDD introduces a certain level of overhead in terms of upfront design and planning. It's crucial to balance the benefits of DDD with the potential complexity it might add to a small project.
- Learning Curve: DDD has a learning curve, especially for those unfamiliar with its principles and patterns. It requires a shift in thinking about software design, focusing on the domain logic rather than technical implementation.
This repository offers a streamlined development environment setup using a devcontainer.json file, allowing you to get up and running quickly with a fully-featured environment in the cloud.[1] Use one of the following links to get started:
|
|||||
If you want to browse the source code without the need to build, you can do so conveniently on GitHub.dev or VSCode.dev: | |||||
This repo is licensed under the MIT License. See the LICENSE
file for details.
-
For local development check out Dev Containers and DevPod. ↩