Publishing and open fields

Drafts, posts that wait for approval, and fields readers can change.

Drafts on public collections

On public_read and community, { published: false } saves a draft the public can't see, enforced by the server. The author still sees their own; your dashboard shows every draft.

const post = await notes.create({ title: "wip" }, { published: false })  // hidden
await notes.update(post.id, {}, { published: true })                     // now live

post.published   // top-level boolean, beside id — not post.data.published

Never fake drafts with a status field + client-side filtering on a public collection; the data still reaches every reader's network tab. published is an option, not a data field; the server rejects it inside data.

Posts that wait for approval

A community collection can hold every post until your human approves it. It is a setting on the safety rule, in plain words, in gemmein/collections/<name>.json or under Publishing on the collection's page in the dashboard's Data:

{ "rule": "community", "means": "reviews, approved before they show", "publishing": "owner approves" }
  • "authors publish" is the default, and what a collection with no setting does.
  • With "owner approves", a person's post is saved as a draft only its author sees. A person's { published: true } on create or update is 403 moderation_required.
  • Your human publishes from the dashboard's Records page; Collections shows how many posts wait. Their server can publish with a secret key, and a relay can too.
  • Your human can't change the rule of a collection while posts wait (409 posts_waiting): approve or delete them, or turn the setting off, first.
  • An author's change to an approved post returns it to waiting (a save that changes nothing keeps the approval), and Collections counts it among the posts waiting ("new or edited after approval"). Unpublishing your own post is always allowed.
  • The setting works on community. On public_read it is refused: only your human writes there, so there is nothing to approve. Anywhere else, and for any other value, gemmein dev and gemmein sync refuse it before anything changes (invalid_publishing).
  • A relay's data_change trigger takes published: false to tell your human each time a post starts waiting.

Fields readers can change

Every record is its author's to edit. For likes, votes, RSVPs, "accept" or "mark as read", name the fields other readers may change under "openFields" in gemmein/collections/<name>.json, or under Open fields on the dashboard's collection's page in Data. Each field gets one operation, and every other field stays its author's. With no openFields, the default, only the author changes anything.

{ "rule": "community", "openFields": { "likes": "count once per person", "status": { "one of": ["accepted", "declined"] }, "read": "per person flag" } }
OperationWhat it doesCall
"count once per person"A number each person adds 1 to once and can take back. The total is record.data.likes, never below 0; the same person twice counts onceopen(id).count("likes", 1), count("likes", -1)
{ "one of": [...] }A choice from the list (up to 50) that any signed-in person who reads the record may set; the last one set winsopen(id).set("status", "accepted")
"per person flag"Each person's own yes or no, which only they see in record.mine; the record itself never changes. Your dashboard and a secret key read who set it in record.flaggedByopen(id).flag("read", true)
"one per person of"A poll or an RSVP: "rsvp": "one per person of yes, maybe, no" (or { "one per person of": [...] } when a choice holds a comma), on a field declared { "type": "json" }. Each person holds one choice, and can change or withdraw it. The record counts each choice, record.data.rsvp → { yes: 3, maybe: 1, no: 0 } in the listed order, and record.mine.rsvp is your choice or nullopen(id).choose("rsvp", "maybe"), choose("rsvp", null) to withdraw
  • Open fields work on shared, community, public_read, addressed and direct, up to 10 per collection. On private and admin_write nobody else reads the records, so gemmein dev and gemmein sync refuse them (invalid_open_fields).
  • record.mine holds your own marks ({ likes: true, read: false, rsvp: "yes" }), so the app can show a filled heart.
  • When many people choose at once, each person holds exactly one choice and the counts equal the choices held. A choice outside the list is 400 open_value_not_in_list, naming the choices. When a person's account is deleted, their choice stays in the counts as an anonymous number, as a like does.
  • When a choice is taken off the list, people who hold it keep it: record.mine.rsvp still says it and record.mineRetired.rsvp is true. record.data.rsvp counts only the listed choices, and choosing the retired one again is 400 open_value_not_in_list. Putting it back on the list brings its count back.
  • A change to an open field never moves record.version, and never sends an approved post back to waiting.
  • A person signed in to your app changes open fields only through open(id); writing one in create() or update() is 400 open_field_write. Your server (a secret key) and your dashboard may set a "one of" field in create() or update(), to a listed choice or null; any other value is 400 open_value_not_in_list. Counters, per person flags and "one per person of" choices change only through open(id), for everyone. See Errors for the rest.
Was this page helpful?

Last updated