Skip to main content

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 CollaborationInvitation and Collaborator.
  • Company partners are company-to-company relationships. They are represented by CompanyConnectionRequest and CompanyRelationship.
  • Shares are object-level grants to collaborators, companies, users, or external token recipients.

Entity Map

AreaMain recordsWhat it means
Collaborator invitationCollaborationInvitation, CollaboratorA user invites an external collaborator or partner contact by email.
Collaborator sharesCollaboratorPipelineShare, CollaboratorTalentPoolShare, CollaboratorTalentShare, CollaboratorJobShareA collaborator receives access to a specific pipeline, talent pool, talent, or job.
Company connectionCompanyConnectionRequest, CompanyRelationshipOne company asks another company to establish a formal business relationship.
Company sharesTalentPoolCompanyShare, PipelineCompanyShare, CvCollectionCompanyShare, SharedTalentListCompanyShareA company shares a resource with another company.
External sharesTalentPoolExternalShare, TalentExternalShare, SharedTalentListExternalShare, CvCollectionExternalShare, ContactExternalShare, UserProfileExternalShareA resource is shared by email token without creating a collaborator or company relationship.
Job seeker profile invitationJobSeekerProfileInvitationA job seeker invites an employer to view their active profile and add them to a talent pool.
Audit and notificationsCompanyShareAudit, CompanyNotificationPreferenceCompany share events are logged and notification preferences control who is emailed.

Collaboration Layers

Use the right layer for the intended relationship:

ScenarioUseDo not use
Add a user to a company's internal staffTeam member invitationCollaborator invitation
Invite an external person to collaborate on selected resourcesCollaborator invitationCompany connection request
Establish a business relationship between two companiesCompany connection requestDirect CompanyRelationship mutation
Share a pipeline, talent pool, CV collection, or shared list with another companyCompany shareCollaborator share
Send a limited public link to a person by emailExternal shareCollaborator or company relationship
Let an employer view a job seeker's active profileJob seeker profile invitationCollaborator invitation
note

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.
  • createCollaborationInvitation uses PlanLimitGuard with maxCollaborationInvites.
  • 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 ACTIVE or PENDING collaboration 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 CollaborationInvitation and a PENDING Collaborator are created together.
  • If initial pipelineIds are supplied and no roleId is supplied, the service tries to assign the RDS role named External Sales.
  • Job seeker CV connection-style collaborator invites pass no pipelineIds, so roleId stays null and the UI can distinguish the intent.

The invitation link format is:

/message/accept?token=<token>&type=collaboration&invitedEmail=<email>

Status Lifecycle

StatusMeaning
PENDINGThe invitation exists and the collaborator record is waiting for acceptance.
ACCEPTEDThe invitee accepted and the collaborator becomes active.
DECLINEDThe 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.)
EXPIREDThe token expired before acceptance.
CANCELLEDThe 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 selectedCompanyId to 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 ACCEPTED and the collaborator becomes ACTIVE.
  • The invitation.accepted event is emitted.
  • ContactAutoCreateListener creates 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

ActionWho can do itRules
Decline by tokenAuthenticated matching inviteePending 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 IDAuthenticated matching inviteePending 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.)
CancelOriginal inviterPending only; cleans collaborator shares and removes the pending collaborator.
ResendOriginal inviterOnly 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:

StatusMeaning
PENDINGCreated with the invitation but not accepted yet.
ACTIVEAccepted and allowed to participate.
INACTIVETemporarily disabled by the inviter.
LEFTThe collaborator left or was removed.

Status and role rules:

  • The inviter and collaborator can read their shared collaborator records.
  • listMyCollaborators returns 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 INACTIVE collaborator.
  • Only the collaborator can move themselves to LEFT.
  • A PENDING collaborator cannot be manually activated; acceptance must go through the invitation flow.
  • LEFT collaborators cannot be reactivated.
  • Only the inviter can update a collaborator's role.
  • leaveCollaboration can only be called by the active collaborator.
  • removeCollaborator can 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 ACCEPTED and 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 — DECLINED for leave, CANCELLED for 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.

Planned — not yet released (backend PR #234)

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.talentIdnull) and blank Talent.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.userId and 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.

Behaviour change (planned)

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.

ResourceModelPermission enumMain creation checks
PipelineCollaboratorPipelineShareAccessPermission (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 poolCollaboratorTalentPoolShareAccessPermission (VIEW, EDIT, MANAGE)Caller must be in the collaboration, collaborator must be ACTIVE, and caller must have pool owner or company access.
TalentCollaboratorTalentSharePermissionLevel (READ_ONLY, EDIT, ADMIN)Resolver resolves the sharing relationship; update and unshare require collaboration permission on the source collaborator.
JobCollaboratorJobShareAccessPermission (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_ONLY talent shares cannot be extracted into another talent pool.
  • EDIT and ADMIN talent shares can be extracted into a target talent pool when the caller has permission.
  • Extraction creates a new Talent with source SHARED, links the active CV, and preserves share notes.
Current implementation note

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.
  • createCompanyConnectionRequest uses PlanLimitGuard with maxConnectionRequestsPerMonth.
  • The caller must belong to the source company.
  • The caller must have an admin role in the source company. The service treats Company Admin and Super Admin as admin roles.
  • The request targets a company email. If a company with that email exists, toCompanyId is 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:

  • PARTNERSHIP
  • ACQUISITION
  • STRATEGIC_ALLIANCE
  • BROKERAGE
  • CLIENT
  • RECRUITER

Acceptance, Decline, and Cancel

ActionWho can do itRules
Accept by tokenTarget company adminAuthenticated; 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 IDTarget company adminSame approval rules as token acceptance; can include responseMessage.
Decline by tokenTarget company memberAuthenticated; membership is required, but the decline path is not admin-only.
Decline by IDTarget company memberSame as token decline; can include responseMessage.
CancelRequester or source company adminPending 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.

Prefer the request workflow

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:

ResourceModelPermission enum
Talent poolTalentPoolCompanyShareAccessPermission
PipelinePipelineCompanyShareAccessPermission
CV collectionCvCollectionCompanyShareAccessPermission
Shared talent listSharedTalentListCompanyShareAccessPermission

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:

  • CREATED
  • UPDATED
  • DELETED
  • ACCESSED
  • PERMISSION_CHANGED
  • REVOKED

External Token Shares

External shares are email-token links. They do not create a collaborator, company connection, or company relationship.

Common external-share fields:

  • email
  • token
  • expiresAt
  • accessCount
  • isActive

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_SEEKER view 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 Default talent pool.
  • A new talent record is created with source: INVITED, the job seeker's active CV, and cvMode: LIVE_ACTIVE. (A team member uploading their own CV instead produces a talent with source: INVITED_MEMBER — see Talents.)
  • The invitation stores acceptedBy, acceptedCompanyId, and talentId.
  • Declining by token is public but requires the provided employerEmail to 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:

FieldDefault
notifyOnConnectionRequesttrue
notifyOnConnectionAcceptedtrue
notifyOnConnectionDeclinedtrue
notifyOnResourceSharedtrue
notifyOnResourceUnsharedtrue
notifyOnPermissionChangedtrue
enableDailyDigestfalse
enableWeeklyDigesttrue
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 keyUsed by
maxCollaborationInvitesCollaborator invitation creation
maxConnectionRequestsPerMonthCompany connection request creation
maxSharedTalentListsShared talent list creation
maxUsersPerCompanyTeam 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

  • CollaborationResolver and CompanyConnectionRequestResolver are guarded by JwtAuthGuard.
  • 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.
  • AccessPermission is used by resource shares that support VIEW, EDIT, and MANAGE.
  • PermissionLevel is used by collaborator talent shares and supports READ_ONLY, EDIT, and ADMIN.
  • 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.