Safety rules

The seven safety rules, your account and your app, rendering other people's content, and what the rules leave out.

The seven safety rules

Gemmein is built for apps you run for your own customers. Team workspaces, organisations and shared company accounts, where a company's members share records, aren't part of it.

RuleWho can readWho can writeUse case
privateOwner only (the dashboard reads every record)Owner onlyPersonal data: tasks, notes, settings
sharedAll signed-in peopleEach person: own records onlyFeeds, communities, team boards
public_readAnyone, without signing inAdmin/owner onlyMenus, listings, single-author blogs
communityAnyone, without signing inEach signed-in person: own records, plain textMulti-author blogs, public boards, profiles
addressedEach person: records addressed to them (the dashboard reads every one)Admin/owner only, naming a recipientNotifications, invoices, order status
directAuthor + the named recipientEach signed-in person, naming a recipientMessages, sharing, requests
admin_writeAll signed-in peopleAdmin/owner onlyApp settings, announcements

Your account and your app

Your Gemmein account and a person using your app are two different things, even when they share an email. Sign in to your own app with that email and you are an ordinary signed-in person: for private collections you see only your own records, under the same safety rule as anyone else. There is no "see everyone" option inside the app. The Gemmein dashboard is where you see every person, every record, every message.

Don't build a role field to hide admin UI. Every session reports member, yours included, so there is no role to branch on and no elevation inside the app. Never filter by userId, and never set userId/owner/role fields. The server derives them from the session and rejects reserved fields (id, userId, ownerUserId, role, createdAt, and others) if you try.

For an admin screen inside your app (a support desk, a moderation queue), create a secret key in the dashboard, scoped read-only to the collections it shows. Keep it on your own server and call your server from the app; a secret key refuses to run in a browser or a phone. See Server: gemmeinServer(sk).

Rendering another person's content

When one person's content renders in another person's session (community, shared, direct), render it with text bindings (textContent, or {} in React/Vue/Svelte), never innerHTML. community, addressed, and direct enforce this server-side: any string field containing HTML tags is refused with 400 html_not_allowed, and the message names the collection's allowsMarkup setting. Your human turns it on in the dashboard (Content: allows markup) for a collection whose app renders HTML safely.

What the safety rules leave out

  • Writes are always a signed-in person. The person is the sign-in: editing your own, per-person write limits and erasure rest on it. A guest book signs people in with an email code, or your server writes with a secret key.
  • Acknowledgements on addressed records live in a private collection, one keyed record per item: acks.create({ item: notice.id }, { key: "ack:" + notice.id }). The app writes an addressed record; its recipient reads it.
  • expand works on community, shared and direct. On private nothing is another person's to read, and public_read and admin_write hold the app's own records with no link fields; join in memory there.
Was this page helpful?

Last updated