This is a technical proposal for the needs that we have from back-end to implement the new BackpackV2 feature.
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:
/lambdas/collections/wearables?collectionId=urn:decentraland:off-chain:base-avatars
/lambdas/users/:userId/wearables?includeDefinitions=true
/lambdas/users/:userId/emotes?includeDefinitions=true
/lambdas/users/:userId/third-party-wearables/:collectionId&includeDefinitions=true
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.
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:
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.
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=on-chain
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=base-wearable
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=third-party&collectionIds=urn:decentraland:matic:collections-thirdparty:cryptoavatars,urn:decentraland:matic:collections-thirdparty:kollectiff,...
/<lambdasEndPoint>/:userAddress/wearables?collectionCategory=on-chain,base-wearable,third-party&collectionIds=urn:decentraland:matic:collections-thirdparty:cryptoavatars,urn:decentraland:matic:collections-thirdparty:kollectiff,...
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:
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.
/<lambdasEndPoint>/:userAddress/emotes?collectionCategory=on-chain
/<lambdasEndPoint>/:userAddress/emotes?collectionCategory=base
/<lambdasEndPoint>/:userAddress/emotes?collectionCategory=on-chain,base
The user will be able to filter the wearables/emotes by text.
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.
/<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
/<lambdasEndPoint>/:userAddress/emotes?collectionCategory=on-chain,base-wearable&name=chic
The user will be able to filter the wearables by category.
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.
/<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
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.
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:
newest
oldest
rarest
less_rare
name_a_z
name_z_a
In cases where wearables or emotes dont have minted timestamps, they should be added at the bottom of the list.
/<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
/<lambdasEndPoint>/:userAddress/emotes?collectionCategory=on-chain,base&orderBy=name&direction=ASC
The user will be able to click on a wearable and open a modal with some details as:
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:
/<lambdasEndPoint>/:wearableId/market-details
The user will be able to click on a [RANDOMIZE] button and equip a random list of wearables on his avatar.
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.
/<lambdasEndPoint>/:userAddress/random-wearables
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?)
We though about several alternatives to avoid performance issues by saving the profile every time you equip an item:
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.
By summarizing the requirements described above, we need to implement an endpoint that complies with the following:
Filter criteria:
Sorting criteria: 5. Date:
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.
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.
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.
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.
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.
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.