Permissions & Visibility
Business view
Stock counts introduce four new permissions, mirroring the pattern used everywhere else in Dentolize: View, Add, Edit, Delete. What's new is a fifth, narrower permission — View Created Stock Count — that lets a clinic hand counting duty to staff without giving them visibility into every count anyone has ever opened.
A clinic can, for example, give a receptionist or assistant Edit Stock Count + View Created Stock Count (but not the plain View Stock Count): that person can open and work counts, but when they look at the stock counts list, they only see the ones they created — not the manager's counts, not other staff's counts. It's the same pattern used elsewhere for personal-scope visibility (e.g. "view created expenses").
Out of the box, only the seeded Inventory Admin permission group gets stock count access (all four base permissions). Everyone else needs it granted explicitly, same as any other module.
Technical view
The permissions
Defined in packages/server/src/enums.graphql:540 and around it: VIEW_STOCK_COUNT, VIEW_CREATED_STOCK_COUNT, ADD_STOCK_COUNT, EDIT_STOCK_COUNT, DELETE_STOCK_COUNT. They're surfaced in the permission-group editor UI via packages/clinic-web/src/components/dashboard/settings/Groups/tableData.js:443.
Seeded default: only the Inventory Admin group gets VIEW_STOCK_COUNT / ADD_STOCK_COUNT / EDIT_STOCK_COUNT / DELETE_STOCK_COUNT (packages/server/src/seedDatabase/permissionGroups.js:950-953). VIEW_CREATED_STOCK_COUNT isn't assigned to any seeded group — it exists for clinics to build their own narrower "counter" role.
Query-time gating
Every stock count query (stockCounts, totalStockCounts, stockCountDetails, stockCountItems, totalStockCountItems, stockCountItemBySku) is permitted by or(hasPermission('VIEW_STOCK_COUNT'), hasPermission('VIEW_CREATED_STOCK_COUNT')) (packages/server/src/permissions/permissions.js:2445-2470) — either permission is enough to query, but which permission you hold changes what you see, enforced in two separate places:
- List filtering —
getWhereForStockCounts(packages/server/src/utils/helpers.js:3566-3577) addscreatedById: request.session.user.idto thewhereclause'sANDarray whenever the caller hasVIEW_CREATED_STOCK_COUNT, alongside whatever other filters (date range, storage, branch, search) are active. This scopes thestockCountslist and its count query. - Direct-access checks —
isSameCompanyAsStockCount(packages/server/src/permissions/rules.js:3015-3036), the rule guarding every mutation and detail query that takes astockCountid argument, does the same scoping again independently: if the caller hasVIEW_CREATED_STOCK_COUNT, the rule additionally requiresitem.createdById === request.session.user.id. This matters because list filtering alone wouldn't stop someone from guessing or reusing another count's id directly againststockCountDetailsor a mutation — the rule closes that gap at the object level, not just the list level.
Mutation permissions
packages/server/src/permissions/permissions.js:4068-4072:
addNewStockCount: isAuthenticated + hasGeneratedID + ADD_STOCK_COUNT
editStockCountItems: isAuthenticated + isSameCompanyAsStockCount + EDIT_STOCK_COUNT
confirmStockCount: isAuthenticated + isSameCompanyAsStockCount + EDIT_STOCK_COUNT
cancelStockCount: isAuthenticated + isSameCompanyAsStockCount + EDIT_STOCK_COUNT
deleteStockCount: isAuthenticated + isSameCompanyAsStockCount + DELETE_STOCK_COUNT
Confirming and cancelling both only require EDIT_STOCK_COUNT — there's no separate "confirm" permission. The one place a second, unrelated permission gets checked is inside confirmStockCount itself: requesting updateStock: true additionally requires DO_ALL or ADD_INVENTORY_ADJUSTMENT (checked in the resolver, not the permission shield — see Closing a Count). That's a deliberate split: the ability to count and the ability to let a count change live stock are different privileges, and a clinic can grant one without the other.
Frontend mirroring
Both clients derive simple booleans from the raw permission list for the UI to gate buttons on — stockCounts, addStockCount, editStockCount, deleteStockCount — in packages/clinic-mobile/src/shared/utils/getUserPermissions.js:43-46 (shared by both web and mobile, since clinic-web imports mobile's store code). These are UI conveniences only; the server-side rules above are the actual enforcement.
What's returned either way
Regardless of which view-permission a caller holds, the shape of the data is the same — stockCountSelect / stockCountItemSelect (packages/server/src/resolvers/queries/actions/stockCounts/stockCountsSelect.js) don't vary by permission. There's no field-level redaction; the distinction is entirely about which rows a caller can reach, not which columns.