# Sidetrail Lexicons

Three record types stored in users' ATProto repositories.

## `app.sidetrail.trail`

A trail with 2-24 embedded stops.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.
