# app.zeens.collection

> Published by [zeens.app](https://lexicon.garden/identity/did:plc:pwpuqwge6g7xrjmfbw73uycw)

✓ This is the authoritative definition for this NSID.

## Links

- [View on Lexicon Garden](https://lexicon.garden/lexicon/did:plc:pwpuqwge6g7xrjmfbw73uycw/app.zeens.collection)
- [Documentation](https://lexicon.garden/lexicon/did:plc:pwpuqwge6g7xrjmfbw73uycw/app.zeens.collection/docs)
- [Examples](https://lexicon.garden/lexicon/did:plc:pwpuqwge6g7xrjmfbw73uycw/app.zeens.collection/examples)

## Definitions

### `app.zeens.collection#coverPhoto`

**Type**: `object`

Pointer to one photo in the collection, used as its cover. Stores the image blob CID together with the photo's AUTHOR DID (not the collection owner's) so a cover picked from another user's photo still resolves on the CDN. Readers must ignore the pointer unless both `cid` and `did` are present.

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `cid` | `string` | Yes | CID of the image blob itself, NOT of the post record. |
| `did` | `string` (did) | Yes | DID of the photo's author, which owns the blob. May differ from the collection owner. |
| `uri` | `string` (at-uri) | No | AT-URI of the subject post the cover was picked from. Used to match the pointer against the collection's items (e.g. to clear it when that photo is removed). |

### `app.zeens.collection`

**Type**: `record`

A user-curated collection (folder) of Zeens posts and articles. Visibility controls whether anyone other than the owner can see it via the AppView. The cover is the owner's chosen `coverPhoto` when set, otherwise the most recently added item, resolved at render time.

**Key**: `tid`

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `animation` | `string` | No | Story-layout scroll animation. 'alternate' fades photos in from alternating sides as they enter the viewport. Respects prefers-reduced-motion. Default 'none'. |
| `app.zeens.v` | `integer` | No | Zeens marker so the firehose / lua filters can identify our records. |
| `autoApprove` | `boolean` | No | Community collections only: approve every submission at once, whatever the photographer's standing. |
| `community` | `boolean` | No | A community collection: owned by the Zeens account, open to submissions. Only honoured on collections in the configured community account's repo; anyone else setting it changes nothing. |
| `coverImage` | `blob` | No | Legacy user-uploaded cover image, resolved against the OWNER's DID. Superseded by `coverPhoto`; still honoured for records written before it existed. Readers should prefer `coverPhoto` when both are set. |
| `coverPhoto` | `ref` → `#coverPhoto` | No | Optional pointer to one photo already in this collection, chosen by the owner as its cover. When unset, readers fall back to the most recently added photo. |
| `coverPhotos` | `array` | No | Community collections only: up to four photos from the collection shown together as its cover, in order. Each carries the photo's image blob cid and author DID so it resolves on the CDN, like coverPhoto. |
| `createdAt` | `string` (datetime) | Yes |  |
| `description` | `string` | No | Optional long-form description shown in the story layout's left rail and used as the collection's meta description for share previews. |
| `gridColumns` | `integer` | No | Number of columns when gridLayout='grid'. Allowed: 2 or 3. Default 2. |
| `gridGap` | `integer` | No | Gap in pixels between photos when gridLayout='grid'. Allowed: 0, 4, 8, or 16. Default 8. |
| `gridLayout` | `string` | No | How photos stack in the portfolio view. Both options preserve natural aspect ratio (no cropping). 'single' = one column at full width. 'grid' = masonry grid; column count + gap are controlled by `gridColumns` and `gridGap`. Default 'single'. |
| `name` | `string` | Yes | Display name for the collection. |
| `publication` | `ref` → `#publication` | No | Set once this collection has been published to the ATmosphere as a site.standard.document. Absent means never published. Cleared (and the document deleted) if the collection is later made private. |
| `rules` | `string` | No | Community collections only: the theme and rules a photo has to meet. Shown on the collection page; a declined submission means the photo did not meet them. |
| `showCredit` | `boolean` | No | Show each photo's photographer credit. Defaults to TRUE when absent. Only ever written as false. |
| `showExif` | `boolean` | No | Show each photo's camera settings (or its film stock) beneath it in the single-column story layout. Defaults to TRUE when absent: attribution is opt-out, so a record written before this field existed keeps its full caption. Only ever written as false. |
| `showLicense` | `boolean` | No | Show each photo's licence label. Defaults to TRUE when absent. Only ever written as false. |
| `subtitle` | `string` | No | Short tagline shown under the title in the story layout. |
| `theme` | `string` | No | Background palette for the story layout. Default 'light'. |
| `title` | `string` | No | Long-form display title shown in the story layout. Falls back to `name` when unset. |
| `visibility` | `string` | Yes | public = visible to anyone via the AppView. private = only the owner can fetch it via getCollection. Records remain readable from the user's PDS by anyone who knows the URI; treat 'private' as obscurity-level, not cryptographic. |

### `app.zeens.collection#publication`

**Type**: `object`

Pointer to the site.standard.document this collection publishes as, and the Bluesky post announcing it.

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `bskyPostRef` | `ref` → `com.atproto.repo.strongRef` | No | The Bluesky post announcing this collection, when the owner chose to announce. Kept so the announcement can be found later; it does NOT suppress re-announcing, since ticking the box is an explicit request each time. |
| `canonicalUrl` | `string` (uri) | No | The public address on the owner's portfolio, e.g. https://alice.zeens.app/<rkey>. The document's `site` + `path` resolve to this, and it is the host that serves the /.well-known/site.standard.publication proof. Stored so the collection page canonicalises to what the record actually says. |
| `document` | `string` (at-uri) | Yes | AT-URI of the site.standard.document on the owner's repo. Re-publishing reuses this record's rkey so the document is updated in place rather than duplicated. |
| `documentCid` | `string` (cid) | No | CID of the document, for the strongRef the Bluesky announcement carries. |
| `publishedAt` | `string` (datetime) | No |  |
| `site` | `string` | No | The document's `site`: a publication AT-URI. Collections publish INTO the owner's site.standard.publication (auto-created on first publish) because only an at:// ref renders the rich standard.site card on Bluesky. Older records may carry a plain https URL from when collections published as loose documents. |

## Raw Schema

```json
{
  "$type": "com.atproto.lexicon.schema",
  "defs": {
    "coverPhoto": {
      "description": "Pointer to one photo in the collection, used as its cover. Stores the image blob CID together with the photo's AUTHOR DID (not the collection owner's) so a cover picked from another user's photo still resolves on the CDN. Readers must ignore the pointer unless both `cid` and `did` are present.",
      "properties": {
        "cid": {
          "description": "CID of the image blob itself, NOT of the post record.",
          "type": "string"
        },
        "did": {
          "description": "DID of the photo's author, which owns the blob. May differ from the collection owner.",
          "format": "did",
          "type": "string"
        },
        "uri": {
          "description": "AT-URI of the subject post the cover was picked from. Used to match the pointer against the collection's items (e.g. to clear it when that photo is removed).",
          "format": "at-uri",
          "type": "string"
        }
      },
      "required": [
        "cid",
        "did"
      ],
      "type": "object"
    },
    "main": {
      "description": "A user-curated collection (folder) of Zeens posts and articles. Visibility controls whether anyone other than the owner can see it via the AppView. The cover is the owner's chosen `coverPhoto` when set, otherwise the most recently added item, resolved at render time.",
      "key": "tid",
      "record": {
        "properties": {
          "animation": {
            "description": "Story-layout scroll animation. 'alternate' fades photos in from alternating sides as they enter the viewport. Respects prefers-reduced-motion. Default 'none'.",
            "knownValues": [
              "none",
              "alternate"
            ],
            "type": "string"
          },
          "app.zeens.v": {
            "description": "Zeens marker so the firehose / lua filters can identify our records.",
            "type": "integer"
          },
          "autoApprove": {
            "description": "Community collections only: approve every submission at once, whatever the photographer's standing.",
            "type": "boolean"
          },
          "community": {
            "description": "A community collection: owned by the Zeens account, open to submissions. Only honoured on collections in the configured community account's repo; anyone else setting it changes nothing.",
            "type": "boolean"
          },
          "coverImage": {
            "accept": [
              "image/jpeg",
              "image/png",
              "image/webp"
            ],
            "description": "Legacy user-uploaded cover image, resolved against the OWNER's DID. Superseded by `coverPhoto`; still honoured for records written before it existed. Readers should prefer `coverPhoto` when both are set.",
            "maxSize": 4000000,
            "type": "blob"
          },
          "coverPhoto": {
            "description": "Optional pointer to one photo already in this collection, chosen by the owner as its cover. When unset, readers fall back to the most recently added photo.",
            "ref": "#coverPhoto",
            "type": "ref"
          },
          "coverPhotos": {
            "description": "Community collections only: up to four photos from the collection shown together as its cover, in order. Each carries the photo's image blob cid and author DID so it resolves on the CDN, like coverPhoto.",
            "items": {
              "properties": {
                "cid": {
                  "description": "Image blob CID.",
                  "type": "string"
                },
                "did": {
                  "format": "did",
                  "type": "string"
                },
                "uri": {
                  "format": "at-uri",
                  "type": "string"
                }
              },
              "required": [
                "uri",
                "cid",
                "did"
              ],
              "type": "object"
            },
            "maxLength": 4,
            "type": "array"
          },
          "createdAt": {
            "format": "datetime",
            "type": "string"
          },
          "description": {
            "description": "Optional long-form description shown in the story layout's left rail and used as the collection's meta description for share previews.",
            "maxLength": 2000,
            "type": "string"
          },
          "gridColumns": {
            "description": "Number of columns when gridLayout='grid'. Allowed: 2 or 3. Default 2.",
            "maximum": 3,
            "minimum": 2,
            "type": "integer"
          },
          "gridGap": {
            "description": "Gap in pixels between photos when gridLayout='grid'. Allowed: 0, 4, 8, or 16. Default 8.",
            "maximum": 16,
            "minimum": 0,
            "type": "integer"
          },
          "gridLayout": {
            "description": "How photos stack in the portfolio view. Both options preserve natural aspect ratio (no cropping). 'single' = one column at full width. 'grid' = masonry grid; column count + gap are controlled by `gridColumns` and `gridGap`. Default 'single'.",
            "knownValues": [
              "single",
              "grid"
            ],
            "type": "string"
          },
          "name": {
            "description": "Display name for the collection.",
            "maxLength": 100,
            "type": "string"
          },
          "publication": {
            "description": "Set once this collection has been published to the ATmosphere as a site.standard.document. Absent means never published. Cleared (and the document deleted) if the collection is later made private.",
            "ref": "#publication",
            "type": "ref"
          },
          "rules": {
            "description": "Community collections only: the theme and rules a photo has to meet. Shown on the collection page; a declined submission means the photo did not meet them.",
            "maxLength": 3000,
            "type": "string"
          },
          "showCredit": {
            "description": "Show each photo's photographer credit. Defaults to TRUE when absent. Only ever written as false.",
            "type": "boolean"
          },
          "showExif": {
            "description": "Show each photo's camera settings (or its film stock) beneath it in the single-column story layout. Defaults to TRUE when absent: attribution is opt-out, so a record written before this field existed keeps its full caption. Only ever written as false.",
            "type": "boolean"
          },
          "showLicense": {
            "description": "Show each photo's licence label. Defaults to TRUE when absent. Only ever written as false.",
            "type": "boolean"
          },
          "subtitle": {
            "description": "Short tagline shown under the title in the story layout.",
            "maxLength": 200,
            "type": "string"
          },
          "theme": {
            "description": "Background palette for the story layout. Default 'light'.",
            "knownValues": [
              "light",
              "dark"
            ],
            "type": "string"
          },
          "title": {
            "description": "Long-form display title shown in the story layout. Falls back to `name` when unset.",
            "maxLength": 200,
            "type": "string"
          },
          "visibility": {
            "description": "public = visible to anyone via the AppView. private = only the owner can fetch it via getCollection. Records remain readable from the user's PDS by anyone who knows the URI; treat 'private' as obscurity-level, not cryptographic.",
            "knownValues": [
              "public",
              "private"
            ],
            "type": "string"
          }
        },
        "required": [
          "name",
          "visibility",
          "createdAt"
        ],
        "type": "object"
      },
      "type": "record"
    },
    "publication": {
      "description": "Pointer to the site.standard.document this collection publishes as, and the Bluesky post announcing it.",
      "properties": {
        "bskyPostRef": {
          "description": "The Bluesky post announcing this collection, when the owner chose to announce. Kept so the announcement can be found later; it does NOT suppress re-announcing, since ticking the box is an explicit request each time.",
          "ref": "com.atproto.repo.strongRef",
          "type": "ref"
        },
        "canonicalUrl": {
          "description": "The public address on the owner's portfolio, e.g. https://alice.zeens.app/<rkey>. The document's `site` + `path` resolve to this, and it is the host that serves the /.well-known/site.standard.publication proof. Stored so the collection page canonicalises to what the record actually says.",
          "format": "uri",
          "type": "string"
        },
        "document": {
          "description": "AT-URI of the site.standard.document on the owner's repo. Re-publishing reuses this record's rkey so the document is updated in place rather than duplicated.",
          "format": "at-uri",
          "type": "string"
        },
        "documentCid": {
          "description": "CID of the document, for the strongRef the Bluesky announcement carries.",
          "format": "cid",
          "type": "string"
        },
        "publishedAt": {
          "format": "datetime",
          "type": "string"
        },
        "site": {
          "description": "The document's `site`: a publication AT-URI. Collections publish INTO the owner's site.standard.publication (auto-created on first publish) because only an at:// ref renders the rich standard.site card on Bluesky. Older records may carry a plain https URL from when collections published as loose documents.",
          "type": "string"
        }
      },
      "required": [
        "document"
      ],
      "type": "object"
    }
  },
  "id": "app.zeens.collection",
  "lexicon": 1
}
```
