diff --git a/psf-memo-client/specs/follow-user.feature b/psf-memo-client/specs/follow-user.feature new file mode 100644 index 0000000..8b9d7db --- /dev/null +++ b/psf-memo-client/specs/follow-user.feature @@ -0,0 +1,55 @@ +# Scenarios: Follow User - 1, Follow User - 2, Follow User - 3, Follow User - 4, Follow User - 5 +# +# The follow/unfollow OP_RETURN payload is the followee's 20-byte hash160. +# Convert the followee's cash address with bch-js Address.toHash160() (available +# through the minimal-slp-wallet embedded bch-js) before broadcasting 0x6d06 / +# 0x6d07. Do not add a separate cashaddr dependency. +Feature: Follow User + + Background: + Given a wallet authenticated for the address bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d + Given the wallet has spendable output to pay the transaction fee + + Scenario Outline: Follow User - 1 viewing another user's profile shows a Follow button + Given I open the profile page for the address + Then the profile page shows a Follow button + + Examples: + | addr | + | bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy | + | bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r | + + Scenario Outline: Follow User - 2 clicking Follow broadcasts the follow action and shows Unfollow + Given I open the profile page for the address + When I click the Follow button + Then the app broadcasts an OP_RETURN transaction with the Memo follow prefix for the address + Then the profile page shows an Unfollow button + + Examples: + | addr | + | bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy | + + Scenario Outline: Follow User - 3 clicking Unfollow broadcasts the unfollow action and shows Follow + Given the psf-memo-db API reports that I follow the address + Given I open the profile page for the address + When I click the Unfollow button + Then the app broadcasts an OP_RETURN transaction with the Memo unfollow prefix for the address + Then the profile page shows a Follow button + + Examples: + | addr | + | bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy | + + Scenario: Follow User - 4 viewing my own profile does not show a Follow button + Given I open the profile page for my own address + Then the profile page does not show a Follow button + + Scenario Outline: Follow User - 5 the profile page shows Unfollow when I already follow the user + Given the psf-memo-db API reports that I follow the address + Given I open the profile page for the address + Then the profile page shows an Unfollow button + + Examples: + | addr | + | bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy | + | bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r | diff --git a/psf-memo-db/specs/follow-read.feature b/psf-memo-db/specs/follow-read.feature new file mode 100644 index 0000000..d50acc2 --- /dev/null +++ b/psf-memo-db/specs/follow-read.feature @@ -0,0 +1,39 @@ +# Scenarios: Follow Read - 1, Follow Read - 2, Follow Read - 3 +# +# The follows store keys followees by 20-byte hash160. Use bch-js +# Address.toHash160() / Address.hash160ToCash() to convert between cash +# addresses and hash160 for the follow state and following/followers lists. +# Prefer bch-js over adding a separate cashaddr dependency. +Feature: Follow Read + + Background: + Given a psf-memo-db instance with a follows store + Given the fixture "follows" is loaded into the follows store + + Scenario Outline: Follow Read - 1 GET /follow/state reports whether a follower follows a followee + When the client requests the follow state for follower and followee + Then the follow state reports following + + Examples: + | follower | followee | following | + | bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d | bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy | true | + | bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d | bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r | false | + | bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a | bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy | true | + + Scenario Outline: Follow Read - 2 GET /follow/following lists the addresses a follower follows + When the client requests the following list for + Then the following list contains the addresses + + Examples: + | follower | expected | + | bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d | bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy | + | bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a | bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy | + + Scenario Outline: Follow Read - 3 GET /follow/followers lists the addresses that follow a followee + When the client requests the followers list for + Then the followers list contains the addresses + + Examples: + | followee | expected | + | bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy | bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d,bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a | + | bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r | | diff --git a/specifier-prompt.md b/specifier-prompt.md index 101e3b0..f9368d5 100644 --- a/specifier-prompt.md +++ b/specifier-prompt.md @@ -318,6 +318,12 @@ that a single user-facing feature may require specs in more than one component. example value that was broadcast, so Gherkin mutation of the URL survives trivially. Same pattern as set-bio Scenario 1. If tightening, tie the assertion to independent fixture data rather than the broadcast example. +15. **Use bch-js for cashaddr conversion, not a new dependency.** The follow + (`0x6d06`) / unfollow (`0x6d07`) payload is the followee's 20-byte hash160 + (P2PKH). Convert with `bchjs.Address.toHash160()` (client, via the + minimal-slp-wallet embedded bch-js) and `bchjs.Address.hash160ToCash()` + (DB read side). Prefer bch-js over installing a separate cashaddr library. + See `specs/feature-backlog.md` "Suggested next spec" for the follow feature. --- diff --git a/specs/feature-backlog.md b/specs/feature-backlog.md index ddb6804..aa71ace 100644 --- a/specs/feature-backlog.md +++ b/specs/feature-backlog.md @@ -220,6 +220,21 @@ Polls require a new data model and rendering. The indexer has no handler yet. - The indexer already stores follows in `followsDb`; the missing pieces are the client write path and the DB read side. +### cashaddr conversion (use bch-js, not a new dependency) + +The follow/unfollow OP_RETURN payload is the followee's **20-byte hash160** +(P2PKH). The `followsDb` store keys followees by that hash160. Convert between +cash addresses and hash160 with **bch-js** `Address` tools, which are already +available and preferred over adding a separate cashaddr library: + +- Client: `bchjs.Address.toHash160(followeeCashAddress)` returns the hash160 + hex for the `0x6d06` / `0x6d07` payload. bch-js is embedded in + `minimal-slp-wallet`, so no new client dependency is needed. +- DB read side: `bchjs.Address.toHash160(followeeCashAddress)` for the follow + state lookup, and `bchjs.Address.hash160ToCash(followeePkHash)` to return + cash addresses in the following/followers lists. Add `@psf/bch-js` to + `psf-memo-db` rather than a separate cashaddr package. + This is the next smallest end-to-end win after the set-avatar-url write path closed. ---