Pre-alpha. No tagged release and no upgrade path between versions. Use for evaluation and development only, not production.
Core DevPre-alpha

Record rules

Record rules (sys.rule) restrict which rows a user sees or modifies, on top of model ACLs (sys.access). Same rules apply to the web UI and JSON-RPC.

When to use

  • Users share a model but must not see each other's rows (e.g. salespeople see only their company's orders)
  • Multi-company isolation within one database

Use ACLs first for coarse CRUD; add record rules only when row filtering is required.

Model fields

FieldPurpose
nameRule label
model_idTarget model
domain_forceJSON domain (see Domain filters)
perm_read, perm_write, perm_create, perm_unlinkWhich operations the rule applies to
globalApply to all users (vs group-scoped)
groupsMany2many to core.group when not global

Administrators edit rules under Settings → Security → Record rules when security_admin.xml is loaded.

Loading from addons

Place rules in security/*_rules.xml (or inline in security.xml). List the file in manifest.json → data after groups and ACLs.

xml
xml
<record id="rule_sale_order_company" model="sys.rule">
  <field name="name">Sales orders: multi-company</field>
  <field name="model_id" ref="model_sale_order"/>
  <field name="domain_force">[["company_id", "in", "$company_ids"]]</field>
  <field name="perm_read" eval="True"/>
  <field name="perm_write" eval="True"/>
  <field name="global" eval="True"/>
</record>

Run -u your_module after changes. Rule cache invalidates on update.

Global vs group rules

  • Global rules — AND-combined; every user must satisfy them
  • Group rules — OR-combined among rules sharing the same groups; then AND with globals

Keep domains testable — overly complex rules are hard to debug.

Multi-company pattern

Typical pattern for business documents:

json
json
[["company_id", "in", "$company_ids"]]

The active company comes from the company switcher (POST /web/company/switch). This is not multi-tenant SaaS — one PostgreSQL database, shared schema. See Isolation model.

Worked example: CRM own leads

  1. Create group crm.group_user (already in CRM addon)
  2. ACL grants read/write on crm.lead for that group
  3. Optional record rule: [["user_id", "=", "$uid"]] for non-managers

Managers use a separate group without the restrictive rule or with global rules that allow all leads in company.

RPC and exports

JSON-RPC search, search_read, and report export all enforce the same record rules as the workspace UI.

See also