Collaborators, Partners, and Other Collaborations
This page is the source-reviewed rulebook for collaboration behavior in the backend. It separates four concepts that are easy to mix up in product language:
- Team members are users inside the same company. They are managed by company invitations and
UserCompanyRole. See Team Member Management. - Collaborators are invited users outside the normal team roster. They are represented by
CollaborationInvitationandCollaborator. - Company partners are company-to-company relationships. They are represented by
CompanyConnectionRequestandCompanyRelationship. - Shares are object-level grants to collaborators, companies, users, or external token recipients.
Entity Map
| Area | Main records | What it means |
|---|---|---|
| Collaborator invitation | CollaborationInvitation, Collaborator | A user invites an external collaborator or partner contact by email. |
| Collaborator shares | CollaboratorPipelineShare, CollaboratorTalentPoolShare, CollaboratorTalentShare, CollaboratorJobShare | A collaborator receives access to a specific pipeline, talent pool, talent, or job. |
| Company connection | CompanyConnectionRequest, CompanyRelationship | One company asks another company to establish a formal business relationship. |
| Company shares | TalentPoolCompanyShare, PipelineCompanyShare, CvCollectionCompanyShare, SharedTalentListCompanyShare | A company shares a resource with another company. |
| External shares | TalentPoolExternalShare, TalentExternalShare, SharedTalentListExternalShare, CvCollectionExternalShare, ContactExternalShare, UserProfileExternalShare | A resource is shared by email token without creating a collaborator or company relationship. |
| Job seeker profile invitation | JobSeekerProfileInvitation | A job seeker invites an employer to view their active profile and add them to a talent pool. |
| Audit and notifications | CompanyShareAudit, CompanyNotificationPreference | Company share events are logged and notification preferences control who is emailed. |
Collaboration Layers
Use the right layer for the intended relationship:
| Scenario | Use | Do not use |
|---|---|---|
| Add a user to a company's internal staff | Team member invitation | Collaborator invitation |
| Invite an external person to collaborate on selected resources | Collaborator invitation | Company connection request |
| Establish a business relationship between two companies | Company connection request | Direct CompanyRelationship mutation |
| Share a pipeline, talent pool, CV collection, or shared list with another company | Company share | Collaborator share |
| Send a limited public link to a person by email | External share | Collaborator or company relationship |
| Let an employer view a job seeker's active profile | Job seeker profile invitation | Collaborator invitation |
The active relationship enum is RelationshipType.PARTNERSHIP. There is no PARTNER relationship enum in the current Prisma schema.
Collaborator Invitations
Collaborator invitations are handled by CollaborationResolver and the collaboration-management services.
Creation Rules
- The caller must be authenticated.
createCollaborationInvitationusesPlanLimitGuardwithmaxCollaborationInvites.- The invitation email is normalized before duplicate checks.
- A pending, unexpired invitation blocks another invitation to the same email in the same scope.
- If the invitee already has a user account, an existing
ACTIVEorPENDINGcollaboration blocks a duplicate collaboration. - The token is generated with 32 random bytes and stored as hex.
- Default expiry is 7 days; the core service allows 1 to 30 days.
- A
CollaborationInvitationand aPENDINGCollaboratorare created together. - If initial
pipelineIdsare supplied and noroleIdis supplied, the service tries to assign the RDS role namedExternal Sales. - Job seeker CV connection-style collaborator invites pass no
pipelineIds, soroleIdstays null and the UI can distinguish the intent.
The invitation link format is:
/message/accept?token=<token>&type=collaboration&invitedEmail=<email>
Status Lifecycle
| Status | Meaning |
|---|---|
PENDING | The invitation exists and the collaborator record is waiting for acceptance. |
ACCEPTED | The invitee accepted and the collaborator becomes active. |
DECLINED | The invitee declined a pending invitation. Shares are cleaned up and the collaborator row is removed. (Planned: an active collaborator who leaves will also land here, and the company's hold on the invited user's CV will be released — see CV release when a collaboration ends.) |
EXPIRED | The token expired before acceptance. |
CANCELLED | The inviter cancelled the pending invitation. Shares are cleaned up and the collaborator row is removed. (Planned: removing an active collaborator will also land here, and the company's hold on the invited user's CV will be released — see CV release when a collaboration ends.) |
Acceptance Rules
- Token acceptance and dashboard acceptance both require authentication in the current resolver.
- The authenticated user's email must match the invitation email.
- Token acceptance allows
selectedCompanyIdto be omitted, so a new invitee can accept before creating or selecting a company. - Dashboard acceptance by invitation ID currently requires
selectedCompanyId. - The service rejects expired invitations and marks them
EXPIRED. - The service rejects accepted, declined, cancelled, or expired invitations unless the request is an idempotent accept by the same already-active collaborator.
- On successful acceptance, the invitation becomes
ACCEPTEDand the collaborator becomesACTIVE. - The
invitation.acceptedevent is emitted. ContactAutoCreateListenercreates a contact in the inviter's company when a collaborator accepts, using the event company ID or the inviter's selected company.
Decline, Cancel, and Resend
| Action | Who can do it | Rules |
|---|---|---|
| Decline by token | Authenticated matching invitee | Pending only; cleans collaborator shares and removes the pending collaborator. (Planned: will also release the company's hold on the invited user's CV — see CV release when a collaboration ends.) |
| Decline by ID | Authenticated matching invitee | Pending only; accepts a reason argument, but the current schema does not persist the reason. (Planned: will also release the company's CV hold — see the admonition below.) |
| Cancel | Original inviter | Pending only; cleans collaborator shares and removes the pending collaborator. |
| Resend | Original inviter | Only declined, expired, or cancelled invitations; pending and accepted invitations cannot be resent. Resend generates a new token and 7-day expiry, and recreates the pending collaborator. Today, leave and remove leave the invitation on ACCEPTED, so resend is blocked for a job seeker who left or whom the company removed; the planned change (see below) moves those to DECLINED/CANCELLED so resend works. |
Collaborator Management
CollaboratorStatus values are:
| Status | Meaning |
|---|---|
PENDING | Created with the invitation but not accepted yet. |
ACTIVE | Accepted and allowed to participate. |
INACTIVE | Temporarily disabled by the inviter. |
LEFT | The collaborator left or was removed. |
Status and role rules:
- The inviter and collaborator can read their shared collaborator records.
listMyCollaboratorsreturns records where the current user is either inviter or collaborator.- Only the inviter can set a collaborator to
INACTIVE. - Only the inviter can reactivate an
INACTIVEcollaborator. - Only the collaborator can move themselves to
LEFT. - A
PENDINGcollaborator cannot be manually activated; acceptance must go through the invitation flow. LEFTcollaborators cannot be reactivated.- Only the inviter can update a collaborator's role.
leaveCollaborationcan only be called by the active collaborator.removeCollaboratorcan only be called by the inviter.- Leave and remove operations clean up collaborator shares and delete the collaborator row. On production today, they do nothing else: the invitation stays
ACCEPTEDand the derived Talent/CV is left in the company's pool (orphaned). The planned change (see CV release when a collaboration ends) will additionally release the company's hold on the job seeker's CV and move the invitation to a terminal status —DECLINEDfor leave,CANCELLEDfor remove — without deleting the invitation row, which lets the company re-invite via resend.
CV release when a collaboration ends
When a company adds an existing platform user as a talent, two things are created: a Talent/CV entry in the company's talent pool and a CollaborationInvitation (type JOBSEEKER) plus a Collaborator record for the person's consent. Ending the collaboration should not leave the company holding the person's CV after consent is withdrawn.
The CV-release behaviour described in this section is not live on production yet. It is implemented on backend branch fix/collab-end-releases-talent (PR #234) but has not been merged to main or dev, so it is not deployed.
As of today, ending a collaboration (leaveCollaboration / removeCollaborator) deletes only the Collaborator row and its shares. The derived Talent/CV lingers in the company's talent pool (orphaned) and the CollaborationInvitation stays ACCEPTED — so connectionStatus still reads ACTIVE and resend is blocked. The design below describes the intended behaviour once PR #234 ships.
Ending happens on decline (invitee rejects a pending invite), leave (leaveCollaboration, the job seeker withdraws), or remove (removeCollaborator, the employer removes them). Under the planned change, each of these will call CollaboratorShareCleanupService.releaseCollaborationTalentCvs, which will:
- detach the company's CV records from the talent (
CV.talentId→null) and blankTalent.activeCvId, leaving only a stub in the company's pool; - preserve the user's own CV rows — a CV belongs to the user via
CV.userIdand is never deleted.
The talent stub will then resolve a connectionStatus of DECLINED (both DECLINED and CANCELLED invitations map to DECLINED via mapConnectionStatus), so the company will see a "declined / removed collaboration" marker instead of a live CV, and can re-invite the person via resend. leave will move the invitation to DECLINED and remove to CANCELLED.
Today, decline / leave / remove only delete the Collaborator row and its shares — the talent's CV stays fully visible in the company's pool, and leave/remove leave the invitation on ACCEPTED (so connectionStatus still reads ACTIVE and resend is blocked). Any earlier note that leave/remove "delete the linked invitation row" was never accurate. Once PR #234 ships, the behaviour will release the CV, keep a declined stub, and re-enable re-invitation.
Collaborator Resource Shares
Collaborator shares are not company-wide. They grant a specific collaborator access to a specific resource.
| Resource | Model | Permission enum | Main creation checks |
|---|---|---|---|
| Pipeline | CollaboratorPipelineShare | AccessPermission (VIEW, EDIT, MANAGE) | Caller must be in the collaboration, collaborator must be ACTIVE, and caller must own the pipeline or belong to the pipeline company. |
| Talent pool | CollaboratorTalentPoolShare | AccessPermission (VIEW, EDIT, MANAGE) | Caller must be in the collaboration, collaborator must be ACTIVE, and caller must have pool owner or company access. |
| Talent | CollaboratorTalentShare | PermissionLevel (READ_ONLY, EDIT, ADMIN) | Resolver resolves the sharing relationship; update and unshare require collaboration permission on the source collaborator. |
| Job | CollaboratorJobShare | AccessPermission (VIEW, EDIT, MANAGE) | Caller must be the job creator or belong to the job company. Duplicate collaborator/job pairs are blocked. |
Additional talent-share behavior:
READ_ONLYtalent shares cannot be extracted into another talent pool.EDITandADMINtalent shares can be extracted into a target talent pool when the caller has permission.- Extraction creates a new
Talentwith sourceSHARED, links the active CV, and preserves share notes.
CollaboratorJobShareService does not currently enforce the same collaborator-participant and ACTIVE status checks used by pipeline and talent-pool collaborator shares. It checks whether the caller can share the job, then creates, updates, or removes the collaborator job share.
Company Connection Requests
Company connection requests are the partner relationship workflow. They are handled by CompanyConnectionRequestResolver and company-collaboration/connection-requests.
Creation Rules
- The caller must be authenticated.
createCompanyConnectionRequestusesPlanLimitGuardwithmaxConnectionRequestsPerMonth.- The caller must belong to the source company.
- The caller must have an admin role in the source company. The service treats
Company AdminandSuper Adminas admin roles. - The request targets a company email. If a company with that email exists,
toCompanyIdis linked. - Duplicate pending requests are blocked by
[fromCompanyId, toCompanyEmail, relationshipType]. - Existing relationships are checked in both directions before a new request is created.
- Connection tokens expire after 14 days.
Relationship Types
Current RelationshipType values:
PARTNERSHIPACQUISITIONSTRATEGIC_ALLIANCEBROKERAGECLIENTRECRUITER
Acceptance, Decline, and Cancel
| Action | Who can do it | Rules |
|---|---|---|
| Accept by token | Target company admin | Authenticated; validates target company membership and admin role. If the target company was not linked, the approver must administer a company whose email matches the request email. |
| Accept by ID | Target company admin | Same approval rules as token acceptance; can include responseMessage. |
| Decline by token | Target company member | Authenticated; membership is required, but the decline path is not admin-only. |
| Decline by ID | Target company member | Same as token decline; can include responseMessage. |
| Cancel | Requester or source company admin | Pending only. |
When accepted, the service creates two CompanyRelationship rows:
Company A -> Company B
Company B -> Company A
This makes the relationship visible from both companies.
Direct CompanyRelationship CRUD mutations still exist and are protected only by authentication in the current resolver, with a separate super-admin query for paginated admin listing. Product and backend flows should prefer connection requests because they enforce admin approval and create bidirectional relationship rows.
Company Resource Shares
Company shares grant another company access to a resource. The shared company receives access through one of the company share tables:
| Resource | Model | Permission enum |
|---|---|---|
| Talent pool | TalentPoolCompanyShare | AccessPermission |
| Pipeline | PipelineCompanyShare | AccessPermission |
| CV collection | CvCollectionCompanyShare | AccessPermission |
| Shared talent list | SharedTalentListCompanyShare | AccessPermission |
Company share service rules:
- Creating a company share requires an admin role in the source company.
- Updating or deleting a company share requires an admin role in the source company or the original share creator.
- Viewing shares is allowed for company members.
- The shared-company relationship check currently logs a warning when no relationship exists; it does not block share creation.
- Share creation, permission changes, and revocation are logged through
CompanyShareAuditService. - Share notifications are routed through
CompanyCollaborationNotificationService.
Audit actions use ShareActionType:
CREATEDUPDATEDDELETEDACCESSEDPERMISSION_CHANGEDREVOKED
External Token Shares
External shares are email-token links. They do not create a collaborator, company connection, or company relationship.
Common external-share fields:
emailtokenexpiresAtaccessCountisActive
Use external shares when the recipient should only receive a limited link. Use collaborator or company shares when the recipient should have an ongoing authenticated relationship in the platform.
Job Seeker Profile Invitations
Job seeker profile invitations are a separate collaboration path handled by JobSeekerInvitationResolver.
Send Rules
- The sender must be authenticated.
- The sender must be in
JOB_SEEKERview mode. - The sender must have an active CV.
- A duplicate pending invitation to the same employer email is blocked.
- The token is generated with 32 random bytes and stored as hex.
- The invitation expires after 30 days.
- The employer receives a link at:
/invitations/job-seeker/accept?token=<token>
Accept and Decline Rules
- Accepting requires authentication.
- The accepting employer must belong to the selected company.
- If the job seeker already has a talent record in one of that company's talent pools, it is reused and set to
LIVE_ACTIVE. - Otherwise the service finds or creates the company's
Defaulttalent pool. - A new talent record is created with
source: INVITED, the job seeker's active CV, andcvMode: LIVE_ACTIVE. (A team member uploading their own CV instead produces a talent withsource: INVITED_MEMBER— see Talents.) - The invitation stores
acceptedBy,acceptedCompanyId, andtalentId. - Declining by token is public but requires the provided
employerEmailto exactly match the invitation email. - The job seeker can cancel only pending invitations.
- The job seeker can delete only non-pending invitation history rows. Accepted invitation deletion preserves the underlying talent record.
- Resend is allowed for declined, expired, or cancelled invitations. Pending and accepted invitations cannot be resent.
Notification Preferences
CompanyNotificationPreference controls company collaboration email behavior:
| Field | Default |
|---|---|
notifyOnConnectionRequest | true |
notifyOnConnectionAccepted | true |
notifyOnConnectionDeclined | true |
notifyOnResourceShared | true |
notifyOnResourceUnshared | true |
notifyOnPermissionChanged | true |
enableDailyDigest | false |
enableWeeklyDigest | true |
digestRecipients | [] |
notificationEmails | [] |
If no explicit notification emails are configured, company admins are used as recipients.
Plan Limits
Collaboration-related plan limit keys in the backend are:
| Limit key | Used by |
|---|---|
maxCollaborationInvites | Collaborator invitation creation |
maxConnectionRequestsPerMonth | Company connection request creation |
maxSharedTalentLists | Shared talent list creation |
maxUsersPerCompany | Team member invitation creation |
Resource creation has its own plan limits outside this page, such as talent pools, pipelines, jobs, CV collections, contacts, meetings, and interviews.
Security Notes
CollaborationResolverandCompanyConnectionRequestResolverare guarded byJwtAuthGuard.- Job seeker profile invitation accept requires authentication; get-by-token and decline-by-token are public.
- Collaborator and company share permissions are resource-specific and should not be treated as interchangeable with company roles.
AccessPermissionis used by resource shares that supportVIEW,EDIT, andMANAGE.PermissionLevelis used by collaborator talent shares and supportsREAD_ONLY,EDIT, andADMIN.- Company connection acceptance is admin-only; decline is target-company-member-only in the current service.
- Company share relationship checks are advisory in code today, not a hard authorization gate.