an app to share curated trails sidetrail.app
atproto nextjs react rsc
50
fork

Configure Feed

Select the types of activity you want to include in your feed.

Sidetrail Lexicons#

Three record types stored in users' ATProto repositories.

app.sidetrail.trail#

A trail with 2-12 embedded stops.

{
  "title": "Getting Started with Bluesky",
  "description": "A quick tour of the basics",
  "stops": [
    {
      "tid": "3abc...",
      "title": "Create an account",
      "content": "Head to bsky.app and sign up...",
      "buttonText": "Done",
      "external": {
        "uri": "https://bsky.app",
        "title": "Bluesky",
        "thumb": { "$type": "blob", ... }
      }
    }
  ],
  "accentColor": "#e8a87c",
  "backgroundColor": "#fdf8f3",
  "createdAt": "2024-01-01T00:00:00Z"
}

Stops have stable TIDs so they survive reordering. The external field can hold http(s) URLs or at:// URIs (for embedding Bluesky posts).

app.sidetrail.walk#

Tracks a user's progress through a trail. Deleted on completion or abandon.

{
  "trail": {
    "uri": "at://did:plc:xyz/app.sidetrail.trail/abc",
    "cid": "bafyrei..."
  },
  "visitedStops": ["3abc...", "3def..."],
  "createdAt": "2024-01-01T00:00:00Z",
  "updatedAt": "2024-01-01T00:01:00Z"
}

The app only respects the most recent walk per trail (by TID). visitedStops grows as the user progresses - current position is the last item.

app.sidetrail.completion#

Permanent record that a user finished a trail.

{
  "trail": {
    "uri": "at://did:plc:xyz/app.sidetrail.trail/abc",
    "cid": "bafyrei..."
  },
  "createdAt": "2024-01-01T00:05:00Z"
}

Uses a strong ref (uri + cid) so we know exactly which version was completed. Users can complete the same trail multiple times.

Lifecycle#

  1. Start walking: Create a walk record with visitedStops = [firstStopTid]
  2. Advance: Append the next stop TID to visitedStops
  3. Complete: Delete the walk, create a completion
  4. Abandon: Just delete the walk

Editing#

Trails can be edited in place (same URI, new CID). Stop TIDs survive reordering. If a stop is deleted mid-walk, the client handles it gracefully.