At this level
app.zeens · 55- app.zeens.authFull permission-set
- app.zeens.c2pa record Content Credentials (C2PA) read from a post's original photos at upload, for the photos the creator chose to show them on. The rkey matches the rkey of the associated post record, as with app.zeens.postMeta. This is a summary of what the C2PA manifest said, not the manifest itself: the manifest can carry an uncropped ingredient thumbnail and the photographer's GPS, so it is deliberately not republished. The summary is the creator's statement, signed by their repo; `status` records what the valid
- app.zeens.chatPrefs record A user's chat privacy preference: who may start a conversation with them. This is a public policy flag (not message content), so storing it in a public repo is fine. One record per user (rkey 'self'). The server-side gate and the AppView indexer both enforce it. Carries the app.zeens.v marker.
- app.zeens.collection 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.
- app.zeens.collectionItem record A single item (post or article) inside a Zeens collection. The collection itself is referenced by its AT-URI. Removing an item is a record delete. Re-adding the same subject creates a new item record (clients should de-dupe by subject.uri at write time if needed).
- app.zeens.collectionRejection record Written by a community collection's owner when a submitted photo does not qualify for it: either declined in review or removed after approval. Carries no reason; the collection's own rules are the reason. Resets the photographer's auto-approve standing.
- app.zeens.event record An event: a photowalk, workshop, meetup, exhibition or talk. Written to the organiser's own PDS. Others RSVP via app.zeens.rsvp (ATProto handle) or via an email address tracked off-protocol in PocketBase. The app does NOT collect payment: paid events carry free-text paymentInstructions and any URL/link in that field is rejected at write time. Carries the app.zeens.v marker so firehose + Lua filters recognise it. NOTE: the record id stays 'app.zeens.event' and the app.zeens.* namespace is network
- app.zeens.eventComment record A comment (question / feedback / discussion) on an app.zeens.event, written to the commenter's own PDS. Bluesky replies require an app.bsky.feed.post parent, and an event isn't one, so events use this dedicated record (same rationale as app.zeens.post). A `parent` strongRef threads replies, letting the organiser respond in-line. Counted into the event's reply_count. Carries the app.zeens.v marker.
- app.zeens.eventPhoto record Tags one of the author's photo posts to an app.zeens.event, written to the author's own PDS. Only permitted when the author has an app.zeens.rsvp with status 'going' to that event AND the event has already ended; both gates are enforced client- and server-side at write time. Structurally a clone of app.zeens.collectionItem. Removing a tag is a record delete. Carries the app.zeens.v marker.
- app.zeens.featuredItem record An admin-curated featured item, written to the dedicated curator repo (feeder.psky.social). Currently always a post; `kind` future-proofs featured collections. `active=false` pulls the item from the splash carousel but keeps it for the Inspire > Featured archive. Reorder = putRecord with a new `position`; unfeature = putRecord with active=false; hard-remove = deleteRecord.
- app.zeens.getActiveAuthors query Returns the distinct DIDs that have posted Zeens content (have an app.zeens.postMeta record) since an optional `since` timestamp. Powers the 'posted recently' half of the admin Active Users tab in one bulk query instead of a per-user getAuthorFeed.
- app.zeens.getChatGate query Return whether a sender may start/continue a conversation with a recipient, based on the recipient's chatPrefs and the follow relationship. Used by the server-side start gate.
- app.zeens.getChatUnreadCount query Return the total number of unread chat messages for a viewer across all accepted conversations (for the nav badge).
- app.zeens.getCollection query Fetch a single collection record + a recent-items preview for the cover. Returns 404 if visibility=private and viewer != owner.
- app.zeens.getCollectionContributors query Everyone whose photos appear in a collection, most recent first, with their photo count.
- app.zeens.getCollectionItems query List items inside a collection. Returns 404 if the collection is private and viewer != owner. Items are returned newest-first by addedAt.
- app.zeens.getCollections query List collections owned by an actor. Private collections are only returned when viewer == actor.
- app.zeens.getCollectionsContaining query For a viewer, list which of their own collections (private + public) currently contain a given subject URI. Each match includes the parent collection's name, rkey, and visibility. Used by the 'Add to collection' modal to show which boxes are already checked, and by the post-detail page to render a 'part of collection' pill (public collections only).
- app.zeens.getCollectionsFeed query Browse all public collections across users, ordered by most recent item activity (newest item indexed_at). Only collections with at least 3 items are returned (MIN_ITEMS in getCollectionsFeed.lua). Optional `q` filters by name (preferred) then description text.
- app.zeens.getCommunityActivity query What `owner` did with `actor`'s photos: items added to a community collection and rejections, newest first, plus the actor's auto-approve standing.
- app.zeens.getCommunitySubmissions query Submissions to `owner`'s community collections, each with its derived status (pending / approved / declined). Without `actor` returns the pending review queue; with `actor` returns that photographer's own submissions in every status.
- app.zeens.getContentFacets query Category and location counts for the /search discovery landing, computed with the same visibility and matching rules getPhotoFeed applies so a tile's count matches the search it links to. A category counts a post when its postMeta categories match OR the post carries the tag as a hashtag facet.
- app.zeens.getConvos query Return a viewer's conversation list (newest activity first), paginated. No message preview is returned. 'state' selects the inbox or the requests bucket.
- app.zeens.getEngagement query Like count and the viewer's own like for any record URI, one or a batch. Subject-agnostic: post_engagement is keyed by subject URI and the like hook counts likes on anything, so this serves zeens, events, articles and posts without a branch per lexicon. Pass `uris` to ask about a whole listing in one call -- the profile and studio Zeens tabs list from the author's repo, which carries no engagement, so without a batch each card would need its own round trip.
- app.zeens.getEvent query Fetch a single event by AT-URI, hydrated with the organiser's profile and raw RSVP counts (going / interested) aggregated from app.zeens.rsvp records. For gated events (approvalRequired or capacityMode=waitlist) these raw counts are advisory; the SvelteKit layer overlays canonical approved/waitlisted counts from PocketBase, which Lua cannot see.
- app.zeens.getEventComments query List comments on an event via app.zeens.eventComment, newest-first by createdAt. Returns a flat list (each carrying its optional parent ref) so the client can thread organiser replies. Each comment is hydrated with the author's profile and its own like_count + the viewer's like state.
- app.zeens.getEventFacets query Category and mode counts for the events filter strip, aggregated in Postgres over the whole catalog (not tallied from a page of results). Lets the client offer only filters that will actually return something. Scoped by the same time window as getEvents, so an Upcoming strip counts upcoming events.
- app.zeens.getEventPhotos query List photos tagged to an event via app.zeens.eventPhoto, newest-first by addedAt. Each item is hydrated with the underlying post + author profile + engagement so the client can render a card without a per-item round trip. Same shape as getCollectionItems.
- app.zeens.getEventRsvps query List the ATProto RSVPs to an event, hydrated with each responder's profile. Zeens members are surfaced first. Returns raw rsvp records only; email RSVPs and organiser approval/waitlist state live in PocketBase and are merged in by the SvelteKit layer.
- app.zeens.getEvents query Browse events. Defaults to upcoming events (startsAt >= now) ordered by startsAt ascending with a stable uri tie-breaker. Supports multi-value category filtering (OR-matched), mode filtering (in person / online / hybrid), and nearby filtering (lat/lng/radius, reusing the getNearbyPhotos coordinate convention).
- app.zeens.getExifFacets query Aggregate distinct EXIF facet values (makes, models, lenses, apertures, focal lengths, camera/lens gear with counts) across all app.zeens.postMeta records. Powers the search UI's cascading filters and popular-gear chips without needing any client-side aggregation.
- app.zeens.getFeaturedFeed query List admin-curated featured items from the curator repo, joined to their subject posts and hydrated with author + live engagement counts. `activeOnly=true` returns the splash set ordered by admin position; otherwise returns the full archive newest-first. `curator` is the curator account DID.
- app.zeens.getFilmFacets query Aggregate film-stock usage across app.zeens.postMeta records that have film.stockSlug set. Powers the search 'Popular film stocks' sidebar and the per-profile 'Top film stocks' card.
- app.zeens.getFollowingFeed query Get photos from accounts the requesting user follows. Replaces the fan-out getAuthorFeed pattern.
- app.zeens.getHotFeed query Get the 'hot' Zeens home feed: gravity-decayed engagement score over posts that clear the featuring like floor.
- app.zeens.getMemberFollowers query Followers of the given actor who are themselves on Zeens (have authored at least one app.zeens.postMeta record).
- app.zeens.getMemberFollows query Accounts the given actor follows who are themselves on Zeens (have authored at least one app.zeens.postMeta record).
- app.zeens.getMessages query Return the message history for one conversation, newest-first, paginated. Each item's body is base64-obfuscated (not encrypted); Zeens decodes it. The viewer must be a participant.
- app.zeens.getNearbyPhotos query Retrieve geotagged Zeens photos inside a geographic bounding box. Powers the Explore map: each result carries its lat/lng (decoded from the int*1e7 stored in postMeta), the first image cid for a thumbnail, the author identity, and the like count for ordering co-located stacks.
- app.zeens.getPhotoFeed query Retrieve a feed of Zeens photos and videos with optional filters by camera, category, and engagement.
- app.zeens.getPostsByTag query Get Zeens photo posts carrying a hashtag, newest first or by popularity.
- app.zeens.getSubjectCovers query Cover thumbnails for a batch of zeen / collection URIs. Deliberately narrow -- URIs in, cover refs out -- so a notifications list can draw a preview per row without a round trip each. getCollection takes one uri and returns the whole record plus an item count; a zeen had no AppView read at all and getZeen goes to the author's PDS for every page's full text to find one cid.
- app.zeens.getSuggestedUsers query Suggested accounts for a viewer in one query: members with at least minPosts Zeens posts, ordered by posts in the last 30 days then most recent post, excluding the viewer and accounts the viewer already follows. An optional pinned DID leads the list unless it is already followed.
- app.zeens.getTrending query Get trending Zeens photos ranked by engagement within a time window.
- app.zeens.getZeensFeed query Browse published zeens across users, newest first by publishedAt (the date the zeen became readable, stamped once and preserved across edits — not indexed_at, which reorders on a backfill). Drafts, page-less records and zeens with no publishedAt are excluded. Optional `q` filters by title (preferred) then description text.
- app.zeens.hideConvo query Mark a conversation hidden for the viewer (the delete-conversation view side). getConvos excludes it until a new message arrives.
- app.zeens.markConvoSeen query Advance the viewer's per-conversation seen cursor (never moves backwards). Modelled as a query to avoid the DPoP requirement on procedures; it writes internal bookkeeping, not a PDS record.
- app.zeens.message record A single chat message, written to the SENDER's repo. The body is base64-obfuscated (NOT encrypted) so it isn't plainly readable when browsing the repo, but it is not secret — anyone can decode it. Chats are public on the user's PDS. The convoId groups a 1:1 conversation. Carries the app.zeens.v marker so the firehose recognises it.
- app.zeens.portfolio record Configuration for a user's public Portfolio site (e.g. alice.zeens.app). One per user, keyed 'self'. A portfolio is a curated list of the user's COLLECTIONS, displayed beautifully: it holds the subdomain, a theme + layout/columns/gap applied to every collection, the ordered list of collection AT-URIs to show, and an optional home collection. Collections own their own title/subtitle/description/photos/slug, which the portfolio reuses; the site header comes from the user's profile. Stored on the u
- app.zeens.post record A Zeens-only photo post. Structurally a subset of app.bsky.feed.post, but written to a Zeens-owned collection so it is NOT indexed by the Bluesky AppView and never appears on Bluesky. Used when the creator disables 'Post to Bluesky'. Carries the same app.zeens.v marker and supports the full Zeens feature set (likes, reposts, replies, collections, search, EXIF, film, location) via app.zeens.postMeta, which references this record by AT-URI.
- app.zeens.postMeta record Extended metadata for a Zeens photo post — EXIF, categories, license, and optional external link. The rkey matches the rkey of the associated app.bsky.feed.post record.
- app.zeens.profile record Zeens-specific profile extensions. Stored on the user's own PDS so the data is portable — Zeens reads it on top of app.bsky.actor.profile to render extras like social links. The Bluesky profile (name, avatar, banner, bio) remains the canonical identity.
- app.zeens.rsvp record An RSVP to an app.zeens.event, written to the responder's own PDS. This record is the responder's declaration of intent only. The organiser's decision on a gated event (approve / decline / waitlist) is NOT stored here (the organiser cannot mutate another user's repo); it lives off-protocol in PocketBase. Email-only RSVPs from people without a PDS are tracked entirely off-protocol. Carries the app.zeens.v marker.
- app.zeens.scheduledPost record A post waiting to be published. Holds the finished post record and its postMeta exactly as they will be written, so publishing is a copy and nothing is recomputed. Lives on the author's own PDS rather than on Zeens' servers; the images are uploaded at scheduling time and this record keeps them referenced until publish. NOT PRIVATE: like every repo record it is publicly readable before publishAt. Deliberately absent from the AppView's lexicons and firehose collections, so it is never indexed as c
- app.zeens.zeen record A zeen: a sequence of 1:1.414 pages (ISO A-series proportion) mixing photographs and writing, published as a readable object. Pages may draw photos from a collection, from individual posts, or from the author's own uploads — a zeen is a standalone document, not a view of a collection. The AUTHORED PAGES are the artifact: layout is recomputed from them at read time, so a layout improvement reaches every existing zeen. Replaces an earlier record of this NSID that described a print-ready PDF; that
- app.zeens.notification.getUnreadCount query Get the count of unread notifications for a Zeens user (count newer than the user's seenAt cursor).
- app.zeens.notification.listNotifications query List notifications for the authenticated Zeens user. Merges likes, replies, follows, group-membership and group-photo events from the firehose.
- app.zeens.notification.updateSeen query Update the recipient's notification seenAt cursor. Everything older than this timestamp is considered read. Modelled as a query because our AppView has no user OAuth session and the write is internal bookkeeping (not a PDS record).