Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OBIP-0004: Posts #14

Open
drwasho opened this issue Oct 4, 2017 · 27 comments
Open

OBIP-0004: Posts #14

drwasho opened this issue Oct 4, 2017 · 27 comments
Assignees

Comments

@drwasho
Copy link
Member

drwasho commented Oct 4, 2017

OBIP-0004: Posts

Proposal: https://github.com/OpenBazaar/obips/blob/master/obip-0004.md
Author: @drwasho

  OBIP: 4
  Title: Posts
  Author: Dr Washington Y. Sanchez
  Status: Draft
  Type: Standards Track
  Created: 2017-08-27

Abstract

  • This OBIP describes the addition of a new type of content that can be published and shared on the network by users: posts
  • Posts enable a user to publish written content that can be viewed by other users visiting their store or via third party search
  • Posts can be used for market-related activities such as: advertising listings, announce store updates, publish a new coupon for a special offer etc
  • Moreover, posts can also be used for non-market activities and serve as a platform for censorship-resistant expression on the network, encouraging non-vendors to regularly use the network

Motivation

OpenBazaar has limited tools for Vendors to engage with potential customers. Engagement can be in the form of advertising a listing, announcing a store update, brand-building, announcing special offers or coupons for a sale to name a few. Users in general can also benefit from these tools by blogging interesting items they have seen on the network, and driving sales for Vendors (i.e. OB influencers).

Aside from side-channels (i.e. off the OpenBazaar network), Vendors can only communicate to potential buyers via the About section of their profile, or via direct message. The About section is limited in form and function, and its history is not traversable. Direct message is excellent for one-on-one communication, but it can only be initiated by a user visiting the store.

What is required is a means for Vendors to publish a blog-style post that users can view when visiting their store.

Requirements

Posts allow a Vendor to upload a message or image in a dedicate space in their store. Posts have traversable history, designed for one-way communication from the Vendor to users. The purpose of posts is to inform visitors of any content they feel necessary to drive sales and/or engage with users (i.e. announcements, brand building, promotions, coupons etc).

User Stories

Role: Publisher

A 'publisher' is a vendor or user that is publishing a post on their node for other users to consume.

  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.

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.

Specification

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

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.

Protobuf

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 longForm                     = 4;
    repeated Image images               = 5;
    repeated string tags                = 6;
    google.protobuf.Timestamp timestamp = 7;

    message Image {
        string filename = 1;
        string original = 2;
        string large    = 3;
        string medium   = 4;
        string small    = 5;
        string tiny     = 6;
    }
}

message SignedPost {
    Post post           = 1;
    string hash         = 2;
    bytes signature     = 3;
}

API

We propose that OpenBazaar server-node implementations support the following endpoints:

  1. GET /ob/posts
  2. GET /ob/post
  3. POST /ob/post
  4. PUT /ob/post
  5. DELETE /ob/post

GET ob/posts

Returns an array of posts from the user or a peer (i.e. /ob/posts/:peerId):

[
    {
        "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"
    }
]

GET ob/post

Returns an individual post from the user or a peer (i.e. /ob/post/:peerId/:slug_or_hash):

{
    "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"
    },
    "hash": "zb2rhdrJUgp17bvjnEW98s9C2eToZHep1eh5i7SBp9jhBpREA",
    "signature": "evhmoAw3S/Qx3lmTStd0esnhPjwgWCfRncpGltyLjW3wPG7Gh8kd4uRSsS+LwoPMpVVvibLuIDi0WwyfsrkODA=="
}

POST /ob/post

Creates a new post:

{
	"title": "multiimagetest-4",
	"longForm": "This is a test post dawg.",
	"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"
	]
}

PUT /ob/post

Edits an existing post:

{
	"slug": "multiimagetest4",
    "title": "multiimagetest-4",
	"longForm": "This is a test post yo.",
	"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"
	]
}

DELETE /ob/post

Deletes an existing post: /ob/posts/:slug_or_hash

Rationale

Advantages

  1. Allows for users to engage with visitors and promote sales
  2. Creates basic tools for an influencer and affiliate program
  3. It is a platform for censorship-resistant expression

Disadvantages

  • index.json file can get bloated if there are a lot of posts
    • This could potentially be mitigated by only storing hashes of the post in an array

Backwards Compatibility

This OBIP extends the protocol and creates a collection of new APIs, as well as a new directory to store posts. This means that non-upgraded nodes will not be able to fulfil API calls for posts if requested. The server will return a standard error for unrecognised API calls.

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

https://github.com/drwasho/openbazaar-go/tree/posts

@drwasho drwasho self-assigned this Oct 4, 2017
@drwasho
Copy link
Member Author

drwasho commented Oct 4, 2017

@drwasho

Thinking of refactoring this a bit @morebrownies by replacing reference: {peerId, listings [] } with just a general purposes tags []. That way users can use hashtags, or some symbol to denote a user, or put the slug/hash for a listings in there.

@drwasho
Copy link
Member Author

drwasho commented Oct 4, 2017

@drwasho

Also I need to fix up the protobuf anyway.

@drwasho
Copy link
Member Author

drwasho commented Oct 4, 2017

@morebrownies

Thinking of refactoring this a bit @morebrownies by replacing reference: {peerId, listings [] } with just a general purposes tags []. That way users can use hashtags, or some symbol to denote a user, or put the slug/hash for a listings in there.

hmm do we even need the general purpose tags array? From a UX perspective, it would be easier to enter #hashTags or @Handles directly into the title or longForm field(s). I'm thinking it would function a lot like Twitter.

3rd parties could also scrape the content within the title or longForm and index based on values found.

Maybe I'm over simplifying?

@drwasho
Copy link
Member Author

drwasho commented Oct 4, 2017

@morebrownies

I read through the OBIP for the second time now and I love this OBIP so much. I see it leading to 2 great outcomes for OpenBazaar:

  1. It will become easier to share / discover content within the ecosystem of OpenBazaar applications. Having the ability to communicate in app will increase the utility value of OpenBazaar while also increasing overall time spent in app. Shoppers / casual users may use OpenBazaar purely for communication needs and Vendors will have another avenue to engage with their followers. Having more user generated content within the platform is key to the growth of OpenBazaar.
  2. OpenBazaar the protocol will also become more attractive to developers. They'll have the ability to build p2p social applications with payments + commerce layered in. This new ability for devs may lead to OpenBazaar powered photo apps spinning up on iOS or Android.

Looks good overall. I'm sure others can validate the schema a bit closer, but seemed on point to me.

Washington reacted with a heart emoji

@drwasho
Copy link
Member Author

drwasho commented Oct 4, 2017

@drwasho

Thanks @morebrownies for the comments!

To your earlier points:

hmm do we even need the general purpose tags array? From a UX perspective, it would be easier to enter #hashTags or @Handles directly into the title or longForm field(s). I'm thinking it would function a lot like Twitter.

I kinda feel that tags sort just happened to Twitter and Instagram, and they integrated it as seamlessly as they could (battling with the idea of whether or not hashtags should count to the tweet length). If they were to design it from scratch, perhaps they would have had a dedicated space for tags?

But more concretely my reason for adding a dedicated tags section is two-fold:

  1. I'm sparing a thought for client developers so they don't have to parse titles search for URLs, peerIds, handles, or listings hashes/slugs
  2. Makes it easier for curators and influencers to clearly anchor their content to a store or collection of listings
  3. tags allows users to embed other forms of metadata (i.e. location) without eating into space for content.

@drwasho
Copy link
Member Author

drwasho commented Oct 4, 2017

@drwasho

Btw this is what the schema for a post looks like with tags:

{
    "post": {
        "slug": "test3",
        "vendorID": {
            "peerID": "QmVdst57mJuW8Tr9owADqWmirY5Gao9zZMnbbL4WavKJvB",
            "handle": "",
            "pubkeys": {
                "identity": "CAESIEokc1r9Wfe4IyqA9P/56dO+5W1Hv9eOi2PXdUBDUf5X",
                "bitcoin": "AjjghznFUNeAkgmEdKYOESzj+PXFvVHUv+jbNWWQKkwG"
            },
            "bitcoinSig": "MEQCIAaKg1Cr676NVo7dz1KibSvvhjyrAXQceYakKwYR13+oAiBmAWqIyTWMuMPeVItwPzS1N2SDYeR5H4cD+uxGv1AghQ=="
        },
        "title": "test3",
        "longForm": "This is a test post dawg.",
        "images": [
            {
                "filename": "cat",
                "original": "zb2rhe2o6WbHqcER5VUKsMUbQrmpCC6ihg8qZ4JS9wVgKz9wm",
                "large": "zb2rhmBUB9i7UkfmeD3obJYK3FFS5K8N8QHaUanG8UWLVBHiY",
                "medium": "zb2rhaFhqziCWk1zo5tMRxQEUchfvJFaGG4DY1anEoR4GnYrN",
                "small": "zb2rhbDCeEiTTunugWPaRRKFCfNKUaB7aCR53nrPnMa9usZXY",
                "tiny": "zb2rhgqJDbshwAgPjs7X2h4mDm3V3BpLbp4tFGqkg1LNkg9yV"
            }
        ],
        "tags": [
            "Yo"
        ],
        "timestamp": "2017-10-03T03:17:27.125836681Z"
    },
    "hash": "zb2rhiGehVLbtM6gpDbZ8f6R3r8xsw6hdidpiwZEuYskmnig5",
    "signature": "kX6Cc/8RzUWL7qSpwm8I1ytDGwQQjLshzY571Ejjo3lRZvfY4rOW5ZESLs33Gc330lFGprgRrEBA/ewoPdvFBQ=="
}

@drwasho
Copy link
Member Author

drwasho commented Oct 4, 2017

@morebrownies

I kinda feel that tags sort just happened to Twitter and Instagram, and they integrated it as seamlessly as they could (battling with the idea of whether or not hashtags should count to the tweet length). If they were to design it from scratch, perhaps they would have had a dedicated space for tags?

No mainstream social tools I can think of utilizes an independent tag input. It seems like tagging is almost always accomplished within the body of text.

Using github as an example, you can type # and a overlay displays allowing you to quickly tag another thread.

image

Slack utilizes the same UX for tagging channels and users within text as well.

image

Same goes for Instagram and Twitter (which you mentioned above)

In my opinion, this allows for a much more fluid UX and allows users to write more natural without being required to bounce between multiple inputs. It has also become a well known pattern that people expect within applications.

@drwasho
Copy link
Member Author

drwasho commented Oct 4, 2017

@morebrownies

But more concretely my reason for adding a dedicated tags section is two-fold:

  1. I'm sparing a thought for client developers so they don't have to parse titles search for URLs, peerIds, handles, or listings hashes/slugs

It looks like Twitter does the parsing on their side to make it easier on developers. Something we could consider on the server side too: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-show-id

  1. Makes it easier for curators and influencers to clearly anchor their content to a store or collection of listings

Not entirely sure how it makes it easier? I would think the opposite approach would easier on users.

  1. tags allows users to embed other forms of metadata (i.e. location) without eating into space for content.

True, but you're suggesting a longer text input that would support 50,000 char. Is this really a concern? If users are way over the maximum limit of the short text, they could switch to longer text mode. Maybe UIs could adapt automatically to longer text mode without user action required. Have some ideas for this.

@drwasho
Copy link
Member Author

drwasho commented Oct 4, 2017

@morebrownies

I just took a look at Medium and they do appear to support a independent tag input. This somewhat contradicts my comments above.

image

I think i'm in agreement now that the API should include some type of tags param. If anything, similar to what Twitter does, the server can auto-populate the value.

If certain clients want to expose a tag input, the server doesn't need to auto-populate in those scenarios. Maybe keeping it flexible is best.

Would love to hear opinions from others as well.

@drwasho
Copy link
Member Author

drwasho commented Oct 5, 2017

Updates to the specification and reference implementation have been made: https://github.com/OpenBazaar/obips/pull/16/files

@drwasho
Copy link
Member Author

drwasho commented Oct 5, 2017

Summary of the updates:

  1. Added tags (replacing 'reference')
  2. Instead of showing 1 thumbnail image for GETPosts, I show all of them in an array. Clients can control how many they choose to show.
  3. Updated the protobuf and reference implementation code
  4. Expanded the backwards compatibility section a little to make it clear that the impact of adopting posts will be minimally disruptive

@rmisio
Copy link

rmisio commented Oct 6, 2017

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.

This might just be semantics, but it would be better for the Post to have an ID (a unique non-maleable identifier). Otherwise we might find ourselves in the pickle we are in now with listings where we are using a slug as an ID, and the slug is public facing and if we ever want to give the user the ability to change the slug, it will create a lot of problems since multiple clients (desktop and search) are using it as an ID and not expecting that it could change.

I know there were some IPFS related complications to having both a slug and id. @tyler was brainstorming some potential solutions.

@rmisio
Copy link

rmisio commented Oct 6, 2017

Deletes an existing post: /ob/posts/:slug_or_hash

I don't think we should be able to delete by hash. A hash is just a version of a post. Does that mean you just want to delete the version or deleting any version of a post would delete the entire post (all versions). It's kind of confusing and ambiguius. I would just delete by id (well, slug if we are forced to use that as the id).

@rmisio
Copy link

rmisio commented Oct 6, 2017

google.protobuf.Timestamp timestamp = 7;

I see other parts of the app (e.g. notifications) also use the name "timestamp". I would think "createdAt" would be better. You may at some point want to add in a "updatedAt" making "timestamp" ambiguous.

@rmisio
Copy link

rmisio commented Oct 6, 2017

Returns an array of posts from the user or a peer (i.e. /ob/posts/:peerId):

I think to keep this part lean we would only need to include the first image here. I also think we could probably get away with just returning the "small" and "tiny" images here since I imagine this endpoint will be used for a twitter style feed where you would just show a thumbnail.

If we want to get real fancy at some point the api could expose options where the caller could decide what is sent back... but without that, I would err on the side of keeping it reasonably lean.

@rmisio
Copy link

rmisio commented Oct 6, 2017

index.json file can get bloated if there are a lot of posts
This could potentially be mitigated by only storing hashes of the post in an array

I'm assuming the index.json file is what GET posts is being proposed to return?

I would think we would want to paginate the posts. Perhaps, instead of saving the posts in a single file, they can be saved into multiple files with a file containing a link to the next file (unless it's the last page).

Otherwise, we are just setting a scaling limit on this thing where as your popularity grows, the latency involved with downloading your posts also grows. After a number of years, very active posters could have thousands upon thousands of listings.

The reason we had to punt on this type of paginating on stores is because we wouldn't be able to sort or search the content (at least without centralized solutions). I'm not sure that we will need such functionality here. If we don't, we should definitly paginate.

The amount of posts per page can even be quite large... it's not a huge deal to download a page with 500 posts. We just want to avoid having to download a page with 10,000 posts.

This could potentially be mitigated by only storing hashes of the post in an array

I don't think I would recommend this at all. You're kind of robbing Peter to pay Paul here. You would make your index fetch much leaner, but then you'd have to make a seperate fetch for each post. In traditional architectures, that would be a cardinal sin.

To summarize, here are the options:

1.) fetch a single index.json

pros: the posts would be sortable and searchable in a decentralized way. (do we even need that?)
cons: As the number of posts grow, the speed of the call decreases. Vendor is thus penalized for being active.

2.) break the index.json into multiple files with pointers to each other.

pros: no scaling issue as described above.
cons: can't sort or filter posts in a decentralized way. (there are probably opt-in centralized solutions we could come up to address this with the help of search providers... if we even need this)

3.) store only hashes of posts in the index.json

pros: the index fetch is dramatically leaner
cons: the index would load faster, but similar to the followers lists, you'd just have a bunch of empty boxes with spinners until the individual posts are fetched. This would also be a huge amount of network traffic. (I think the followers lists and the latency involved with them are one of the more problematic issues for clients - I wouldn't want to repeat that here)

I would personally go for option 2.

@drwasho
Copy link
Member Author

drwasho commented Oct 7, 2017

This might just be semantics, but it would be better for the Post to have an ID (a unique non-maleable identifier). Otherwise we might find ourselves in the pickle we are in now with listings where we are using a slug as an ID, and the slug is public facing and if we ever want to give the user the ability to change the slug, it will create a lot of problems since multiple clients (desktop and search) are using it as an ID and not expecting that it could change.

I'm actually not familiar with the rationale for wanting to change the slug of an existing listing.

In my mind the slug is the unique identifier, which maps to an mutable IPFS object (i.e. the post).

@drwasho
Copy link
Member Author

drwasho commented Oct 7, 2017

I don't think we should be able to delete by hash. A hash is just a version of a post. Does that mean you just want to delete the version or deleting any version of a post would delete the entire post (all versions). It's kind of confusing and ambiguius. I would just delete by id (well, slug if we are forced to use that as the id).

The slug can only map to one IPFS object, and previous versions of that object aren't retained by the node AFAIK. It follows that the only you you could have obtained the hash of the post is if it currently exists and is linked to the IPNS slug.

@drwasho
Copy link
Member Author

drwasho commented Oct 7, 2017

I see other parts of the app (e.g. notifications) also use the name "timestamp". I would think "createdAt" would be better. You may at some point want to add in a "updatedAt" making "timestamp" ambiguous.

Agreed, great suggestion.

@rmisio
Copy link

rmisio commented Oct 7, 2017

The slug can only map to one IPFS object, and previous versions of that object aren't retained by the node AFAIK. It follows that the only you you could have obtained the hash of the post is if it currently exists and is linked to the IPNS slug.

Yes, they are retained. An IPFS is a pointer to a version of an object. As soon as that object changes, it gets a new hash, but the old version remains on the network. I'm not sure how long it remains.

@drwasho
Copy link
Member Author

drwasho commented Oct 8, 2017

I think to keep this part lean we would only need to include the first image here. I also think we could probably get away with just returning the "small" and "tiny" images here since I imagine this endpoint will be used for a twitter style feed where you would just show a thumbnail.

Originally it was set like this, but I opted against it because a use-case of Posts is to only add data to title, like a tweet, and attach several images. When using the GETPosts endpoint, you would see the title and an array of however many images that can be rendered something like this in a client (where multiple images are previewed):

screen shot 2017-10-09 at 8 25 11 am

Only having 1 image as a preview makes sense for listings as far as expectations/standards are concerned, but less so for a Post and its use-cases. Client developers always have full control of how many images they choose to render, so they can only show 1 or 5 or 8... up to them.

When you make a GETPost call, you get the image hashes for higher quality images and the longForm key, which has your blog-style post.

@drwasho
Copy link
Member Author

drwasho commented Oct 8, 2017

Yes, they are retained. An IPFS is a pointer to a version of an object. As soon as that object changes, it gets a new hash, but the old version remains on the network. I'm not sure how long it remains.

Yes I stand corrected there, the content can be retained by other nodes on the network too that are out of date. But the endpoint is to Delete the post, which can only be done on your own node. It seems very unlikely to me that a user would obtain a stale hash and use that to try and delete the post. In any case, deleting by hash or slug is what we're doing for listings, and like listings client developers should be handling specific content by its slug.

@drwasho
Copy link
Member Author

drwasho commented Oct 8, 2017

I'm assuming the index.json file is what GET posts is being proposed to return?

Yes, just like listings.

I would think we would want to paginate the posts. Perhaps, instead of saving the posts in a single file, they can be saved into multiple files with a file containing a link to the next file (unless it's the last page). Otherwise, we are just setting a scaling limit on this thing where as your popularity grows, the latency involved with downloading your posts also grows. After a number of years, very active posters could have thousands upon thousands of listings.

I agree here, but I think we're touching on a much larger issue we haven't solved for listings. Since the approach I've followed for posts is exactly the same for listings, whatever solution we come up with there will be used to rebase against.

@rmisio
Copy link

rmisio commented Oct 12, 2017

Client developers always have full control of how many images they choose to render, so they can only show 1 or 5 or 8... up to them.

That's not the point. The point is you don't want that index file growing unnecessarily large. If it's necessary to have more than one image, I would still cap it somewhere (maybe 4 or 5), otherwise people who regularly post with a lot of images (10, 20, 30) will have their index file grow really big, really fast.

@drwasho
Copy link
Member Author

drwasho commented Oct 13, 2017

The point is you don't want that index file growing unnecessarily large

Like adding every country known to man in shipsTo?

I would still cap it somewhere (maybe 4 or 5)

Joking aside, a cap makes sense.

@rmisio
Copy link

rmisio commented Oct 13, 2017

Like adding every country known to man in shipsTo?

Yes, exactly like that :)

FWIW, desktop client support for the ALL shipping region has been in for a few weeks. (you best recognize!)

@drwasho
Copy link
Member Author

drwasho commented Oct 15, 2017

PR based on feedback: #23

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants