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.
tid
Timestamp-based ID
Properties
bskyPostRef
ref
com.atproto.repo.strongRef
Optional
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).
content
union
Optional
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.
createdAt
string
datetime
Required
When this record was created.
durationMinutes
integer
Optional
How long the session actually took.
minimum: 0expansions
array
of
ref
at.rolld.defs#gameRef
Optional
Expansions in play, by BGG id.
game
ref
at.rolld.defs#gameRef
Required
The game played, referenced by BGG id.
images
array
of
ref
at.rolld.defs#image
Optional
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.
maxLength: 4 itemslocation
string
Optional
Free text: whose house, which convention, which cafe.
maxLength: 500 bytesplayedAt
string
datetime
Required
When the play session occurred (may differ from createdAt if logged later).
players
array
of
ref
at.rolld.defs#player
Optional
Who played. Each entry may carry an atproto DID (for real handles) and/or a plain display name.
target
string
uri
Required
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.
textContent
string
Optional
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.
maxLength: 100000 byteswinnerDids
array
of
string
did
Optional
DIDs of winning players, if any were recorded as identities.
winnerNames
array
of
string
Optional
Names of winners not represented by a DID.
View raw schema
{
"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."
}