IndieWebCamp is a 2-day creator camp focused on growing the independent web

Taproot

Contents

Taproot

Taproot is Barnaby Walters’ publishing software. It’s written in PHP 5.4 and drives most of waterpigs.co.uk. It is not currently released to the public, although parts of it are:

Most of the Taproot design artefacts are up on github too in taproot/design.

Design Principles

In addition to the indiewebcamp principles, these are some principles I have discovered through building taproot.

  • Build software which feels safe, all other concerns (privacy, security, technically exciting) are secondary [1] — this is based on personal experience through selfdogfooding taproot
  • Easy things should be easy, remove friction so hard things are only has hard as they need to be [2]
  • Use event listener patterns to build upon the same data in intelligent ways [3]
  • Build reusable, framework-agnostic components and release them to the public, not monolithic products.

IndieWeb Support

Taproot supports the following:

  • Sends pingbacks and webmentions when
    • post a note or an article
      • pings all the links on every post. If there are problems, it may be throttled, possibly to only links marked up with h-cite and h-card
  • Receives pingbacks and displays them as comments
  • All content is marked up using microformats so parse at your leisure.
  • reply notes parse the URL they’re in-reply-to and display a reply-context if microformats are present
  • Notes have webactions with twitter intent fallback
  • All ATOM feeds are marked up using ATOM-activitystreams and syndicated via a PuSH server
  • Notes and articles are POSSEd to twitter automatically and manually to facebook
  • I log in using indieauth; others can too but until I implement access control nothing particularly interesting will happen

Roadmap

(Less of a “road” map, more of a kind of vague treasure map with no compass)

Currently working on:

  • Federated comments
  • Note frontend redesign to better accommodate comments; other interesting metadata
  • Accepting webmentions as well as pingbacks

Next up:

  • spam prevention in aforementioned comments
  • Extracting my more complicated listeners into framework-agnostic components, releasing them for others to benefit from
  • Self-hosted venues
  • Articles redesign, real versioning, generally making them more wiki-like
  • (maybe) access control on notes? Certainly private just for me, maybe more granular too

Just finished:

  • Post-by-email
  • Major migration away from DB storage, toward flat files, with lots of codebase cleanup in the process
  • Import of old posts from Diaspora see them here
  • Frontend js using Backbone and requirejs

Structure

Taproot has a highly modular structure. It is made up of an Application class, which handles event dispatching, simple dependency injection, routing and module loading. There are two types of modules — full modules, which expose URLs, and listeners, which listen to events dispatched within taproot.

Currently there are modules for Index, Notes, Articles, Contacts, Tunes, Tags and Mentions.

There are a large number of listeners which handle everything from authentication to POSSE and content transformation. Typically if I want to add a new piece of functionality I’ll do it in a listener, if I want to add a new content type I’ll create a new module.

Storage

Modules all store their data in flat files (usually YAML) which I index with MySQL using Librarian.

I typically try to make each file as standalone as possible, even if it means content is duplicated — for example, each note and article file has an 'author' key with a representation of me in, and the contents of each comment/reply context are stored as well.

For content which has an intrinsic name (like pieces of music, contacts or blog posts) I tend to use an ASCII-fied slug of the name for the ID, generated using Helpers::toAscii. Otherwise (for notes) I create a <= six-character ID from the newbase60 representation of epoch days + number of seconds into that day.

Schema

The data is all stored in a microformats-2 JSON variant structure which is substantially flatter than mf2 JSON — all properties are properties of the parent object, not a properties key, there is no “children” key and only plural properties map to arrays. I keep most of the semantics the same except on the occasions where I prefer a different term (tag over category) or want to aggregate the properties from what would be multiple different mf properties into one (e.g. combining geo, adr and venue into “location”).

  • Originally I intended on using the activitystreams schema to store and represent all my content, the idea being that it would allow me to make listeners which could work seamlessly on all sorts of content types. In actuality, I have nowhere near as many content types as I anticipated, and want to treat each one very differently. In addition to this, I found some of the semantics within activitystreams irritating (e.g. displayName vs title, both horrible names) and the activity ~= object ambiguity confusing. Coupled with the fact that there is no activitystreams client, I decided to drop activitystreams as the basis for representing my data. --Waterpigs.co.uk 12:33, 14 June 2013 (PDT)

Notes

The Notes module is the mainstay of my Taproot usage. It handles the creation and display of short notes — kinda like tweets, but with a potentially much larger scope through the excessive use of tagging.

As in most of Taproot, the notes module handles basic CRUDL of data, and various listeners do everything else, including converting markdown, interpreting hashtags, autolinking @names, syndication of content.

Posting a note looks like this:

taproot-posting-ui.gif

A still of the posting UI just after the note has saved:

note-saved-ui.png

See Also