Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/docs-clone-delete-time-security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
---

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.
1 change: 1 addition & 0 deletions content/docs/concepts/implementation-status.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ The data (`/data`), metadata (`/meta`), and batch endpoints are implemented in `
| `/data/{object}/createMany` | POST | Batch create | ✅ |
| `/data/{object}/updateMany` | POST | Batch update | ✅ |
| `/data/{object}/deleteMany` | POST | Batch delete | ✅ |
| `/data/{object}/{id}/clone` | POST | Clone a record (gated by `enable.clone`) | ✅ |
| `/data/{object}/batch` | POST | Atomic batch operations | ✅ |

### Advanced Protocols
Expand Down
18 changes: 18 additions & 0 deletions content/docs/guides/api-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,24 @@ Batch delete records by ID list.

---

### `POST /data/:object/:id/clone`

Clone a record. Reads the source, drops engine-owned columns (`id`, the audit
fields, autonumbers, and computed `formula`/`summary` values) so they are
re-derived, applies any caller `overrides`, and inserts the copy. Shallow by
design — it duplicates the record's own fields, not its child records.

Gated by the object's `enable.clone` capability (default `true`); an object with
`enable.clone: false` returns `403 CLONE_DISABLED`.

**Body** (optional): `{ "overrides": { "name": "Acme (Copy)" } }` — applied on
top of the copied values (a bare field map is also accepted). The natural place
to set a new name or clear a unique field.

**Response** `201`: `{ object, id, sourceId, record }`

---

## Analytics

Semantic BI queries using a cube-style API. Available when the analytics service is enabled.
Expand Down
15 changes: 14 additions & 1 deletion content/docs/guides/security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,22 @@ than redefining the basics.
|:--|:--|:--|:--|
| `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. |
| `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. |
| `member_default` | Per-org | Standard end-user CRUD on org records | Default profile for invited members. |
| `member_default` | Per-org | Standard end-user CRUD on org records; **writes are owner-scoped** | Default profile for invited members. |
| `viewer_readonly` | Per-org | Read access only | For auditors / read-only stakeholders. |

> **Owner-scoped writes.** `member_default` grants read/create on org records but
> restricts **edit and delete to the records the user created** — via the
> `owner_only_writes` / `owner_only_deletes` RLS policies, keyed on `created_by`
> (the ownership column the engine stamps on every row). These are enforced on
> single-id `update`/`delete` by a **pre-image authorization check**: before the
> mutation the middleware re-reads the target row through the write-operation RLS
> filter, and a member attempting to modify another user's record gets `403`.
> A permission set with `modifyAllRecords` (or no RLS, e.g. `admin_full_access`)
> bypasses this. An object that opts out of audit fields (`systemFields.audit:
> false`, no `created_by`) fails **closed** for member writes — grant
> `modifyAllRecords` or a per-object policy, or model transferable ownership with
> a dedicated owner field + custom policy.

> **Single-org vs. multi-org runtimes.** The wildcard `tenant_isolation`
> RLS row above only takes effect when `@objectstack/plugin-org-scoping`
> is registered (typically via `OS_MULTI_TENANT=true`). In single-org
Expand Down
10 changes: 9 additions & 1 deletion content/docs/protocol/objectql/types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ business_hours_start:
defaultValue: "09:00:00"
```

**Storage format:** `HH:MM:SS`
**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.

**Use cases:**
- Business hours
Expand Down Expand Up @@ -519,6 +519,14 @@ const opportunities = await ObjectQL.query({
- `restrict`: Prevent deletion if references exist
- `cascade`: Delete this record when referenced record is deleted

> **Required foreign keys.** A `required: true` lookup cannot be nulled, so the
> *default* `set_null` automatically escalates to `restrict` on such a field —
> deleting the parent is refused with `409 DELETE_RESTRICTED` (the response
> carries `dependentObject` and `dependentCount`) instead of a confusing
> "<field> is required" validation error. To delete the children along with
> the parent, set `deleteBehavior: cascade` explicitly. An explicit `set_null`
> or `cascade` is always honored as written.

**Multiple lookups:**
```yaml
contacts:
Expand Down