Context
There is a unique challenge new to Web3 composable ecosystems when defining relationships between two sides that are both user authored content. This challenge does not exist in traditional Web2 systems because, in those systems, a central authority has the ability to enforce custom rules on one side of the relationship (e.g., users can only leave one review for a product, as regulated by the central authority of the Amazon marketplace). In Web3 systems, all relationship rules must be defined at the protocol level.
Ceramic currently supports two account relationship types:
- SINGLE - A developer can define a
BasicProfile
schema and ensure only one document type using this definition can be created per user account (i.e., one DID can have oneBasicProfile
) - LIST - A developer can allow users within a decentralized social media platform to create as many
Post
instances as they want (i.e., one DID can have manyPosts
)
Problem
The existing relationship types do not cover all use cases. For example, in a decentralized marketplace, a developer may want to ensure that each user account (or DID) can only create only one Review
for a specific Product
. However, they may also want to allow users to create Review
s for as many individual Product
s as they want, so long as they can only leave 1 Review
per Product
Ceramic does not currently natively support this use case, which means a user could hypothetically write multiple Reviews
for a single Product
. Developers can attempt to work around the existing limitations by consuming all the Reviews
a user creates for one Product
and applying a custom filter so that only one Review
is displayed. However, this is inefficient and additionally introduces centralized application bias in each different data consuming application within the ecosystem.
Goals
- Transfer decision load or relationship logic from the developer to natively within the protocol to
- Improve the developer experience
- Minimize centralization and bias bottlenecks in data consumption
- Continue enabling products built around “user-controlled data” as opposed to “application-controlled” data
- Improve composability between apps
Solution
This problem is solved by introducing a new “unique list” relationship type that is defined at the protocol level. This new relationship type is called “SET”, after the data structure known in existing computer science definitions.
With the SET feature, a developer can ensure that each user account (or DID) can only create ONE Review
for a specific Product
. However, users are allowed to create Review
s for as many individual Product
s as they want, so long as they only leave 1 review per product.
Code sample: Using SET on a subfield that defines a relation to another document
## very simple boolean-style review shown below
type Product @loadModel(id: "...") {}
type Review @createModel(accountRelation: SET, accountRelationField: "postID") {
postID: StreamID! @documentReference(model: "Post")
review: Boolean!
}
Code sample: Using SET without a relation to another document
## very simple boolean-style trust signal shown below
type TrustedResource @createModel(accountRelation: SET, accountRelationField: "uri") {
uri: URI!
review: Boolean!
}
Requirements
Feature | Details | Priority |
---|---|---|
New relationship type | Introduce a custom syntax that allows developers to define a unique list relationship between accounts and a specific model type | Must have |
Relationship type defined at model schema level | The relationship must be defined during model schema creation. | Must have |
By schema controller | Can only be defined by controller of the schema | Must have |
Cannot be changed | The relationship for a schema cannot be changed later (i.e. from SET to LIST) | Must have |
Relationship value defined at model level | The actual value (i.e., what other thing the model has a SET relationship with) is defined at time of model schema creation | Must have |
Relationship can be deleted and undeleted | E.g., once a user has created a review for a product, the review can be deleted and also undeleted. | Must have |
Compatible with other new features | Allows developers to equitably use SET alongside other features (such as field locking), and in doing so, prevents “conflicting” interactions between the two features | Must have |
Appendix
Existing relationship types supported by ComposeDB
SINGLE
- A developer can defines a
BasicProfile
schema and ensure only one document type using this definition can be created per user account - (i.e., one DID can have one
BasicProfile
)
type BasicProfile
@createModel(accountRelation: SINGLE, description: "Very basic profile")
{
displayName: String! @string(maxLength: 50)
}
LIST
- A developer can allow users within a decentralized social media platform to create as many
Post
instances as they want - (i.e., one DID can have many
Post
s)
type Message
@createModel(accountRelation: LIST, description: "Direct message model")
{
recipient: DID! @accountReference
directMessage: String! @string(maxLength: 50)
}