app.zeens.event
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 plumbing — it is not renamed when the product is. Two orthogonal axes describe an event: `mode` (WHERE it happens — in person, online, or both) and `categories` (WHAT it is — one or more of photowalk/workshop/meetup/exhibition/talk/other). The `hostedBy` field is DEPRECATED (the organiser is the record owner); kept for back-compat with old records.
Details · record, key tid
| Kind | record |
|---|---|
| Record key | tid |
| Authority | zeens.app |
| Indexed |
Record
record · key tidProperties
Zeens version marker (always 1).
approvalRequired
booleanWhen true, an RSVP is pending until the organiser approves it; only approved RSVPs count toward the cap and the attendee list. Approval state is tracked off-protocol (the organiser cannot mutate another user's rsvp record). Default false.
capacityMode
stringBehaviour when maxParticipants is reached. 'hard' = block new going RSVPs. 'waitlist' = overflow goes on a waitlist, promoted in RSVP order. Only meaningful when maxParticipants is set. Default 'hard'.
knownValues: hard | waitlist
WHAT the event is. One or more (max 3) — an event can be both a photowalk and a meetup. Drives browse/filter, which OR-matches any element. Orthogonal to `mode`. The legacy value 'online_meetup' is tolerated on read and means mode 'online' + category 'meetup'.
minLength: 1maxLength: 3
knownValues: photowalk | workshop | meetup | exhibition | talk | other
coverImage
blobWide cover image shown on the event header and share previews.
maxSize: 4000000accept: image/jpeg, image/png, image/webp
createdBy
stringDisplay text for the event creator/organiser (the account that owns this record).
maxLength: 200
description
stringLong-form event description.
maxLength: 3000
endsAt
string · datetimeOptional event end instant.
facets
arrayRich-text facets (links, mentions) over the description, reusing the Bluesky richtext lexicon.
hostedBy
stringDEPRECATED. Display text for who is hosting. The organiser is the record owner, so this is no longer written; kept so old records still read.
maxLength: 200
itinerary
arrayOrdered agenda for the event: a list of items, each with optional time, descriptive text, and an optional location. Works for any event type — a photowalk's route, a workshop's schedule, an exhibition's programme. Items that carry coordinates are drawn on the event map as numbered pins in order; an event whose items have no coordinates simply renders the list with no map.
maxLength: 30
location
refPhysical location. Expected for mode 'in_person' and 'hybrid'; absent for 'online'.
maxParticipants
integerOptional cap on confirmed (going) participants. Absent = unlimited.
minimum: 1
WHERE the event happens, and one of exactly three values. 'in_person' needs a location; 'online' needs a virtualUrl and has no location; 'hybrid' needs both. Orthogonal to `categories` — an online workshop is mode 'online' + categories ['workshop']. Records written before this field carried meaning default to 'in_person' on read. The legacy value 'virtual' is tolerated on read and means 'online'.
knownValues: in_person | online | hybrid
paid
booleanWhether the event costs money. The app never processes payment.
paymentInstructions
stringFree-text explanation of how the organiser collects payment out of band. MUST NOT contain a URL/link; rejected at write time client- and server-side.
maxLength: 1000
photoCategories
arrayPhotography genre tags (Street, Landscape, Portrait, ...). Up to 3, optional. Drawn from the shared category list used by posts. Distinct from `categories`, which is the event type.
maxLength: 3
maxLength: 100
Who may RSVP. 'atmosphere' = any ATProto account. 'photosky' = members only. 'anyone_email' = anyone, including non-ATProto people via an email address. Enforcement is soft (obscurity-level), like collection visibility.
knownValues: atmosphere | photosky | anyone_email
Event start, as an absolute instant. Render in `timezone`.
IANA timezone name (e.g. 'America/New_York'). Stored separately from startsAt so calendar export (.ics DTSTART;TZID) and the displayed local time are correct.
maxLength: 100
Event title.
maxLength: 300maxGraphemes: 150
virtualUrl
string · uriJoin link for events with mode 'online' or 'hybrid'. Required for those modes. Shown only to RSVP'd users in the client.
#itineraryItem
objectProperties
location
refOptional location for this item. Only meaningful for events with mode 'in_person' or 'hybrid'. Items with lat/lng are plotted on the event map.
What happens at this point in the event (e.g. 'Meet at the park entrance', 'Darkroom demo', 'Q&A with the curator').
maxLength: 500
time
stringFree-text time label for this item (e.g. '9:00 AM', 'Lunch'). Stored as text, not a datetime, so it renders verbatim without timezone handling.
maxLength: 50
#link
object#location
objectSimilar lexicons
semantic matchLexicons whose schemas describe something close to this one. Check them before publishing a new one that overlaps.
-
An independently addressable public event appearance for a Craftsky business.
-
Optional fields that can be used to provide less pertinent information about the event
-
org.devcon.event
record -
org.devcon.event.vone
recordOptional fields that can be used to provide less pertinent information about the event
-
org.devcon.event.testcache
record