Building Record-Level Sharing for a CRM Portal
A relationship between two records is not automatically permission to read both. Linking a task to a deal, or a contact to an organization, describes business structure. It should not silently become a broad access grant.
The portal-sharing extension treats access as an explicit decision attached to a record and a recipient context. This keeps collaboration possible without making every connected record visible.
A grant needs a complete scope
A useful conceptual grant includes the target entity type and ID, the portal, the portal user, the associated partner context, and the allowed mode.
Leaving one of those dimensions implicit creates ambiguity. A user may exist in more than one context, and the same entity type can contain both internal and deliberately shared records.
The sharing service checks the acting user's ability to read and edit the target record and their authority to manage the relevant portal. Merely knowing a record ID does not establish either permission.
Delegation should have its own boundary
An internal operator can be allowed to manage collaboration for selected portals without receiving general user administration or unrestricted grant editing.
The service resolves those managed portals from server-side configuration and role data. It then validates active portal users and their linked contacts before offering them as recipients.
That is narrower than exposing a generic grant CRUD API. It gives a business operation a specific set of checks instead of assuming that table-level access expresses the intended policy.
UI availability remains a hint. The save operation must repeat the relevant checks against the actual record and recipient, because permissions and membership can change after the dialog opens.
Inheritance must be a conscious creation decision
When creating a new task or document under an already shared parent, carrying selected recipients forward can be convenient. It should be explicit at that creation boundary.
Sharing an existing parent must not retroactively expose every old note, task, document, or sibling. Those objects may have been created under a different expectation of visibility.
The implementation has a dedicated path for obtaining current parent recipients for deliberate new-child sharing. That distinction is small in code and substantial in the access model.
Revocation needs more than a disappearing button
After a grant is removed, access should be checked through the same server-side paths that deliver lists, details, documents, and downloads. A stale browser may still hold an old reference.
Useful tests include direct record requests after revocation, cross-portal access, inactive users, and a recipient change occurring while a share dialog is open.
Notifications need the current authorization context too. A queued message must not leak content to someone whose access has been withdrawn before delivery.
The extension has local implementation and targeted checks; that is separate from acceptance of a complete production release. The technical invariant is clear throughout: an entity relationship helps organize data, while an explicit, currently valid grant authorizes access to shared data.