Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 113 additions & 109 deletions obip-0004.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,29 @@ Posts allow a Vendor to upload a message or image in a dedicate space in their s
1. As a Publisher, I can post a message {text, image} that is displayed in my store.
2. As a Publisher, I can edit a message that is displayed in my store.
3. As a Publisher, I can delete a message this is displayed in my store.
4. As a Publisher, I can traverse a history of messages in my store.
4. As a Publisher, I can fetch the previous posts in my store.

#### Role: User

1. As a user, I can read a message {text and/or image} posted by a Publisher.
2. As a user, I can traverse a history of messages {text and/or image} posted by a Publisher.
1. As a user, I can read a post {text and/or image} created by a Publisher.
2. As a user, I can fetch previous posts {text and/or image} created by a Publisher.

## Specification

There are 3 types of posts:re

1. **Post.** A generic, standalone social post.
2. **Comment.** A comment against another post, listing, or store.
3. **Repost.** The equivalent of a 'retweet', only for any type of content on the OpenBazaar network.

A post should allow the publisher to include:

1. A short title (max. 280 characters)
- The title field can be used as a title for a long-form post, or as a microblog post in itself (i.e. tweet-style).
2. A long-form post (max. 50,000 characters)
- This field is used for blog-style posts
3. Images
- An array of up to 30 images can be attached to the post
4. Tags
- An array of up to 40 tags
5. A timestamp
1. **`status`.** This is a short content space where a user can post the equivalent of a 'tweet'. The maximum character limit is 280.
2. **`longForm`.** This is a longer content space than `status` ideal of Medium-style blog posts. The maximum character limit is 50,000.
3. **`images`.** A post can carry up to 30 images reference by their IPFS hashes.
4. **`channels`.** Similar to IRC, posts can be targeted for up to 30 channels. Posts can be curated based on whether posts are relevant and included in a feed for that channel.
5. **`tags`.** Each post can carry up to 50 tags, which allow for more granular discovery of a post in their store, or in a channel.
6. **`reference`.** Required when making a comment or repost, which points to the target content. While originally designed for other posts, any other valid content address on the network can be used (i.e. listing, store, image etc).

All posts need to be digitally signed to establish authenticity, and will include a slug for IPNS resolution so the publisher can edit their post.

Expand All @@ -63,21 +66,17 @@ All posts need to be digitally signed to establish authenticity, and will includ
The protobuf spec:

```
syntax = "proto3";
option go_package = "pb";


import "google/protobuf/timestamp.proto";
import "contracts.proto";

message Post {
string slug = 1;
ID vendorID = 2;
string title = 3;
string status = 3;
string longForm = 4;
repeated Image images = 5;
repeated string tags = 6;
google.protobuf.Timestamp timestamp = 7;
repeated string channels = 7;
PostType postType = 8;
string reference = 9;
google.protobuf.Timestamp timestamp = 10;

message Image {
string filename = 1;
Expand All @@ -87,6 +86,12 @@ message Post {
string small = 5;
string tiny = 6;
}

enum PostType {
POST = 0;
COMMENT = 1;
REPOST = 2;
}
}

message SignedPost {
Expand All @@ -112,28 +117,27 @@ Returns an array of posts from the user or a peer (i.e. `/ob/posts/:peerId`):

```JSON
[
{
"hash": "zb2rhdrJUgp17bvjnEW98s9C2eToZHep1eh5i7SBp9jhBpREA",
"images": [
{
"medium": "zb2rhaFhqziCWk1zo5tMRxQEUchfvJFaGG4DY1anEoR4GnYrN",
"small": "zb2rhbDCeEiTTunugWPaRRKFCfNKUaB7aCR53nrPnMa9usZXY",
"tiny": "zb2rhgqJDbshwAgPjs7X2h4mDm3V3BpLbp4tFGqkg1LNkg9yV"
},
{
"medium": "zb2rhY4sqZehNgKD7ehxHiG7z3wnpKZEeNccWxrfx1GmAckxy",
"small": "zb2rhhMRWCb5ozMdez8JePnZnh9WRxyTCJVNk7CfLNVVaUmhz",
"tiny": "zb2rhmxApBVCHh426vnYSJGSDH4KpKpqKyvY2CAWmaiuHd8tZ"
}
],
"slug": "multiimagetest",
"tags": [
"zb2rhXoKEJtXxB5pcxhmcLu1aCCY3MRHR1Vc4tSJMyzPy8KJv",
"#freeWynona"
],
"timestamp": "2017-10-05T00:13:53.892275067Z",
"title": "multiimagetest"
}
{
"channels": [
"test"
],
"hash": "zb2rhhXuXraeA2KVJwXmfiSVrhLh8sCQsbgzSXMPhubnnebDn",
"images": [
{
"medium": "zb2rhaFhqziCWk1zo5tMRxQEUchfvJFaGG4DY1anEoR4GnYrN",
"small": "zb2rhbDCeEiTTunugWPaRRKFCfNKUaB7aCR53nrPnMa9usZXY",
"tiny": "zb2rhgqJDbshwAgPjs7X2h4mDm3V3BpLbp4tFGqkg1LNkg9yV"
}
],
"postType": "POST",
"reference": "",
"slug": "testy7",
"status": "testy7",
"tags": [
"Yo"
],
"timestamp": "2018-10-11T12:17:09.434846957Z"
}
]
```

Expand All @@ -143,45 +147,41 @@ Returns an individual post from the user or a peer (i.e. `/ob/post/:peerId/:slug

```JSON
{
"post": {
"slug": "multiimagetest",
"vendorID": {
"peerID": "QmVdst57mJuW8Tr9owADqWmirY5Gao9zZMnbbL4WavKJvB",
"handle": "",
"pubkeys": {
"identity": "CAESIEokc1r9Wfe4IyqA9P/56dO+5W1Hv9eOi2PXdUBDUf5X",
"bitcoin": "AjjghznFUNeAkgmEdKYOESzj+PXFvVHUv+jbNWWQKkwG"
},
"bitcoinSig": "MEQCIAaKg1Cr676NVo7dz1KibSvvhjyrAXQceYakKwYR13+oAiBmAWqIyTWMuMPeVItwPzS1N2SDYeR5H4cD+uxGv1AghQ=="
},
"title": "multiimagetest",
"longForm": "This is a test post dawg.",
"images": [
{
"filename": "cat",
"original": "zb2rhe2o6WbHqcER5VUKsMUbQrmpCC6ihg8qZ4JS9wVgKz9wm",
"large": "zb2rhmBUB9i7UkfmeD3obJYK3FFS5K8N8QHaUanG8UWLVBHiY",
"medium": "zb2rhaFhqziCWk1zo5tMRxQEUchfvJFaGG4DY1anEoR4GnYrN",
"small": "zb2rhbDCeEiTTunugWPaRRKFCfNKUaB7aCR53nrPnMa9usZXY",
"tiny": "zb2rhgqJDbshwAgPjs7X2h4mDm3V3BpLbp4tFGqkg1LNkg9yV"
},
{
"filename": "random",
"original": "zdj7Wazpqc5dGZ9yyKweKGjkGF3mAj5cjrWSV3QisHU34UsaQ",
"large": "zb2rhemVicsnTAo454S6Cdq2Ct677B47ArbQ7AqNtWYWUbvBQ",
"medium": "zb2rhY4sqZehNgKD7ehxHiG7z3wnpKZEeNccWxrfx1GmAckxy",
"small": "zb2rhhMRWCb5ozMdez8JePnZnh9WRxyTCJVNk7CfLNVVaUmhz",
"tiny": "zb2rhmxApBVCHh426vnYSJGSDH4KpKpqKyvY2CAWmaiuHd8tZ"
}
],
"tags": [
"zb2rhXoKEJtXxB5pcxhmcLu1aCCY3MRHR1Vc4tSJMyzPy8KJv",
"#freeWynona"
],
"timestamp": "2017-10-05T00:13:53.892275067Z"
"post": {
"slug": "testy5",
"vendorID": {
"peerID": "QmS7QyLXGgxge2Nap3wnZr1pBdxDSJ4xu1dGVKnL4XW9YQ",
"handle": "",
"pubkeys": {
"identity": "CAESINypt5aYTJ8ssxKNDusANNH9HFqKsDOC3VJT4sYhPato",
"bitcoin": "A5EJy0XaW/S+OHn2xebf8Nb6kv54H6+lsOBlOpWXb/46"
},
"bitcoinSig": "MEQCIH0h0NZmJE5gWgo5soUdkggnNYSBvykWvm2DbhjW+CgHAiB309+MUBtnAkyFaaI3lEVzFUjwZRm/RU7pGFt1NT4+cA=="
},
"hash": "zb2rhdrJUgp17bvjnEW98s9C2eToZHep1eh5i7SBp9jhBpREA",
"signature": "evhmoAw3S/Qx3lmTStd0esnhPjwgWCfRncpGltyLjW3wPG7Gh8kd4uRSsS+LwoPMpVVvibLuIDi0WwyfsrkODA=="
"status": "testy5",
"longForm": "This is a test post dawg.",
"images": [
{
"filename": "cat",
"original": "zb2rhe2o6WbHqcER5VUKsMUbQrmpCC6ihg8qZ4JS9wVgKz9wm",
"large": "zb2rhmBUB9i7UkfmeD3obJYK3FFS5K8N8QHaUanG8UWLVBHiY",
"medium": "zb2rhaFhqziCWk1zo5tMRxQEUchfvJFaGG4DY1anEoR4GnYrN",
"small": "zb2rhbDCeEiTTunugWPaRRKFCfNKUaB7aCR53nrPnMa9usZXY",
"tiny": "zb2rhgqJDbshwAgPjs7X2h4mDm3V3BpLbp4tFGqkg1LNkg9yV"
}
],
"tags": [
"Yo"
],
"channels": [
"test"
],
"postType": "REPOST",
"reference": "zb2rhbnwaLFrTfw8uGzZKPfS16SLt14FmEFNghrGRZUhY3g2Y",
"timestamp": "2018-10-11T12:08:38.639363790Z"
},
"hash": "zb2rheDrgxGWWfiJBnFCAp7xwmK2Yt1AistCBzaYCrFB1adpN",
"signature": "NVg62CekPbI+3j6YvaTokSi0H8Z5cbMgTW84yT+P5U6E1mYg/0vdF3c6OggW9BcSd9bhQR6wfgaWgurxmi3OBQ=="
}
```

Expand All @@ -191,28 +191,25 @@ Creates a new post:

```JSON
{
"title": "multiimagetest-4",
"status": "testy7",
"longForm": "This is a test post dawg.",
"images": [{
"postType": "POST",
"reference": "",
"images": [
{
"filename": "cat",
"large": "zb2rhmBUB9i7UkfmeD3obJYK3FFS5K8N8QHaUanG8UWLVBHiY",
"medium": "zb2rhaFhqziCWk1zo5tMRxQEUchfvJFaGG4DY1anEoR4GnYrN",
"original": "zb2rhe2o6WbHqcER5VUKsMUbQrmpCC6ihg8qZ4JS9wVgKz9wm",
"small": "zb2rhbDCeEiTTunugWPaRRKFCfNKUaB7aCR53nrPnMa9usZXY",
"tiny": "zb2rhgqJDbshwAgPjs7X2h4mDm3V3BpLbp4tFGqkg1LNkg9yV"
},
{
"filename": "random",
"tiny": "zb2rhmxApBVCHh426vnYSJGSDH4KpKpqKyvY2CAWmaiuHd8tZ",
"small": "zb2rhhMRWCb5ozMdez8JePnZnh9WRxyTCJVNk7CfLNVVaUmhz",
"medium": "zb2rhY4sqZehNgKD7ehxHiG7z3wnpKZEeNccWxrfx1GmAckxy",
"original": "zdj7Wazpqc5dGZ9yyKweKGjkGF3mAj5cjrWSV3QisHU34UsaQ",
"large": "zb2rhemVicsnTAo454S6Cdq2Ct677B47ArbQ7AqNtWYWUbvBQ"
}
],
"tags": [
"zb2rhXoKEJtXxB5pcxhmcLu1aCCY3MRHR1Vc4tSJMyzPy8KJv",
"#freeWynona"
"Yo"
],
"channels": [
"test"
]
}
```
Expand All @@ -223,29 +220,25 @@ Edits an existing post:

```JSON
{
"slug": "multiimagetest4",
"title": "multiimagetest-4",
"longForm": "This is a test post yo.",
"images": [{
"status": "testy7",
"longForm": "This is a test post son.",
"postType": "POST",
"reference": "",
"images": [
{
"filename": "cat",
"large": "zb2rhmBUB9i7UkfmeD3obJYK3FFS5K8N8QHaUanG8UWLVBHiY",
"medium": "zb2rhaFhqziCWk1zo5tMRxQEUchfvJFaGG4DY1anEoR4GnYrN",
"original": "zb2rhe2o6WbHqcER5VUKsMUbQrmpCC6ihg8qZ4JS9wVgKz9wm",
"small": "zb2rhbDCeEiTTunugWPaRRKFCfNKUaB7aCR53nrPnMa9usZXY",
"tiny": "zb2rhgqJDbshwAgPjs7X2h4mDm3V3BpLbp4tFGqkg1LNkg9yV"
},
{
"filename": "random",
"tiny": "zb2rhmxApBVCHh426vnYSJGSDH4KpKpqKyvY2CAWmaiuHd8tZ",
"small": "zb2rhhMRWCb5ozMdez8JePnZnh9WRxyTCJVNk7CfLNVVaUmhz",
"medium": "zb2rhY4sqZehNgKD7ehxHiG7z3wnpKZEeNccWxrfx1GmAckxy",
"original": "zdj7Wazpqc5dGZ9yyKweKGjkGF3mAj5cjrWSV3QisHU34UsaQ",
"large": "zb2rhemVicsnTAo454S6Cdq2Ct677B47ArbQ7AqNtWYWUbvBQ"
}
],
"tags": [
"zb2rhXoKEJtXxB5pcxhmcLu1aCCY3MRHR1Vc4tSJMyzPy8KJv",
"#freeWynona"
"Yo"
],
"channels": [
"test"
]
}
```
Expand Down Expand Up @@ -273,6 +266,17 @@ This OBIP extends the protocol and creates a collection of new APIs, as well as

Posts do not alter the existing database or API calls, so disruption to clients should be minimal. As a result, clients can choose to support this feature - if at all - at their leisure.

## Reference Implementation
## Future work

There are two primary areas of work that need improvments:

1. Feed
2. Reactions

### Feed

The 'feed' is simply a list of posts based on the nodes you follow, or posts published to a certain channel or with a tag. The feed will not require a user to fetch a list of posts manually from each node that they follow. Currently, third parties can construct a social feed of posts based on a list of `peerIds`, a channel, or tag. We aim to explore technologies such as IPFS pubsub and [OrbitDB](https://github.com/orbitdb/orbit-db) in further detail to remove this requirement and allow a more decentralized construction of feeds.

### Reactions

https://github.com/drwasho/openbazaar-go/tree/posts
'Reactions' are social reactions: like, love, smile etc. While this data could exist as its own type of post, this solution isn't scalable and would require frequent republishing of the root IPNS directory, and undermining the ability of peers to seed the latest version of the store. A decentralised solution is required to handle rapidly dynamic data; again, OrbitDB seems like a good candidate to investigate.