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.
| Rule | Who can read | Who can write | Use case |
|---|---|---|---|
private | Owner only (the dashboard reads every record) | Owner only | Personal data: tasks, notes, settings |
shared | All signed-in people | Each person: own records only | Feeds, communities, team boards |
public_read | Anyone, without signing in | Admin/owner only | Menus, listings, single-author blogs |
community | Anyone, without signing in | Each signed-in person: own records, plain text | Multi-author blogs, public boards, profiles |
addressed | Each person: records addressed to them (the dashboard reads every one) | Admin/owner only, naming a recipient | Notifications, invoices, order status |
direct | Author + the named recipient | Each signed-in person, naming a recipient | Messages, sharing, requests |
admin_write | All signed-in people | Admin/owner only | App 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
addressedrecords live in aprivatecollection, one keyed record per item:acks.create({ item: notice.id }, { key: "ack:" + notice.id }). The app writes an addressed record; its recipient reads it. expandworks oncommunity,sharedanddirect. Onprivatenothing is another person's to read, andpublic_readandadmin_writehold the app's own records with no link fields; join in memory there.
Thanks for telling us.
Thanks for telling us.
Last updated