ADR-206: Back-end dependencies for the new Backpack V2

More details about this document
Latest published version:
https://adr.decentraland.org/adr/ADR-206
Authors:
sandrade-dcl
lorux0
davidejensen
pedrotambo
marianogoldman
Feedback:
GitHub decentraland/adr (pull requests, new issue, open issues)
Edit this documentation:
GitHub View commits View commits on githistory.xyz

Abstract

This is a technical proposal for the needs that we have from back-end to implement the new BackpackV2 feature.

image

Context, Reach & Prioritization

We currently have several lambdas endpoints (some of them compatible with pagination) that are already being used by the current version of the Backpack to retrieve the information about the wearables. These endpoints are:

In order to support the new features that come with the version 2 of the backpack, new endpoints are needed. We'll describe below the functional requirements that they must suffice.

Filter WEARABLES by collection

In order to give the user the possibility of seeing and managing any type of wearables (BASE, OWNED and THIRD PARTY) together in the backpack, we would need to receive all the information from a single endpoint instead of having to request them separately.

These will be the filters available in the UI to filter the wearables:

Show BASE WEARABLES ON/OFF

image

Select 1 or more COLLECTIONS ("decentraland" would be the owned wearables and any other would belong to TPW)

image

In order to be able to manage these filters, we will need an endpoint where we can specify a list of collection ids (either "Decentraland", "urn:decentraland:off-chain:base-avatars" or any third party collection) and return the list of wearables that match with those collections.

Examples:

Only owned collection
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=on-chain
Only base collection
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=base-wearable
Several third party collections
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=third-party&collectionIds=urn:decentraland:matic:collections-thirdparty:cryptoavatars,urn:decentraland:matic:collections-thirdparty:kollectiff,...
Any combination
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=on-chain,base-wearable,third-party&collectionIds=urn:decentraland:matic:collections-thirdparty:cryptoavatars,urn:decentraland:matic:collections-thirdparty:kollectiff,...

Filter EMOTES by collection

In order to give the user the possibility of seeing and managing any type of emotes (BASE or OWNED) together in the backpack, we would need to receive all the information from a single endpoint instead of having to request them separately.

This will be the filter available in the UI to filter the emotes:

Show BASE EMOTES ON/OFF

image

In order to be able to manage these filters, we will need an endpoint where we can specify a list of collection ids (either "decentraland" or "base") and return the list of emotes that match with those collections.

Examples:

Only owned collection
/<lambdasEndPoint>/:userAddress/emotes?collectionCategory=on-chain
Only base collection
/<lambdasEndPoint>/:userAddress/emotes?collectionCategory=base
Any combination
/<lambdasEndPoint>/:userAddress/emotes?collectionCategory=on-chain,base

Filter WEARABLES/EMOTES by text

The user will be able to filter the wearables/emotes by text.

image

In order to be able to do it, we will need to add a new parameter to the existing endpoints that will be used to specify a text and return the list of wearables that match with that text. The new parameter will be called textFilter and will be a string that will accept any value.

In order to be able to manage this filter, we will need an endpoint (the same described in the previous sections) where we can specify a text and return the list of wearables that match with that text.

Examples:

Filter any combination of wearables by text
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=on-chain,base-wearable,third-party&collectionIds=urn:decentraland:matic:collections-thirdparty:cryptoavatars,urn:decentraland:matic:collections-thirdparty:kollectiff&name=aviator
Filter any combination of emotes by text
/<lambdasEndPoint>/:userAddress/emotes?collectionCategory=on-chain,base-wearable&name=chic

Filter WEARABLES by category

The user will be able to filter the wearables by category.

image

In order to be able to manage this filter, we will need an endpoint (the same described in the previous sections) where we can specify the category and return the list of wearables that match with that category.

Examples:

Filter any combination of wearables by category
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=on-chain,base-wearable,third-party&collectionIds=urn:decentraland:matic:collections-thirdparty:cryptoavatars,urn:decentraland:matic:collections-thirdparty:kollectiff&categories=hat

Sort WEARABLES/EMOTES

The user will be able to sort the wearables/emotes by different criteria: newest/oldest, rarest/less rare or name A-Z/name Z-A.

image

In order to be able to manage this sorting, we will need an endpoint (the same described in the previous sections) where we can specify the sorting criteria and return the list of wearables sorted by that criteria. The sorting parameter will be a string that will accept the following values:

In cases where wearables or emotes dont have minted timestamps, they should be added at the bottom of the list.

Examples:

Sort any combination of wearables by rarest
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=on-chain,base-wearable,third-party&collectionIds=urn:decentraland:matic:collections-thirdparty:cryptoavatars,urn:decentraland:matic:collections-thirdparty:kollectiff&orderBy=rarity&direction=ASC
Filter any combination of emotes by name A-Z
/<lambdasEndPoint>/:userAddress/emotes?collectionCategory=on-chain,base&orderBy=name&direction=ASC

Get wearable market details (NEW ENDPOINT)

The user will be able to click on a wearable and open a modal with some details as:

image

To be able to request this information, the client will have to use the minted id instead of the generic id. This information is available when querying the wearables. In order to be able to get this info, we will need to create a new endpoint that will return the details of a specific wearable:

Example:

Get market details of a specific wearable
/<lambdasEndPoint>/:wearableId/market-details

Get a random list of equipped wearables (NEW ENDPOINT)

The user will be able to click on a [RANDOMIZE] button and equip a random list of wearables on his avatar.

image

In order to be able to do it, we will need to create a new endpoint that will return a random list of wearable ids from the owned wearables of the user. The wearables must be from each category, avoiding conflicts with hides and replaces whenever possible.

Example:

Get random wearables of a specific user
/<lambdasEndPoint>/:userAddress/random-wearables

Outfits

image

The outfit information needs to be multi-platform support so it will be stored in the user profile.

Regarding to the outfit image previews, they can be generated in the client when saving the outfit. There is no need to store the images in the back-end.

We may encounter the need of checking that the wearables in the outfit are valid for the current user. (What happens if the user does not have the wearable anymore?)

Equip/save wearables

image

We though about several alternatives to avoid performance issues by saving the profile every time you equip an item:

  1. Equip all the items and only when the backpack is closed, make the request to save the profile.
  2. The profile will be updated/saved in intervals of 20 seconds (to be defined) or whenever the user closes the backpack.
  3. Save the profile when the user equips a wearable.

Saving the profile would mean that the nearby users will be able to see the changes as soon as possible.

The chosen option is the number 1, taking in consideration that we can't save the profile when the user quits the application. It will only be saved when closing the backpack, just like the "save" button worked before.

Solution Space Exploration

Functional requirements

By summarizing the requirements described above, we need to implement an endpoint that complies with the following:

Filter criteria:

  1. Owner address (implicit in the URL as a path param).
  2. Collection Type (multiselect):
  3. Name: “contains”, case insensitive.
  4. Category[]: included in categories.

Sorting criteria: 5. Date:

  1. Rarity (rarest / least_rare): consider Third Party as the rarest and Base Wearables as the least rarest.
  2. Name.

Analyzed solutions

Option 1 - Single endpoint to fulfill UI

Create a single endpoint that is capable of returning a paginated collection of all wearable types unified. This includes base wearables, on-chain wearables and third-party wearables. It allows the required filtering criteria: category, name and collection type. And also the sorting criteria: date, rarity and name. This aligns 100% with what the new UI design requires. However it has many API design issues that should not be added to an endpoint that becomes part of the DCL protocol. The main issues are:

The issues above should be sufficient for avoiding going that way. But also, the nature of the issue (different types of entities treated as if they were the same) also permeates to the client, where depending on the type there will be different options available. For example, for on-chain items it makes sense to show marketplace transactions, but not for the other two types. Third party and base wearables don’t have rarity, so a compromise needs to be made regarding where to display them when sorting by rarity. Whatever is chosen can make sense for UI but not for a general purpose endpoint exposed by the Catalyst. The root cause of the issue comes from trying to treat different wearable types as if they were the same, when they are actually quite different. The forcing of this into similar-looking elements adds a lot of complexity to implementation and maintenance of the UI also.

Option 2 - Multiple endpoints - Front end code unifies

Leverage the existing endpoints created for passport, enhancing them with filtering and sorting capabilities. Change would be backwards compatible, it only adds specification for filtering and sorting criteria, but still behaves the same when nothing is specified. This solution doesn’t serve exactly what the new UI design suggests, but the endpoints can still be used to provide the same approach (unified view) by implementing the unification in the client side. The main advantages of this approach are:

The disadvantage is that the UI needs to either implement the unification by consuming the existing endpoints + adding a layer of merging the different sources into a single collection.

Option 3 - Multiple endpoints - UI changes to show items separately

This option is similar to Option 2 in regards to the API endpoints: enhancing existing endpoints with filtering / sorting capabilities. The difference would be that the UI changes to show the 3 types of wearables separately. So this makes the nature of the different types of wearables (which have different behavior) become visible to the user, rather than trying to hide it. The UI should be iterated and adapted so it doesn’t try to force the unified view of entities of different kinds. It will be easier for users to understand what is happening. It will be easier for UI developers to develop and maintain in the future. For e.g. users may wonder: why can’t I see transactions for this wearable (being a third party one)? Why are base wearables at the beginning / end when sorting by date? Or other things that make no sense in one type but do in others.

Option 4 - Unified intermediate service

This option aims to have an intermediary service, out of the Decentraland protocol, and enable use cases for our reference client. In this approach we would be using the endpoints resulting from Option 3 in the service for wearables and doing the merge of the three while paginating the results to the client. In this case the solution in the frontend side would be similar to Option 1, having a single endpoint for paginating all kinds of wearables. It remains to be analyzed where this intermediate service would be hosted, whether inside or outside the Catalysts.

Conclusion

After discussing the different solutions between Platform, Renderer and Product team, we agreed to go with the Option 4 since it has the best effort/benefit balance.

Participants

RFC 2119 and RFC 8174

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

License

Copyright and related rights waived via CC0-1.0. DRAFT Draft