Skip to content

dylanlangston/langston-wedding.com

Repository files navigation

This project aims to build a modern wedding website using Domain-Driven Design (DDD) principles.
🚧 Currently under construction. 🚧

GitHub Test Workflow GitHub License GitHub repo size

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.


Domain Vision Statement/Project Overview 🎉

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.

Implementation Details ⚙️

  • 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.

DDD in Action 🛠️

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:

Distillation: Finding the Core Domain 🌟

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.

Bounded Contexts 📏

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:

  • Wedding Information 📝: This context focuses on managing the core details of the Wedding Event. This includes information like the date and time of the wedding, the location of the ceremony and reception, and any other essential details guests need to know. The Wedding Event Aggregate will likely reside within this bounded context.
  • RSVP Management 📅: This context is responsible for handling everything related to RSVPs. It manages the API integration with Google Sheets, processes guest responses, and stores the RSVP data securely. The RSVP service, responsible for interacting with the Google Sheets API, would belong here, as would the Guest Aggregate, which would store information about each guest and their RSVP status.
  • Guest Communication 📧: This context centers around communication with guests. This includes the chatbot functionality, which provides instant answers to guest queries, as well as potential features like email notifications about wedding updates. The Chatbot Service, responsible for processing chatbot interactions, would be part of this bounded context.

Ubiquitous Language 🗣️

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: ./UbiquitousLanguage.md

Aggregates 📚

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:

  • Wedding Event Aggregate 💍: This aggregate, likely residing within the "Wedding Information" bounded context, acts as the central point for all core wedding details. It includes information about the Wedding Event itself, such as the date, time, venue, and potentially a description. This aggregate also encapsulates the RSVP data, as RSVPs are directly related to the Wedding Event. It ensures that all updates and changes to the Wedding Event and its associated RSVPs happen consistently.
  • Guest Aggregate 👤: Belonging to the "RSVP Management" bounded context, this aggregate represents a single guest and their associated information. It stores the guest's name, contact details, any dietary restrictions or special requests they might have, and their RSVP status. By encapsulating this data, the Guest Aggregate makes it easier to manage individual guest information and ensures that any changes, like updating a guest's contact information or RSVP status, happen atomically.

Entities and Value Objects ⚖️

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:

  • Entities 👤:
    • Guest: A Guest is an entity because they have a unique identity. Even if their contact information changes, they're still the same guest.
    • Wedding Event: The wedding event has a unique identity too.
    • Venue: The venue also has a unique identity.
  • Value Objects 🔧:
    • Wedding Date: The wedding date is a value object—it's a specific point in time and doesn't change.
    • Venue Address: The address is also a value object, representing a specific location.

Services 🛠️

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:

  • Chatbot Service 🤖: This service handles all interactions with the Azure OpenAI API. It takes a guest's query as input, processes it, gets a response from the AI model, and delivers the response back to the user.
  • RSVP Service 📅: This service manages the interaction with our Google Sheets database. It handles tasks like adding new RSVPs, updating existing ones, and retrieving RSVP data for display on the website.

Project Structure 🏗️

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.

Models 📊

Visual models help us understand the project's structure and the relationships between different components. Here are some key models for this wedding website:

C4 Context Diagram: High-Level System Relationships

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")
Loading

Entity Relationship Diagram: Core Domain Data Structure

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
    }
Loading

Flowchart: Website Workflows and Interactions

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
Loading

State Diagram: Lifecycle of Chatbot Interactions

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
Loading

Design Mockups 🖼️

For a visual representation of the website's design and layout, please refer to the Mockups Document.

Challenges and Considerations 🤔

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.

Dev Environment 💻

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:

Open in GitHub Codespaces

Open Dev Container

Open DevPod

If you want to browse the source code without the need to build, you can do so conveniently on GitHub.dev or VSCode.dev:

Edit on GitHub.dev

Open in vscode.dev

License 📜

This repo is licensed under the MIT License. See the LICENSE file for details.

  1. For local development check out Dev Containers and DevPod.