You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reflect runtime behavior shipped this cycle in the hand-written docs:
- api-reference + implementation-status: POST /data/:object/:id/clone (gated by
enable.clone; overrides; 201 {object,id,sourceId,record}).
- protocol/objectql/types: a required lookup FK escalates a defaulted set_null to
restrict → 409 DELETE_RESTRICTED; Field.time accepts HH:MM/HH:MM:SS.
- guides/security: member_default writes are owner-scoped (created_by) and now
enforced on by-id update/delete via a pre-image authorization check; admins /
modifyAllRecords bypass; audit-opt-out objects fail closed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs: document the record-clone endpoint, required-FK delete escalation (DELETE_RESTRICTED), Field.time input format, and owner-scoped member writes — reflecting the runtime behavior shipped this cycle. Docs-only.
Copy file name to clipboardExpand all lines: content/docs/guides/security.mdx
+14-1Lines changed: 14 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -231,9 +231,22 @@ than redefining the basics.
231
231
|:--|:--|:--|:--|
232
232
|`admin_full_access`| Platform (no RLS) | All objects, all system permissions, Studio + Setup, cross-org reads | Reserved for platform operators. Auto-granted to the bootstrap admin (`bootstrapPlatformAdmin`) — the **first registered human**. The non-loginable seed-data identity `usr_system` (role `system`, provisioned before the first sign-up to own seeded rows) is deliberately skipped, so the real admin wins the promotion. |
233
233
|`organization_admin`| Per-org (`tenant_isolation` RLS, only active when `@objectstack/plugin-org-scoping` is loaded) | Wildcard CRUD inside the org, `manage_org_users`, Setup app shell (only org-scoped entries visible), invite members, manage roles assignment |**Read-only** on `sys_role`, `sys_permission_set`, `sys_role_permission_set`, `sys_user_permission_set`, `sys_user_role` to prevent self-elevation. Does **not** see Studio. |
234
-
|`member_default`| Per-org | Standard end-user CRUD on org records | Default profile for invited members. |
234
+
|`member_default`| Per-org | Standard end-user CRUD on org records; **writes are owner-scoped**| Default profile for invited members. |
235
235
|`viewer_readonly`| Per-org | Read access only | For auditors / read-only stakeholders. |
236
236
237
+
> **Owner-scoped writes.**`member_default` grants read/create on org records but
238
+
> restricts **edit and delete to the records the user created** — via the
239
+
> `owner_only_writes` / `owner_only_deletes` RLS policies, keyed on `created_by`
240
+
> (the ownership column the engine stamps on every row). These are enforced on
241
+
> single-id `update`/`delete` by a **pre-image authorization check**: before the
242
+
> mutation the middleware re-reads the target row through the write-operation RLS
243
+
> filter, and a member attempting to modify another user's record gets `403`.
244
+
> A permission set with `modifyAllRecords` (or no RLS, e.g. `admin_full_access`)
245
+
> bypasses this. An object that opts out of audit fields (`systemFields.audit:
246
+
> false`, no `created_by`) fails **closed** for member writes — grant
247
+
> `modifyAllRecords` or a per-object policy, or model transferable ownership with
248
+
> a dedicated owner field + custom policy.
249
+
237
250
> **Single-org vs. multi-org runtimes.** The wildcard `tenant_isolation`
238
251
> RLS row above only takes effect when `@objectstack/plugin-org-scoping`
239
252
> is registered (typically via `OS_MULTI_TENANT=true`). In single-org
Copy file name to clipboardExpand all lines: content/docs/protocol/objectql/types.mdx
+9-1Lines changed: 9 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -353,7 +353,7 @@ business_hours_start:
353
353
defaultValue: "09:00:00"
354
354
```
355
355
356
-
**Storage format:** `HH:MM:SS`
356
+
**Storage format:** `HH:MM:SS` — input accepts `HH:MM` or `HH:MM:SS` (with an optional fractional part and `Z`/offset). A `time` is a wall-clock value, not an instant: it is validated as a time-of-day, not parsed as a date.
0 commit comments