Enterprise Angular

Domain Driven Design


The Goal

We are going to discuss how the our code should be a reflection of the business domain that we are operating in.

We also want to highlight the importance of having clear boundaries between distinct contexts within our conceptual understanding as well as in our code.

These boundaries allow us to start to develop and converge on a set of unambiguous semantics that developers and non-technical stakeholders can use to describe the core domain and sub-domains.

Another super important concept is the need to establish a data contract so that the frontend and the backend are decoupled as they can both program to the same interfaces.

Our goal is to define the domain model and data contract for our application.

The Domains

Users

The user domain is responsible for registering users and setting user roles.

The users domain will also be responsible for authenticating users. This may need to be broken out into a separate domain.

Challenges

The challenges domain is where challenges can be created and grouped in a series for users to complete.

Flashcards

The flashcards domain is where flashcards can be created and iterated through much like Anki.

Notes

The notes domain allows for users to create and save snippets much like GitHub Gist.

The Apps

Portal The portal is a registery for microfrontends (MFEs) which is used to expose MFEs, control access, andd perform health checks.

We may consider allowing the register API endpoints as well.

Dashboard

The dashboard is the client facing application which queries the portal after authenticating and loads available MFEs.

Mobile

The mobile application is a read-only mobile variation which will illustrate the power of creating reusuable libraries.

The Stack

Portal Dashboard Mobile Users Challenges Flashcards Notes
APP
API
DOCKER
DB

The Data Contract

Users

export interface BaseEntity {
  id?: string | null;
}

export interface User extends BaseEntity {
  firstName: string;
  lastName: string;
  email: string;
  password: string;
  role: UserRoleEnum;
  company_id: string;
}

export enum UserRoleEnum {
  ADMIN = 'admin',
  MENTOR = 'mentor',
  APPRENTICE = 'apprentice',
}

export interface Company extends BaseEntity {
  name: string;
  description: string;
}

Challenges

export interface Challenge extends BaseEntity {
  slug: string;
  title: string;
  description: string;
  completed: boolean;
  repo_url: string;
  comment: string;
  user_id: string;
}

Notes


export interface Note extends BaseEntity {
  title: string;
  content: string;
  type: NoteTypeEnum;
  user_id: string;
}

export enum NoteTypeEnum {
  TEXT = 'text',
  IMAGE = 'image',
  VIDEO = 'video',
  LINK = 'link',
}

Flashcards

export interface Flashcard extends BaseEntity {
  title: string;
  description: string;
  question: string;
  answer: string;
  user_id: string;
}

The Portal

export interface Feature extends BaseEntity {
  title: string;
  description: string;
  slug: string;
  remote_uri: string;
  api_uri: string;
  healthy: boolean;
}

The Commands

Create the workspace with a portal application.

npx create-nx-workspace@18.0.8 workshop \
  --appName=portal \
  --preset=angular-monorepo \
  --workspaceType=integrated \
  --bundler=esbuild \
  --e2eTestRunner=cypress \
  --style=scss \
  --ci=skip \
  --ssr=false

Create a library to hold the interfaces for the entire root domain and sub-domains.

npx nx g @nx/js:lib api-interfaces --directory=libs --unitTestRunner=none --minimal --no-interactive

Challenges

Choose and define an entity that we can use to build a feature slice around.

Resources

The Core of Domain-Driven Design

Modern Architectures with Angular – Part 1: Strategic Design with Sheriff and Standalone Components

Domain Modeling: What you need to know before coding

< Angular Home