at.rolld.play

rolld.at

{
  "id": "at.rolld.play",
  "defs": {
    "main": {
      "key": "tid",
      "type": "record",
      "record": {
        "type": "object",
        "required": [
          "game",
          "target",
          "playedAt",
          "createdAt"
        ],
        "properties": {
          "game": {
            "ref": "at.rolld.defs#gameRef",
            "type": "ref",
            "description": "The game played, referenced by BGG id."
          },
          "images": {
            "type": "array",
            "items": {
              "ref": "at.rolld.defs#image",
              "type": "ref"
            },
            "maxLength": 4,
            "description": "Optional photos of the play (board, table, scores). Up to 4, matching Bluesky's per-post image limit so the same blobs can be embedded in a companion app.bsky.feed.post. Each blob lives in the user's PDS and is referenced here; the photo is part of the play (not a standalone record). Powers the per-game photo gallery via the existing plays-of-this-game Constellation query (filter plays that have images). See DECISIONS D-33."
          },
          "target": {
            "type": "string",
            "format": "uri",
            "description": "Canonical per-game web URL (https://rolld.at/g/<bggId>) that Constellation indexes as a backlink target. FROZEN format, emitted from one shared helper shared by write and read paths. This is the linchpin of the serverless read model — backlinks to this URL ARE the play aggregation. No catalog segment: game identity is permanently BGG-keyed."
          },
          "content": {
            "refs": [
              "at.markpub.markdown"
            ],
            "type": "union",
            "description": "Optional rich note about how the play went. Open union (bring-your-own-content, like standard.site's content field) so the format can grow without a breaking change. v1 accepts markpub Markdown. Render via the $type; consumers that don't understand it fall back to textContent."
          },
          "players": {
            "type": "array",
            "items": {
              "ref": "at.rolld.defs#player",
              "type": "ref"
            },
            "description": "Who played. Each entry may carry an atproto DID (for real handles) and/or a plain display name."
          },
          "location": {
            "type": "string",
            "maxLength": 500,
            "description": "Free text: whose house, which convention, which cafe."
          },
          "playedAt": {
            "type": "string",
            "format": "datetime",
            "description": "When the play session occurred (may differ from createdAt if logged later)."
          },
          "createdAt": {
            "type": "string",
            "format": "datetime",
            "description": "When this record was created."
          },
          "expansions": {
            "type": "array",
            "items": {
              "ref": "at.rolld.defs#gameRef",
              "type": "ref"
            },
            "description": "Expansions in play, by BGG id."
          },
          "winnerDids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "did"
            },
            "description": "DIDs of winning players, if any were recorded as identities."
          },
          "bskyPostRef": {
            "ref": "com.atproto.repo.strongRef",
            "type": "ref",
            "description": "Strong ref (uri + cid) to a companion app.bsky.feed.post, if the user chose to share this play on Bluesky. The post links back to the per-entry permalink (/@<handle>/play/<rkey>). Storing the ref also enables showing Bluesky replies as discussion on the entry later (the Leaflet POSSE pattern)."
          },
          "textContent": {
            "type": "string",
            "maxLength": 100000,
            "description": "Plain-text rendering of `content`, always populated when `content` is present. The universal fallback for any consumer that can't render the content union's $type, and the field to index for search/previews. Same role as standard.site's textContent. No grapheme limit."
          },
          "winnerNames": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 320
            },
            "description": "Names of winners not represented by a DID."
          },
          "durationMinutes": {
            "type": "integer",
            "minimum": 0,
            "description": "How long the session actually took."
          }
        }
      },
      "description": "A single logged session of playing a board game. The high-volume event record. Reads ('times played', 'who played this game') are served by querying Constellation for backlinks to the 'target' URL — derived live, never stored."
    }
  },
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1
}

Validate Record

Validate a record against at.rolld.play

Validation Options
Automatically resolve and include external schemas for full validation
Treat any remaining unresolved references as valid

Metadata

DID
did:plc:vjpkp7kuxs6iicilpqlibvl4
CID
bafyreie5flwrievpymjrfxnih3d3knznydilixr4qxrztcijzt3vqssap4
Indexed At
2026-07-26 20:15 UTC
AT-URI
at://did:plc:vjpkp7kuxs6iicilpqlibvl4/com.atproto.lexicon.schema/at.rolld.play

Referenced Schemas (4)

Lexicon Garden

@