Permissions & Authorization
Status: ๐ก gates validated; fine-grained CRUD matrix to be validated against authz code ยท Last validated: 2026-09-06
"Who can do what, under which conditions." Authorization in Koovira is layered gates, not a single ACL. Documented here are the gates confirmed against code + DB; the per-action CRUD matrix is seeded and marked where it still needs an authz-code pass.
The gate layers (in order)
- Authenticated? a valid
kv_auth_sessionsrow (actor_type/actor_id). Guests get public
read only. See ../30-core/auth.md.
- Actor type โ the session's
actor_type(customer / merchant / partner / padmin) +actor_role. - Module on + visible โ
kv_module_controlflags (customer_access,merchant_enrollment,
frontend_visibility). See ../00-architecture/module-registry.md.
- Enrollment โ for merchant actions, a
kv_module_registrytype +company_master+
company_business_profiles row for that module.
- Membership tier โ
kv_membershipsgates limits/features (and platform fee %). - KYC/verification โ approved
claim_kyc_requestsfor KYC-gated publish/transact. - Ownership โ the row's
buyer_id/seller_id/company_id/createdbymust match the actor
(e.g. getListing(viewerUserId, โฆ), cancelOrderByUser(userId, โฆ) all take the actor id and enforce ownership in the query).
- Staff permission โ sub-users get scoped rights via
AdminUserManagerModule/ merchant staff
screens (restaurant_staff, hotel_staff_assignments, etc.).
- Admin authz โ padmin has its own shell (
padmin/includes/authz_ext.phpโ corrected
2026-09-06, was cited as padmin/authz_ext.php; the file lives under includes/ and is require_once'd from padmin/includes/boot.php:55) + the 74-control (corrected 2026-09-06, was cited as 72; live count via SecurityControls::catalog()) SecurityControls switchboard (classs/admin/SecurityControls.php).
A request must clear every applicable layer. The Error Center's "merchant cannot publish" walkthrough is exactly this chain failing at layer 4/5/6.
Actor capability matrix (intended model โ verify each cell against the owning method)
| Capability | Guest | Customer | Merchant owner | Merchant staff | Partner (driver/rider/agent) | Admin |
|---|---|---|---|---|---|---|
| View public content | โ | โ | โ | โ | โ | โ |
| Buy / book (wallet) | โ | โ | โ | scoped | โ | โ |
| Create listing/product | โ | โ | โ | scoped | โ | โ |
| Publish (needs KYC) | โ | โ | โ (KYC) | scoped | โ | โ |
| Manage orders/fulfil | โ | own only | โ | scoped | assigned | โ |
| Financial (wallet/settlement) | โ | own wallet | company | scoped | payouts | all |
| Approve KYC / refunds / config | โ | โ | โ | โ | โ | โ |
โ/โ reflect the layered gates above. Each cell becomes authoritative only when tied to the actual permission check in the owning method (mostclasss/*Modulemethods take the actor id and enforce ownership/role inline). Do not quote a cell as fact until that method is cited โ this is the next validation pass (readAdminUserManagerModule,padmin/authz_ext.php, and the staff-permission storage).
Business rules
BR-AUTHZ-001โ every state-changing method takes the actor id and enforces ownership/role inline;
there is no trust of client-supplied owner ids (cf. CommerceX server-side pricing).
BR-AUTHZ-002โ admin (padmin) is a separate actor domain with its own session shell +SecurityControls.BR-AUTHZ-003โ one account owns one company (house rule) โ block a 2nd company at every entry point.
To validate next
Read classs/AdminUserManagerModule.php + merchant staff-permission storage + padmin/authz_ext.php to turn the matrix cells into cited, per-action rules.