Skip to content

OBIP-0003: Channels #13

@drwasho

Description

@drwasho

OBIP-0003: Channels

Proposal: https://github.com/OpenBazaar/obips/blob/master/obip-0003.mediawiki
Author: @cpacia

  OBIP: 3
  Title: Channels
  Author: Chris Pacia 
  Discussions-To: #openbazaar-2_0 on Slack, Github Issues, or 
  Status: Draft
  Type: Standards Track
  Created: 2017-9-27
  License: Public Domain

Abstract

Channels are a feature designed to improve the browsing experience in OpenBazaar. Being a decentralized application OpenBazaar faces challenges displaying interesting, relevant, and timely content to users. Most e-commerce platforms solve this problem by using their access to their centralized listing database to curate content for their home page or category landing pages. Since most OpenBazaar implementations are oriented towards consumers and run on either home computers on or mobile devices, it's not feasible for the software to index all listings.

One strategy for dealing with this limitation is to have the application download content from a centralized curator. While this approach would mostly work, it goes strongly against OpenBazaar's core value of decentralization.

The alternative presented here is to open the curation to everyone and allow users to seed their curated content on the OpenBazaar network. By allowing everyone to participate in curation we avoid having a single point of failure. Further we can take advantage of OpenBazaar's distributed architecture to distribute the content around the network ensuring the data will remain available even if the content creator is offline.

Definitions

A channel is one or more user curated pages of content.

A page is a static JSON document containing one or more views that is interpreted by clients. Pages can contain links to other pages creating a browsing experience similar to that of the web.

A view is the most basic element on a page. It contains the data to be displayed and information about how to display it.

Specification

Channel Schema

The channel schema consists of a JSON object containing some metadata and a list of views (to be rendered in order veriticaly):

{
  "name": "OB1",
  "logo": "zb2rhcQdW4Jb9YmJUASEumQg4xetuc9tob9Hofn24g74c12p7",
  "slug": "index",
  "lastUpdated": ""2017-09-28T03:15:51.785762669Z",
  "searchEndpoint": "https://search.ob1.io/search/listings",
  "onClick": "https://clickdata.ob1.io/channel",
  "onLoad": "https://loaddata.ob1.io/channel",
  "version": 1,
  "views": [
    // views here
  ]
}

Only name, logo, slug and views are required. onClick and onLoad are endpoints which clients are expected to POST to for data collection purposes. The POST body should contain the loaded page URI for onLoad or the URL of the clicked item for onClick.
The current version is 1. Slug must unique for each page and set to index for the main channel page.

Types of Views

ImageView

Self explanatory. Used for banner images, product promotions, etc. Images should be hosted on IPFS and can optionally link to a product or another page. Links may use either ob:// (for listings, user pages, or channel pages) or http:// (for channel pages only).

{
  "type": "IMAGE_VIEW",
  "imageHash": "zb2rhcQdW4Jb9YmJUASEumQg4xetuc9tob9Hofn24g74c12p7",
  "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/another_channel_page",
  "height": 275,
  "width": 580
} 

TextView

Display text on the page.

{
  "type": "TEXT_VIEW",
  "text": "Welcome to my channel!",
  "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/another_channel_page",
  "size": 28,
  "font": "noto sans",
  "color": "#343434",
  "align": "center"
} 

ListingGridView

A 4 by x grid of listing cards. Title should be displayed at the top of the view. Button is optional and it displays at the
bottom of the view and gives the ability to link to another page. The listing data must be included.

{  
   "type":"LISTING_GRID_VIEW",
   "title":"New Listings",
   "button":{  
      "Text":"See More",
      "Link":"ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/another_channel_page"
   },
   "listings":[  
      {  
         "vendor":{  
            "id":"QmWBSdbs7LLR7BdFgtKQA7CUq8aCzoTi74V7UwiwvfYpU5",
            "handle":"@yPayne",
            "avatarHashes":{  
               "tiny":"QmTHCaDpznJStWvPUSiKNDd53VVZmPtnrHx5diGP5gskCx",
               "small":"QmfVecQaoy1pZD3wsHHC82kYg24yhVaqBsAzm5aJCabXPQ"
            }
         },
         "data":{  
            "hash":"zb2rhcQdW4Jb9YmJUASEumQg4xetuc9tob9Hofn24g74c12p7",
            "slug":"air-direct-amplifier",
            "title":"Air Direct Amplifier",
            "thumbnail":{  
               "small":"QmfVecQaoy1pZD3wsHHC82kYg24yhVaqBsAzm5aJCabXPQ",
               "medium":"QmS1z4qW1SiDNtLD1Bfno8WEbFUV8qwb5CQxgR6BREyVTJ"
            },
            "price":{  
               "currencyCode":"btc",
               "amount":34
            },
            "nsfw":true
         }
      }
   ]
}

PaginatedListingView

Similar to the ListingGridView but designed to allow a large number of listing cards to be displayed on the page by using pagination. Clients are free to decide how many listings to display per page and whether or not to offer sorting functionality.

{  
   "type":"PAGINATED_LISTING_VIEW",
   "count": 200,
   "listings":[  
      {  
         "vendor":{  
            "id":"QmWBSdbs7LLR7BdFgtKQA7CUq8aCzoTi74V7UwiwvfYpU5",
            "handle":"@yPayne",
            "avatarHashes":{  
               "tiny":"QmTHCaDpznJStWvPUSiKNDd53VVZmPtnrHx5diGP5gskCx",
               "small":"QmfVecQaoy1pZD3wsHHC82kYg24yhVaqBsAzm5aJCabXPQ"
            }
         },
         "data":{  
            "hash":"zb2rhcQdW4Jb9YmJUASEumQg4xetuc9tob9Hofn24g74c12p7",
            "slug":"air-direct-amplifier",
            "title":"Air Direct Amplifier",
            "thumbnail":{  
               "small":"QmfVecQaoy1pZD3wsHHC82kYg24yhVaqBsAzm5aJCabXPQ",
               "medium":"QmS1z4qW1SiDNtLD1Bfno8WEbFUV8qwb5CQxgR6BREyVTJ"
            },
            "price":{  
               "currencyCode":"btc",
               "amount":34
            },
            "nsfw":true
         }
      }
   ]
}

UserGridView

A 4 by x grid of user cards. Title should be displayed at the top of the view. Button is optional and it displays at the
bottom of the view and gives the ability to link to another page. The user profile data must be included.

{  
   "type":"USER_GRID_VIEW",
   "title":"Top vendors",
   "button":{  
      "Text":"See More",
      "Link":"ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/another_channel_page"
   },
   "users":[  
      {  
          "id":"QmWBSdbs7LLR7BdFgtKQA7CUq8aCzoTi74V7UwiwvfYpU5",
          "handle":"yPayne.id",
          "avatarHashes":{  
             "tiny":"QmTHCaDpznJStWvPUSiKNDd53VVZmPtnrHx5diGP5gskCx",
             "small":"QmfVecQaoy1pZD3wsHHC82kYg24yhVaqBsAzm5aJCabXPQ"
          },
          "headerHashes":{  
             "tiny":"QmTHCaDpznJStWvPUSiKNDd53VVZmPtnrHx5diGP5gskCx",
             "small":"QmfVecQaoy1pZD3wsHHC82kYg24yhVaqBsAzm5aJCabXPQ"
          },
          "shortDescription": "Webstore specialized in selling unique, interesting and high-quality..."  
      }
   ]
}

PaginatedUserView

The user card equivilent of PaginatedListingView.

{  
   "type":"PAGINATED_USER_VIEW",
   "count": 200,
   "users":[  
      {  
          "id":"QmWBSdbs7LLR7BdFgtKQA7CUq8aCzoTi74V7UwiwvfYpU5",
          "handle":"yPayne.id",
          "avatarHashes":{  
             "tiny":"QmTHCaDpznJStWvPUSiKNDd53VVZmPtnrHx5diGP5gskCx",
             "small":"QmfVecQaoy1pZD3wsHHC82kYg24yhVaqBsAzm5aJCabXPQ"
          },
          "headerHashes":{  
             "tiny":"QmTHCaDpznJStWvPUSiKNDd53VVZmPtnrHx5diGP5gskCx",
             "small":"QmfVecQaoy1pZD3wsHHC82kYg24yhVaqBsAzm5aJCabXPQ"
          },
          "shortDescription": "Webstore specialized in selling unique, interesting and high-quality..."  
      }
   ]
}

SlideshowView

A view which which rotates through the provided image views.

{
  "type": "SLIDESHOW_VIEW",
  "height": 250,
  "width": 400,
  "images": [
    {
      "imageHash": "zb2rhcQdW4Jb9YmJUASEumQg4xetuc9tob9Hofn24g74c12p7",
      "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/another_channel_page"
    }
  ]
} 

CategoryView

A list of categories for the client to render. The optional field breadcrumbs is used to display the current nesting.

{
  "type": "CATEGORY_VIEW",
  "categories": [
    {
      "name": "Marvel",
      "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/marvel"
    },
    {
      "name": "Spiderman",
      "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/spiderman"
    },
    {
      "name": "Superman",
      "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/superman"
    }
  ],
  "breadcrumbs": [
    {
      "name": "Books",
      "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/books"
    },
    {
      "name": "Comic Books",
      "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/comic_books"
    }
  ]
} 

HBox

An HBox allows ImageViews to be aligned horizontally next to each other. HBoxes can be nested inside other HBoxes or inside VBoxes. Only ImageViews, TextViews, HBoxes, and VBoxes are currently supported inside HBoxes. All other types should be ignored.

{
  "type": "HBOX",
  "padding": 10,
  "views": [
  	{
	  "type": "IMAGE_VIEW",
	  "imageHash": "zb2rhcQdW4Jb9YmJUASEumQg4xetuc9tob9Hofn24g74c12p7",
	  "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/another_channel_page",
	  "height": 275,
	  "width": 580
	},
	{
	  "type": "IMAGE_VIEW",
	  "imageHash": "zb2rhcQdW4Jb9YmJUASEumQg4xetuc9tob9Hofn24g74c12p7",
	  "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/another_channel_page",
	  "height": 275,
	  "width": 580
	} 
  ]
} 

VBox

A VBox allows ImageViews to be aligned vertically on top of each other. VBoxes can be nested inside other VBoxes or inside HBoxes. Only ImageViews, TextViews, HBoxes, and VBoxes are currently supported inside VBoxes. All other types should be ignored.

{
  "type": "VBOX",
  "padding": 10,
  "views": [
  	{
	  "type": "IMAGE_VIEW",
	  "imageHash": "zb2rhcQdW4Jb9YmJUASEumQg4xetuc9tob9Hofn24g74c12p7",
	  "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/another_channel_page",
	  "height": 275,
	  "width": 580
	},
	{
	  "type": "IMAGE_VIEW",
	  "imageHash": "zb2rhcQdW4Jb9YmJUASEumQg4xetuc9tob9Hofn24g74c12p7",
	  "Link": "ob://QmYj1ojj3cRKrmkQR3o8KtPqmTbgsZWsgq5grpUpAbjiYx/channel/another_channel_page",
	  "height": 275,
	  "width": 580
	} 
  ]
} 

Loading a channel

When entering and saving a new channel a user should be able to enter either an OB URI (ob://ob1.io/channel) or HTTP URL (https://ob1.io/channel).
Clients should be able to fetch the main page json from either source.

Extensibility

Clients should ignore view types they do not know how to parse. This allows us to introduce new views without breaking old clients.

FAQ

Will the channel be slow to load and provide a bad experience?

This OBIP calls for listing data and user data to be provided in each view which means the only loading that needs to be done is the initial JSON document and images. It would be great to make it so these views do not need to provide the data and instead it could be fetched from IPNS but current IPNS speeds are too slow for this to be feasible. As IPNS optimizations come to fruition this option can be revisted.

As for initial page load, pages served over IPNS will be subject to IPNS load times but serving pages via HTTP is an option for those that care about page load speed and have the resources and technical knowledge to do so. Serving pages via HTTP also allows for dynamic page creation.

Given that the data must be provided with each view, wont the channel data get stale?

For pages served via HTTP the server can build the page using the most up to date data it knows about.

For pages served via IPNS, the responsibility falls on the channel creator to update and republish their channel periodically. Implementions can fairly easily provide automated functionality to iterate over the channel data, update each listing/user with current data, and republish. How stale a channel is will be dependent on the tools one use to curate the channel and how committed they are to maintaining it.

Wont users see a bunch of unmaintained channels with stale data?

Channels served via IPNS will drop out of the network after a week if the creator does not republish his data. It's unlikely stale channels will persist. Additionally this OBIP does not specify channel discovery which could itself be curated by a channel and only list well maintained channels.

How does a user actually curate a channel? Do they need a crawler? What tool do they use? Or is it entirely a manual process?

Curation is not specified by this OBIP as it will depend on the tools available to the user. API calls to create, update, and publish a channel are pretty easy to create and fairly easy to use. Crawlers are not needed per se as curators can find listings via other channels or via search. Though specialized crawlers might be desireable for curating listings behind Tor, as an example. Open source crawlers that do this already exist.

Less technical users will probably need to wait until UIs are created which make building channels more user friendly. Even without such UIs simply creating a JSON text file is orders of magnitude easier to do than building a search engine and a step in the right direction.

Is the average person going to do this? What is their incentive to do so?

Average people creating and sharing channels would certainly improve user engagment and interaction with the app but isn't necessary for the purpose of improving the browsing experience. The user experience would still be much improved if only several big players create and maintain channels provided that there is free entry and competition.

Further, there may be a financial incentive to create a channel. It's pretty trivial right now to create a "Buy ad space on my channel" listing which may provide a revenue stream large enough to compensate for the time invested into maintaining the channel.

Isn't there going to be all kinds of cross platform issues when rending the channel?

The channel schema provides the data to be displayed and a rough suggestion about how that data should be used. It's up to each client implementation to decide how best to render the data. For example, the ListingGridView might work well as a 4x2 grid on desktop, but mobile designers may choose to render it as an ImageSwitcher with swipe gestures. Futher platform specific channels can also be created, ex) ob://ob1.io/channel/mobile.

Doesn't this design preclude things pagination and/or sorting by price/rating, etc?

No. The PaginatedListingView and PaginatedUserView can probably hold several thousand listing/user data objects while still keeping the page to a reasonable size. Clients can paginate the listings/user cards and offer sorting as they desire. Should a page require more than one thousand listings, say, it would probably make sense, both from a UX and efficiency perspective, to break that view up into separate pages. For example, if you are trying to build a page that contains comic book listings and you have more than one thousand comic books, you should probably break the page up into multiple pages of comic book subcategories.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions