Brain Dump - ATProto Goodreads

The following design document is acting as a brain dump, there will probably be holes in whatever I was thinking at the time.

Wording may be a bit weird because I used this in conjunction with AI to paste into a chat and get feedback. No generative AI was used to write this (hence the grammar mistakes). This brain dump is from awhile ago when my knowledge of the protocol was very hazy. Progress was started on this, but this specific iteration was very optimistic and would have never happened.

Notes

When I refers to “AppViews“, I am talking about the frontend and backend of a site which interacts with this lexicon specification. I doubt anybody will fork the site I make for this lexicon, though just in-case it is a well-considered case scenario in this document.

AppViews would be requested to comply with the user’s privacy decisions; however, due to the nature of the protocol, all data is public. I feel like making certain data such as journal entries or bookshelves be stored in a private database would be defeating the point of data portability and ownership that is the driving factor behind the protocol. The default AppView will commit to following the privacy specified in journal records.

Each record will contain the standard .$type and .createdAt properties; however, they will not be explicitly stated in this document due to the implied existence of these properties for all AT protocol records.

The reason for the weird separation between the .shelves and .shelfItem collections is because that is how Bluesky itself organizes lists. Bluesky’s lexicon has both a app.bsky.graph.list collection and a app.bsky.graph.listitem collection. That is why it is structured the way it is, for parallel to the official lexicon of Bluesky (I would assume they know what they are doing and how to do it best since they made the protocol)

Collections may have a version record to ensure backwards compatibility, and migrations to later lexicon versions and changes.

When privacy is set to public, AppViews are encouraged to show the data to all users.

When privacy is set to link-only, AppViews are encouraged to only show the data if the specific URL is accessed and nowhere else.

When privacy is set to private, AppViews are encouraged to only show the data to the author of said data.

Collections

.books

This record collection would be used for storing the book data in a way that contributes to the intent of the protocol - which is data portability. Instead of having a reference such as gr:123456 , and leaving it at that for AppViews to manually fetch the actual individual book data, the lexicon should store enough information for the user to own their data. Each book record would contain the following:

Name

Author(s)

Cover (as a blob)

Source ID (e.g. if the book was collected from Goodreads, the source ID would be gr:123456)

Status (token definition, options: “Read“, “Currently Reading“, “Want to Read”, “Abandoned”)

Physical Copy Owned? (whether or not the user owns a physical copy of the book)

Progress

Progress would be stored as the amount of pages the user has read

If the user enters a percentage, the site will take the page count and get the approximate page count and save that internally

Exclude from Statistics? (if checked, all mood, pace, time to read, and other data will be excluded when the user goes to the statistics page, this does not mean it’d be excluded from any future recommendation algorithm)

Other data, such as page count, genre, description, publisher, etc can be considered irrelevant and would be a waste of storage space on each user’s individual PDS (personal data server).

On the topic of books being in a centralized account and user PDSes referencing the book data stored in an official account of the site rather than in their own PDSes, I feel as though it’d go against the idea of data portability. Along with the fact that most of the AT protocol projects I’ve seen, such as teal.fm , rocksky.app , and bookhive.buzz , store artist/song data and book data in the user’s respective PDS rather than in a centralized account with reference links. In a perfect world, I’d leave it up to the user as a choice; however, that would complex the code having to deal with references for some users and then not having to deal with that same thing for other users.

.reviews

This record collection would be used for storing overall reviews of a book. This allows user to collect their thoughts from journal entries, into one overall review for other users. Each review record would contain the following:

Book Record (at:// reference, record will be located in the .books collection)

Star Rating

Star ratings would be out of 5 stars, including half stars.

The rating counter could be out of 10, for easy calculations and processing, it would also align itself with other AT protocol projects such as skylights.my .

Content (string, shown as a text box on the AppView)

Optional Algorithm Contributions (allows the user to contribute and help a future recommendation algorithm, and discovery for other users):

Questions:

Pace (fast, medium, slow)

Plot or character driven? (plot, a mix, character)

Strong character development? (yes, complicated, no, N/A)

Lovable characters? (yes, complicated)

Diverse cast of characters? (yes, complicated, no, N/A)

Flaws of characters a main focus? (yes, complicated, no, N/A)

Additional Tags (any answers, array will be generated by splitting the response by commas)

Content Warnings (any answers, array will be generated by splitting the response by commas)

The contributions will be averaged out and then used for any future recommendation algorithm, and used for better discovery when a user goes to a book view page they will see the percentage of answers from reviews if there are a lot of reviews for a certain book.

These statistics are taken from the closed-source centralized Goodreads alternative known as The Story Graph.

.dates

This record collection would be used for storing the date(s) a book was read. This allows users to track how many times they’ve read a book, and when they started and stopped. In conjunction with the .journals record collection, this can be used for personalized journal entries for each read-through at each point in progress. Each date record would contain the following:

Book Record (at:// reference, record will be located in the .books collection)

Start Date

End Date

Re-read? (this would be explicitly specified by the user, instead of assuming that the first record is the first read)

.journals

This record collection would be used for storing the personal journal entries for each book the user has read. This allows users to track their thoughts and recaps at different points in a book. In conjunction with the .dates record collection, this can be used for filtering journals by a specific read-through of a book. Each journal record would contain the following:

Book Record (at:// reference, record will be located in the .books collection)

Date Record (at:// reference, record will be located in the .dates collection)

Progress Point (percentage or page number)

Content (string which will be shown as a textbox to the user in the AppView)

Privacy (public, link-only, hidden)

.shelves

This record collection would be used for storing lists (would be referred to as “bookshelves” by the AppView, or just “shelves” for short) of books. This allows users to further categorize their book collections in any way they would like. Each shelf record would contain the following:

Name

Description

Privacy (public, link-only, hidden)

The default AppView will have several default shelves, those being:

Favorites (any book that is rated 4.5 or more stars)

Default shelves will have the special functionality of auto-adding books. To ensure the ability to opt-out, the shelves can still be deleted, or they can be renamed to remove a prefix from the name so the AppView doesn’t enforce the default auto-add behavior. The prefix would probably be a *. Another method of removing built-in behavior, could just be allowing the user to check a box when creating a list which would say “use default behavior“, and then allow them to select a default behavior such as “Add any book that is rated 4.5 or more stars automatically“.

.shelfItem

This record collection would be used for storing what books are associated with each shelf. Each shelf item record would contain the following:

Book Record (at:// reference, record will be located in the .books collection)

List Record (at:// reference, record will be located in the .shelves collection)

.readingPrefs

This record collection would be used for storing reading preferences of users. The collection would only contain one record, “self”. This data can be used for future reference when making a recommendation algorithm. The self record would contain the following information:

Favorite Genres

Preferred Types of Books

Preferred Characteristics

Disliked Genres

Disliked Characteristics

Disliked Moods

Content to Avoid

Disliked Topics

This idea is taken from the closed-source centralized Goodreads alternative known as The Story Graph. This will be recommended to be filled out on first log-in of the AppView, but will be able to be edited at any time.

Answers could be simplified to a tagging/enum system where it only allows pre-approved responses that the user can add as many for each input. This would make the data much more expected and interopable.

.accountPrefs

This record collection would be used for storing information on general AppView settings of users. The collection would only contain one record, “self”. The self record would contain the following information:

Region (optional, used for regional book locking potentially; I don’t know exactly)

Use Centralized Book Data? (determines whether to use at:// references for book data, default: false)

Centralized Data Source Account DID (only used if the “Use Centralized Book Data?” preference is checked)

Profile Privacy (public, link-only, private)

Default Journal Privacy (public, link-only, private)

Default Shelf Privacy (public, link-only, private)

.goals

This record collection would be used for storing personal goals a user plans to achieve in a certain timeframe. Each goal record would contain the following information:

Name

Description (optional)

Start Date

End Date

Statistic to Track (token, options will be any statistic shown on the AppView’s statistics page)

Statistic Goal Value (value the statistic should be at the end of the goal timeframe)