# world.treeline.route.review

> An athlete's rating and review of a route. Field-compatible with app.attrails.review (subject, rating, text, completedAt, images, langs, labels, createdAt), plus an optional link to the athlete's own activity on the route and the gear they used. AppViews treat the most recent review per (author, subject) as canonical: to change a review, write a new one; older ones stay in the repo as history.

- Kind: record
- Record key: tid
- Authority: route.treeline.world
- Lexicon: 1
- Published by [treeline.world](https://lexicon.garden/identity/did:plc:sjejpugpajgvxweilujzjcmq), the NSID's authority

## Links

- [Documentation](https://lexicon.garden/lexicon/did:plc:sjejpugpajgvxweilujzjcmq/world.treeline.route.review)
- [Schema JSON](https://lexicon.garden/lexicon/did:plc:sjejpugpajgvxweilujzjcmq/world.treeline.route.review/schema.json)
- [Analytics](https://lexicon.garden/lexicon/did:plc:sjejpugpajgvxweilujzjcmq/world.treeline.route.review/analytics)

## Record (`world.treeline.route.review`)

Type: record · key tid

### Properties

- `activity` (ref): Optional proof of completion: the reviewer's own world.treeline.activity.record on this route. AppViews show a review as verified only when the activity is in the reviewer's repo and matches the subject route.
  - Reference: `com.atproto.repo.strongRef`
- `completedAt` (string · datetime): Optional. When the reviewer last did the route.
- `createdAt` (string · datetime, required): When the review was written. Decides which review per (author, subject) is the latest.
- `gearRef` (ref): Optional reference to the world.treeline.gear.item the reviewer used on the route.
  - Reference: `com.atproto.repo.strongRef`
- `images` (array): Optional photos, in display order. At most 4, so a review can be cross-posted as one app.bsky.embed.images embed. Clients must strip all EXIF metadata from the image blob before upload.
  - Constraints: maxLength: 4
  - `items` (ref)
    - Reference: `#image`
- `labels` (union): Optional self-label values the author applies to this record, effectively content warnings (e.g. graphic-media for an injury photo).
  - One of: `com.atproto.label.defs#selfLabels`
- `langs` (array): Optional. The human languages of this record's text (the review text and image alt text), as BCP-47 tags, so consumers can filter or translate.
  - Constraints: maxLength: 3
  - `items` (string · language)
- `rating` (integer, required): Star rating from 1 (worst) to 5 (best).
  - Constraints: minimum: 1, maximum: 5
- `subject` (ref, required): The route being reviewed: usually a world.treeline.route.record, but any route record from another app (e.g. app.attrails.route) may be reviewed.
  - Reference: `com.atproto.repo.strongRef`
- `text` (string): Optional review text, as CommonMark. Clients must not render raw HTML.
  - Constraints: maxLength: 30000, maxGraphemes: 3000

## #aspectRatio (`world.treeline.route.review#aspectRatio`)

Type: object

Width:height ratio of an image, so clients can lay out the gallery before the image loads. Matches app.bsky.embed.defs#aspectRatio.

### Properties

- `height` (integer, required)
  - Constraints: minimum: 1
- `width` (integer, required)
  - Constraints: minimum: 1

## #image (`world.treeline.route.review#image`)

Type: object

A photo attached to a review. image, alt and aspectRatio match app.bsky.embed.images#image and app.attrails.defs#image field for field.

### Properties

- `alt` (string, required): Alt text for screen readers and Bluesky embeds. May be empty, as on app.bsky.embed.images#image.
  - Constraints: maxLength: 10000, maxGraphemes: 1000
- `aspectRatio` (ref)
  - Reference: `#aspectRatio`
- `image` (blob, required): The photo, re-encoded by the client with all EXIF metadata removed. Same size limit as app.bsky.embed.images#image.
  - Constraints: maxSize: 1000000, accept: image/jpeg, image/png, image/webp

## Schema

```json
{
  "$type": "com.atproto.lexicon.schema",
  "defs": {
    "aspectRatio": {
      "description": "Width:height ratio of an image, so clients can lay out the gallery before the image loads. Matches app.bsky.embed.defs#aspectRatio.",
      "properties": {
        "height": {
          "minimum": 1,
          "type": "integer"
        },
        "width": {
          "minimum": 1,
          "type": "integer"
        }
      },
      "required": [
        "width",
        "height"
      ],
      "type": "object"
    },
    "image": {
      "description": "A photo attached to a review. image, alt and aspectRatio match app.bsky.embed.images#image and app.attrails.defs#image field for field.",
      "properties": {
        "alt": {
          "description": "Alt text for screen readers and Bluesky embeds. May be empty, as on app.bsky.embed.images#image.",
          "maxGraphemes": 1000,
          "maxLength": 10000,
          "type": "string"
        },
        "aspectRatio": {
          "ref": "#aspectRatio",
          "type": "ref"
        },
        "image": {
          "accept": [
            "image/jpeg",
            "image/png",
            "image/webp"
          ],
          "description": "The photo, re-encoded by the client with all EXIF metadata removed. Same size limit as app.bsky.embed.images#image.",
          "maxSize": 1000000,
          "type": "blob"
        }
      },
      "required": [
        "image",
        "alt"
      ],
      "type": "object"
    },
    "main": {
      "description": "An athlete's rating and review of a route. Field-compatible with app.attrails.review (subject, rating, text, completedAt, images, langs, labels, createdAt), plus an optional link to the athlete's own activity on the route and the gear they used. AppViews treat the most recent review per (author, subject) as canonical: to change a review, write a new one; older ones stay in the repo as history.",
      "key": "tid",
      "record": {
        "properties": {
          "activity": {
            "description": "Optional proof of completion: the reviewer's own world.treeline.activity.record on this route. AppViews show a review as verified only when the activity is in the reviewer's repo and matches the subject route.",
            "ref": "com.atproto.repo.strongRef",
            "type": "ref"
          },
          "completedAt": {
            "description": "Optional. When the reviewer last did the route.",
            "format": "datetime",
            "type": "string"
          },
          "createdAt": {
            "description": "When the review was written. Decides which review per (author, subject) is the latest.",
            "format": "datetime",
            "type": "string"
          },
          "gearRef": {
            "description": "Optional reference to the world.treeline.gear.item the reviewer used on the route.",
            "ref": "com.atproto.repo.strongRef",
            "type": "ref"
          },
          "images": {
            "description": "Optional photos, in display order. At most 4, so a review can be cross-posted as one app.bsky.embed.images embed. Clients must strip all EXIF metadata from the image blob before upload.",
            "items": {
              "ref": "#image",
              "type": "ref"
            },
            "maxLength": 4,
            "type": "array"
          },
          "labels": {
            "description": "Optional self-label values the author applies to this record, effectively content warnings (e.g. graphic-media for an injury photo).",
            "refs": [
              "com.atproto.label.defs#selfLabels"
            ],
            "type": "union"
          },
          "langs": {
            "description": "Optional. The human languages of this record's text (the review text and image alt text), as BCP-47 tags, so consumers can filter or translate.",
            "items": {
              "format": "language",
              "type": "string"
            },
            "maxLength": 3,
            "type": "array"
          },
          "rating": {
            "description": "Star rating from 1 (worst) to 5 (best).",
            "maximum": 5,
            "minimum": 1,
            "type": "integer"
          },
          "subject": {
            "description": "The route being reviewed: usually a world.treeline.route.record, but any route record from another app (e.g. app.attrails.route) may be reviewed.",
            "ref": "com.atproto.repo.strongRef",
            "type": "ref"
          },
          "text": {
            "description": "Optional review text, as CommonMark. Clients must not render raw HTML.",
            "maxGraphemes": 3000,
            "maxLength": 30000,
            "type": "string"
          }
        },
        "required": [
          "subject",
          "rating",
          "createdAt"
        ],
        "type": "object"
      },
      "type": "record"
    }
  },
  "id": "world.treeline.route.review",
  "lexicon": 1
}
```
