-
Notifications
You must be signed in to change notification settings - Fork 9
afra demo application
NOTE: This page is still being written
DISCLAIMER: This documentation refers to milestone Boda, which is currently in early stages of development. Some or all of the features mentioned here may not yet exist, or be unstable.
This page demonstrates how much can be done with just a declaration of a simple domain model, and a minimal UIDL spec - all together less than 300 lines of code.
Code listings presented on this page are based on planned features of milestone Boda, while the screenshots are taken from a similar application built on NWheels milestone Afra, which can be found here: https://github.com/felix-b/NWheels/tree/afra/Source/NWheels.Samples.MyMusicDB.
The next sections contain:
- Code of the domain model (using the DDD framework)
- Code of client app UIDL spec (using the UIDL framework)
- Contents of the
app.json
file - Screenshots of the database
- Screenshots of a web UI app
The following code is based on planned features of milestone Boda.
using System;
using System.Collections.Generic;
using NWheels.Api.Ddd;
namespace MyMusicDB
{
[DomainModel.BoundedContext]
public class MusicDBContext
{
protected virtual EntityRepository<Genre> Genres { get; }
protected virtual EntityRepository<Artist> Artists { get; }
protected virtual EntityRepository<Album> Albums { get; }
protected virtual EntityRepository<Track> Tracks { get; }
}
//------------------------------------------------------------------------------------------------------------------
[DomainModel.Entity(IsAggregateRoot = true)]
public class Genre
{
[DomainModel.EntityId(AutoGenerated = true)]
public virtual int Id { get; protected set; }
[DomainModel.Invariant.Required, DomainModel.Invariant.Unique]
public virtual string Name { get; set; }
public class Reference : EntityReference<Genre, int> { }
}
//------------------------------------------------------------------------------------------------------------------
[DomainModel.Entity(IsAggregateRoot = true)]
public class Artist
{
[DomainModel.EntityId(AutoGenerated = true)]
public virtual int Id { get; protected set; }
[DomainModel.Invariant.Required, DomainModel.Invariant.Unique]
public virtual string Name { get; set; }
[DomainModel.Invariant.Required, DomainModel.Semantic.MultilineText]
public virtual string Description { get; set; }
public virtual ISet<GenreAssociation> Genres { get; }
public class Reference : EntityReference<Artist, int> { }
}
//------------------------------------------------------------------------------------------------------------------
[DomainModel.ValueObject]
public class GenreAssociation
{
[DomainModel.Relation.AggregationParent]
public virtual Genre.Reference Genre { get; set; }
public virtual bool IsPrimary { get; set; }
public virtual bool IsRecommended { get; set; }
}
//------------------------------------------------------------------------------------------------------------------
[DomainModel.Entity(IsAggregateRoot = true)]
public class Album
{
[DomainModel.EntityId(AutoGenerated = true)]
public virtual int Id { get; protected set; }
public virtual Artist.Reference Artist { get; set; }
[DomainModel.Invariant.Required, DomainModel.Invariant.UniquePerParents(nameof(Artist))]
public virtual string Name { get; set; }
[DomainModel.Semantic.Year, DomainModel.Invariant.Past]
public virtual int ReleaseYear { get; set; }
[DomainModel.Invariant.Required, DomainModel.Semantic.MultilineText]
public virtual string Description { get; set; }
[DomainModel.Semantic.ImageUrl]
public virtual string CoverImageUrl { get; set; }
[DomainModel.Relation.Composition]
public virtual IList<Track.Reference> Tracks { get; set; }
public class Reference : EntityReference<Album, int> { }
}
//-----------------------------------------------------------------------------------------------------------------
[DomainModel.Entity(IsAggregateRoot = true)]
public class Track
{
[DomainModel.EntityId(AutoGenerated = true)]
public virtual int Id { get; protected set; }
[DomainModel.Invariant.Required, DomainModel.Invariant.UniquePerParents(nameof(Album))]
public virtual string Name { get; set; }
[DomainModel.Relation.CompositionParent]
public virtual Album.Reference Album { get; set; }
[DomainModel.Invariant.Positive, DomainModel.Semantic.OrderBy]
public virtual int TrackNumber { get; set; }
[DomainModel.Invariant.Positive]
public virtual TimeSpan Length { get; set; }
[DomainModel.Invariant.Required, DomainModel.Semantic.MultilineText]
public virtual string Description { get; set; }
public virtual string AlbumText
{
get
{
return $"{Album.Instance.Artist.Instance.Name}, {Album.Instance.Name} ({Album.Instance.ReleaseYear})";
}
}
public class Reference : EntityReference<Track, int> { }
}
}
TBD (check back soon)
TBD (check back soon)
- Doing one thing well
- High-level overview
- Microservice anatomy
- Testability
- Authorization and access control
- Scalability and availability
- Containerization and deployment
- Monitoring and analysis
- Caching, local and distributed
- Event-driven processing and reliability
- Communication endpoints
- Unobtrusive customization
- Internationalization
- N-dimensional configuration
- Support of common architectural patterns
- Kernel Layer
- Platform Layer
- Scalability & Availability Layer
- Domain-Driven Design
- Processing Workflows
- User Interface
- Data representation
- Semantic Logging & Data Collection
- Testing
- Infrastructure Domains
- Business Domains
- Database
- User Interface
- Communication Endpoints
- Scalability
- Services/Libraries
- Developer Tools
- nwheels.org powered by NWheels
- Popular communities
- Books and videos