feat(integration-ever-works): people matching and agent provisioning (G-P1-6)
Merged
EV
10d ago+1110+1110+0123456789012345678901234567890123456789-4-4-0123456789
What
G-P1-6 of the Gauzy ↔ Ever Works integration: people and agents, inside the flag-gated plugin @gauzy/plugin-integration-ever-works. Nothing loads unless EVER_WORKS_ENABLED=true. This PR adds no migration and no core change.
People (members ↔ employees, MEMBER links)
GET /mappings/:integrationTenantId/peoplereturns the Ever Works members of the mapped organization (contractGET /members, all pages, organization-scoped withX-Scope-Slug). Each member comes with its Gauzy pairing and an optional suggestion: an exact, case-insensitive match of a verified Ever Works email with a Gauzy person. The response also lists the Gauzy people who have no pairing yet.PUT /mappings/:integrationTenantId/peopleconfirmslinks, removesunlinks, oracceptSuggestions. Each member and each employee is paired at most once, and a new pairing replaces the old one on either side. The change is written in one transaction. Nothing is linked silently, and unlinking removes only the pairing.- Agents are never offered as people.
- Ever ID matching is not possible yet: Gauzy stores no Ever ID subjects. The member's
everIdSubjectsare kept on the link for when it can.
Agents (EW → Gauzy, one way, AGENT links)
- Each Ever Works agent of a mapped organization becomes a Gauzy employee of kind
agentthrough the platform's agent-provisioning path from #10766 (EmployeeService.createAgentEmployee: no password, no welcome email, no invite). Itsemployee_agent_profilehassource='ever_works'andmanagedExternally=true, plus slug, title, capabilities, status, scope, reports-to, model, avatar and web URL (HTTPS only). - The address is
agent-<id>@agents.invalid..invalid(RFC 2606) can never receive mail.EVER_WORKS_AGENT_EMAIL_DOMAINmay override the domain, but it must also end in.invalid. - The inbound handler covers
agent.created/updated/status_changed/archived/deleted/visibility_changed:- An event at or below the linked version is skipped.
- An archived or deleted agent is archived (
isActive=false,isArchived=true), never deleted. - An agent made private is unlinked and stops syncing.
- With the mapping's
agentsdirectionoff, nothing is written.
- Ever Works owns its agents: the profile is rewritten from Ever Works on each change, and Gauzy edits are never pushed.
GET /mappings/:integrationTenantId/agentslists the linked agent employees.POST …/agents/importqueues every agent of the organization as an initial event. Managers come first, by reporting depth. The sync loop applies them under its lease, with the version check, so an import never overwrites a newer change. The response is{ queued, duplicates }.
The endpoints and events used are all in contract v1 (GET /members, GET /agents, the agent.* events). No endpoint was invented.
Not in this PR
- Invite actions ("invite to Ever Works" / "invite to Gauzy"). Ever Works invitations need
members:write, which is P2 in the contract. The Gauzy invite command/service is not exported from@gauzy/coreeither. - The UI People tab is part of the connect wizard (G-P1-11).
Verification
Local, EVERDESK3, Node 26.12.0. Per the owner's merge-first directive of 2026-10-16, the full suites run once all integration PRs are in.
- Strict typecheck of the plugin (
strict,noImplicitOverride,noPropertyAccessFromIndexSignature): no errors. ever-works-agents.service.spec.tspasses 11/11 after the Greptile fixes in ed6db7ea75. These add: the mapping switch, cleared fields following Ever Works, import through the sync loop in manager-first order, and reporting depths with a cycle.- Originally the spec passed 7/7. It covers the mail-proof address and its override rule, provisioning through the platform path with the managed profile and the link, archive instead of delete, version skip, private → unlink, direction off, and a refusal when the provisioning path is missing (nothing half-written).
- cspell is clean on the changed files.
🤖 Generated with Claude Code