Permission & Access-Control Model
Permission & Access-Control Model
Status: Draft v0.1
Audience: Backend & Front-end engineers
Purpose: Describe how global roles, organisation groups, abilities and container-level ACLs interact to decide who can do what, where.
1. Layers of Authorisation
| Layer | Scope | Implemented with | Example |
|---|---|---|---|
| System Role | Whole platform | system_roles table + JWT role_id claim |
system_owner, manufacturer_issuer |
| Org Group | Single organisation | org_permission_groups, org_group_members |
Warehouse Staff, Family, External Auditor |
| Ability | Atomic action | role_abilities, org_group_abilities |
OBJECT_READ, SPATIAL_MOVE, RESET_PWD |
| Container ACL | Sub-tree of spatial graph | container_acl table |
Deny OBJECT_READ in CEO Room for Everyone |
Decision flow (highest → lowest):
- Super-Admin bypasses all checks (
role_id⇒ abilitySUPER_ADMIN). - RLS policy calls
jwt_has_ability('X'). If false → deny.
– Abilities come either from the system role or from one/more org groups. - When ability is spatial (read/move),
jwt_scope_allows_*helper evaluates current container ACL hierarchy.
– Deny rows override allow rows deeper in the path.
2. Tables & Helpers
roles / role_abilities (global)
roles(role_id PK, role_name text, is_internal bool)
role_abilities(role_id fk, ability text)
org-scoped groups
org_permission_groups(group_id PK, organisation_id fk, group_name text)
org_group_members(group_id fk, user_id uuid)
org_group_abilities(group_id fk, ability text)
container ACL
container_acl(
container_id uuid REFERENCES object_instances(id),
group_id uuid REFERENCES org_permission_groups(group_id),
ability text,
mode enum('allow','deny') default 'allow'
)
Helper functions (simplified snippets)
create function jwt_has_ability(_a text) returns boolean ...;
create function jwt_scope_allows_container(_container uuid) returns boolean ...;
create function jwt_can_see_object(_obj uuid) returns boolean ...;
See api_security_guidelines.md → JWT Claim Design for claim format.
3. Ability Catalogue (v1)
| Category | Ability Key | Typical Holders | Description |
|---|---|---|---|
| Object CRUD | OBJECT_READ |
all roles | View object metadata & images |
OBJECT_CREATE |
editors, makers | Create new object instance or class | |
OBJECT_UPDATE |
editors | Edit name/description/properties | |
OBJECT_DELETE |
admins | Hard-delete object & graph links | |
| Spatial | SPATIAL_MOVE |
movers, scanners | Change current spatial relationship |
SPATIAL_SET_EXPECTED |
admins, planners | Set / change expected (home) location | |
| Functional & Lifecycle | FUNCTIONAL_EDIT |
technicians | Add/remove functional relations |
STATUS_UPDATE |
technicians | Add/remove lifecycle statuses | |
| Ownership & Commerce | OWNERSHIP_TRANSFER |
admins | Transfer ownership inside org |
OFFER_LEND |
lend desk | Create & accept lend offers | |
OFFER_RENT |
rental desk | Create & accept rental agreements | |
OFFER_SELL |
sales | Create & accept sale offers | |
OFFER_AUCTION |
auction house | Manage auction lots | |
| Identifiers | IDENTIFIER_MINT |
manufacturer issuers | Mint new PlingsIdentifier |
IDENTIFIER_REVOKE |
super-admin | Revoke compromised identifiers | |
| Batch & Collection | BATCH_CREATE |
camera workflow | Rapid image batch capture |
COLLECTION_BULK_ACTION |
power users | Bulk move / transfer operations | |
| Organisation Admin | ORG_USER_INVITE |
org admin | Invite / remove users in org |
ORG_ROLE_ASSIGN |
org admin | Assign users to permission groups | |
ORG_BILLING_VIEW |
org admin | View usage & invoices | |
ORG_BILLING_PAY |
finance | Approve payments, apply credits | |
ORG_AUDIT_VIEW |
org admin | View audit log for their organisation | |
| Plings Global Admin | ADMIN_CLASS_MANAGEMENT |
plings admin | Create/edit/delete object classes globally |
ADMIN_BILLING_MANAGEMENT |
plings admin | Handle invoicing across all organizations | |
ADMIN_TRANSACTION_RESOLVE |
plings admin | Resolve sale/rent/ownership conflicts | |
ADMIN_WALLET_MANAGEMENT |
plings admin | Issue HD wallet spaces for tags | |
ADMIN_USER_MANAGEMENT |
plings admin | Manage users across organizations | |
ADMIN_ORG_MANAGEMENT |
plings admin | Create/suspend/manage organizations | |
ADMIN_PERMISSION_ASSIGN |
plings admin | Assign roles and permissions globally | |
ADMIN_AUDIT_ACCESS |
plings admin | Access audit logs across all organizations | |
ADMIN_CONTENT_MODERATION |
plings admin | Moderate user-generated content | |
ADMIN_SUPPORT_ESCALATION |
plings admin | Handle customer support escalations | |
ADMIN_MARKETPLACE_CONTROL |
plings admin | Manage marketplace listings and disputes | |
ADMIN_ANALYTICS_ACCESS |
plings admin | Access business analytics and reports | |
| Plings Developer Tools | DEV_BACKEND_SWITCH |
plings developer | Access backend switching tools |
DEV_DEBUG_PANEL |
plings developer | Access development debug panels | |
DEV_CONSOLE_ACCESS |
plings developer | Access development console tools | |
DEV_API_TESTING |
plings developer | Access API testing interfaces | |
DEV_DATABASE_INSPECT |
plings developer | Inspect database states and queries | |
DEV_PERFORMANCE_MONITOR |
plings developer | Access performance monitoring tools | |
DEV_FEATURE_FLAGS |
plings developer | Control feature flag systems | |
DEV_SYSTEM_DIAGNOSTICS |
plings developer | Access system diagnostic tools | |
DEV_LOG_ACCESS |
plings developer | Access detailed system logs | |
DEV_DEPLOYMENT_TOOLS |
plings developer | Access deployment and CI/CD tools | |
| Support & Super | RESET_PWD |
support | Reset password / MFA for any user |
IMPERSONATE_USER |
support | Issue short-lived shadow JWT | |
ACL_BYPASS |
support | Temporarily bypass container ACL | |
SUPER_ADMIN |
system owner | Full bypass of all checks |
Abilities can be granted to system roles or org permission groups. The list is data-driven—adding a new ability only requires inserting a row and referencing
jwt_has_ability('NEW_ABILITY')in policies/resolvers.
4. ACL Inheritance Algorithm
- Starting from the current spatial parent (
IN/ON/UNDER), walk upward. - Accumulate ACL rows (deny overrides allow).
- Stop at organisation root.
- If no matching ACL row → fall back to organisation-wide visibility.
A misplaced hammer left in the CEO room becomes hidden because its current path passes through a deny ACL; once scanned and moved the path changes and the ACL check re-evaluates.
5. Example Scenarios
5.1 CEO Private Room
Room-123 ACL: DENY OBJECT_READ group Everyone
Room-123 ACL: ALLOW OBJECT_READ group CEO_Private
Everyone group loses visibility; CEO’s private group keeps it.
5.2 Family vs. Medicine-Box
MedicineBox ACL: DENY OBJECT_READ group Family
Everything else in the house is visible to Family because it inherits the default allow.
5.3 Support Impersonation
Support role has ability IMPERSONATE_USER. Resolver checks that ability before issuing a short-lived scoped JWT; RLS continues to apply for the impersonated identity.
6. Open Items
- Decide on complete
abilityvocabulary (see spreadsheet). - JSON vs. table storage for
groups[]&abilitiesclaim (size trade-off). - Admin UI for inspecting effective ACL of a selected object.