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 is403 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. Onpublic_readit is refused: only your human writes there, so there is nothing to approve. Anywhere else, and for any other value,gemmein devandgemmein syncrefuse it before anything changes (invalid_publishing). - A relay's
data_changetrigger takespublished: falseto 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" } }
| Operation | What it does | Call |
|---|---|---|
"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 once | open(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 wins | open(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.flaggedBy | open(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 null | open(id).choose("rsvp", "maybe"), choose("rsvp", null) to withdraw |
- Open fields work on
shared,community,public_read,addressedanddirect, up to 10 per collection. Onprivateandadmin_writenobody else reads the records, sogemmein devandgemmein syncrefuse them (invalid_open_fields). record.mineholds 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.rsvpstill says it andrecord.mineRetired.rsvpistrue.record.data.rsvpcounts only the listed choices, and choosing the retired one again is400 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 increate()orupdate()is400 open_field_write. Your server (a secret key) and your dashboard may set a"one of"field increate()orupdate(), to a listed choice ornull; any other value is400 open_value_not_in_list. Counters, per person flags and"one per person of"choices change only throughopen(id), for everyone. See Errors for the rest.
Thanks for telling us.
Thanks for telling us.
Last updated