Domain Model Outline (DDD)#
This document outlines a potential domain model based on the lexicon definitions, following Domain-Driven Design (DDD) principles and a layered architecture.
Bounded Contexts#
We identify three primary bounded contexts:
- Annotations Context: Manages the creation, definition, and querying of annotations, annotation fields, and templates.
- User Management Context: Responsible for representing users within this application, linking them to their external Bluesky identity via OAuth, and managing their session state. Users from this context act as actors within the Annotations context.
- ATProto Context: Deals with the underlying AT Protocol concepts like repositories, records, and strong references. This context primarily provides foundational types and potentially infrastructure adapters (like OAuth clients) used by other contexts.
Layered Architecture#
1. Domain Layer#
Contains the core business logic, entities, value objects, and aggregates. It is independent of application and infrastructure concerns.
Annotations Context#
-
Aggregates & Entities:
Annotation(Aggregate Root):- Entity representing a single annotation instance.
- Contains
AnnotationValue(Value Object) representing the specific data based on the field type. - References
AnnotationFieldviaStrongRef(Value Object from ATProto context). - May reference
AnnotationTemplate(s) viaStrongRef(Value Object from ATProto context). - Includes
url(Value Object - potentially a specific URI type) and optionaladditionalIdentifiers(List ofIdentifierValue Objects). - Includes optional
note(string). - Root ensures the consistency between the
AnnotationFieldreference and theAnnotationValuetype.
AnnotationField(Aggregate Root):- Entity defining the structure and type of an annotation.
- Contains
FieldDefinition(Value Object) which holds the specific configuration (e.g.,DyadFieldDef,RatingFieldDef). - Properties:
name,description,createdAt. - Root ensures the validity of the
FieldDefinition.
AnnotationTemplate(Aggregate Root):- Entity grouping multiple
AnnotationFields. - Properties:
name,description,createdAt. - Contains a list of
TemplateField(Value Object), each holding aStrongRefto anAnnotationFieldand arequiredflag. - Root ensures the integrity of the template definition.
- Entity grouping multiple
-
Value Objects:
AnnotationValue: Represents the actual value of an annotation. Could be a union/interface implemented by:DyadValue(value)TriadValue(vertexA,vertexB,vertexC,sum)RatingValue(rating)SingleSelectValue(option)MultiSelectValue(optionarray)
FieldDefinition: Represents the definition of anAnnotationField. Could be a union/interface implemented by:DyadFieldDef(sideA,sideB)TriadFieldDef(vertexA,vertexB,vertexC)RatingFieldDef(numberOfStars)SingleSelectFieldDef(optionsarray)MultiSelectFieldDef(optionsarray)
TemplateField: Represents an entry inAnnotationTemplate.annotationFields. ContainsfieldRef(StrongRef) andrequired(boolean).Identifier: (type,value) - Representsapp.annos.defs#identifier.URI: Represents a validated URI string.
ATProto Context (as relevant to Annotations)#
- Value Objects:
StrongRef: (cid,uri) - Representscom.atproto.repo.strongRef. Used for linking between aggregates/records.TID: Represents a unique record identifier within the ATProto context. (Used askeyin lexicons).
User Management Context (See docs/user-domain.md for details)#
- Aggregates & Entities:
User - Value Objects:
DID,Handle - Domain Events:
UserAccountLinked,UserLoggedIn
2. Application Layer#
Contains application-specific logic, orchestrates use cases, and coordinates domain objects. It depends on the Domain Layer but not the Infrastructure Layer (uses interfaces defined in the domain/application layer).
-
Use Cases / Application Services:
CreateAnnotationUseCase: Handles creating a newAnnotationrecord. Validates input, fetches relatedAnnotationField, creates theAnnotationaggregate, and uses a repository to persist it.GetAnnotationUseCase: Retrieves anAnnotationby its identifier.CreateAnnotationFieldUseCase: Handles creating a newAnnotationField. Validates definition, creates the aggregate, persists.GetAnnotationFieldUseCase: Retrieves anAnnotationField.CreateAnnotationTemplateUseCase: Handles creating a newAnnotationTemplate. Validates input, resolvesAnnotationFieldreferences, creates the aggregate, persists.GetAnnotationTemplateUseCase: Retrieves anAnnotationTemplate.FillAnnotationTemplateUseCase: Handles creating a set ofAnnotationrecords based on a providedAnnotationTemplateand input values for a specific target URL. Fetches the template and fields, validates input, creates multipleAnnotationaggregates (populatingfieldRefandtemplateRefsappropriately), and persists them.AddAnnotationFieldToTemplateUseCase: Adds a field reference to an existing template.ListAnnotationsForResourceUseCase: Finds annotations associated with a specific URL or identifier.- (Other CRUD operations and specific query use cases)
-
Data Transfer Objects (DTOs): Used for input and output of Application Services to decouple from the internal domain model and external interfaces (e.g., API requests/responses).
AnnotationInputDTO,AnnotationOutputDTOAnnotationFieldInputDTO,AnnotationFieldOutputDTOAnnotationTemplateInputDTO,AnnotationTemplateOutputDTOFillAnnotationTemplateInputDTO: Input forFillAnnotationTemplateUseCase, containing template URI, target URL, and a map of field URIs to their values.FillAnnotationTemplateOutputDTO: Output forFillAnnotationTemplateUseCase, containing a list of the createdAnnotationOutputDTOs.
-
Repository Interfaces: (Defined here or in Domain, implemented in Infrastructure)
IAnnotationRepositoryIAnnotationFieldRepositoryIAnnotationTemplateRepositoryIUserRepository
-
Infrastructure Service Interfaces: (Defined here, implemented in Infrastructure)
IOAuthProcessorIOAuthSessionStoreIOAuthStateStore
3. Infrastructure Layer#
Contains implementation details for data persistence, external service integrations, UI frameworks, etc. It depends on the Application and Domain Layers.
- Persistence (Example: Drizzle ORM):
- Implementation of Repository Interfaces (
AnnotationRepository,AnnotationFieldRepository,AnnotationTemplateRepository) using Drizzle ORM. - Defines Drizzle schemas mapping domain entities/aggregates to database tables.
- Handles database connections and transactions.
- Serializes/deserializes Value Objects (like
AnnotationValue,FieldDefinition,StrongRef) for storage.
- Implementation of Repository Interfaces (
- External Services:
- Clients or adapters for interacting with other ATProto services if needed (e.g., resolving
StrongRefdetails if not handled purely by reference).
- Clients or adapters for interacting with other ATProto services if needed (e.g., resolving
- API / Presentation:
- (e.g., Express.js, Fastify) Handles HTTP requests, uses Application Services (Use Cases) to perform actions, and formats responses (often using DTOs). Maps API routes to use case handlers.
Interactions#
- The Application Layer orchestrates interactions. For example,
CreateAnnotationUseCasemight fetch anAnnotationFieldusingIAnnotationFieldRepositoryto validate the incomingAnnotationValuebefore creating theAnnotationaggregate and saving it viaIAnnotationRepository. StrongRefValue Objects are used within the Annotations context domain models but their resolution or validation might involve calls (potentially abstracted via interfaces) to ATProto-specific logic or repositories.