.agents/features/ee-projects.md
The EE Projects module adds team collaboration, role-based access control (RBAC), git-based environment sync, and per-project piece filtering on top of the base project entity. It introduces project membership (invitations, roles), custom project roles with fine-grained permissions, project releases for deploying flows between environments, and a git sync mechanism for version-controlling flow definitions in an external repository.
packages/server/api/src/app/ee/projects/ — platform project service, RBAC enforcementpackages/server/api/src/app/ee/project-members/ — member CRUD, role lookuppackages/server/api/src/app/ee/project-role/ — default and custom role managementpackages/server/api/src/app/ee/project-release/ — release creation, diff, applypackages/server/api/src/app/ee/git-sync/ — SSH repo push/pullpackages/core/shared/src/lib/ee/project-members/project-member.ts — ProjectMember typepackages/core/shared/src/lib/ee/project-members/project-member-request.ts — list/update request DTOspackages/core/shared/src/lib/automation/project-release/project-release.ts — ProjectRelease typepackages/core/shared/src/lib/automation/project-release/project-release.request.ts — release request DTOspackages/core/shared/src/lib/automation/project-release/project-state.ts — ProjectSyncPlanpackages/web/src/features/members/api/project-members-api.ts — projectMembersApipackages/web/src/features/members/hooks/project-members-hooks.ts — projectMembersHookspackages/web/src/features/members/hooks/user-invitations-hooks.ts — userInvitationsHookspackages/web/src/features/members/components/ — InviteUserDialog, EditRoleDialog, ProjectMemberCard, InvitationCardpackages/web/src/features/project-releases/api/project-release-api.ts — projectReleaseApipackages/web/src/features/project-releases/api/git-sync-api.ts — gitSyncApipackages/web/src/features/project-releases/hooks/project-release-hooks.ts — projectReleaseQueriespackages/web/src/features/project-releases/hooks/git-sync-hooks.ts — gitSyncHookspackages/web/src/app/components/project-settings/members/index.tsx — MembersSettings componentpackages/web/src/app/routes/project-release/index.tsx — ProjectReleasesPageprojectRolesEnabled and environmentsEnabled plan flags.customRolesEnabled. Git sync and releases behind environmentsEnabled.workerGroupId assignment / per-project worker routing: Enterprise feature gated behind platform_plan.isolatedWorkersEnabled. Both setting a project's workerGroupId (via the project update endpoint) and listing project worker groups (GET /v1/projects/worker-groups) require the flag.Canonical term definitions live in the bounded-context glossaries — see CONTEXT-MAP.md.
READ_FLOW, WRITE_CONNECTION).rbacService.assertPrincipalAccessToProject().1cpu_machine). When set (and isolatedWorkersEnabled is on for the platform), the project's EXECUTE_FLOW/EXECUTE_WEBHOOK jobs are routed to project-<label>-jobs; other job types are unaffected. The matching worker advertises AP_WORKER_GROUP_ID=<label> with AP_PROJECT_WORKER=true (scope comes from the flag, not a prefix). Set via POST /v1/projects/:id. See the Workers feature doc for the unified worker-group mechanics.Entity: id, projectId, userId, projectRoleId, platformId. Unique on (projectId, userId, platformId).
Service methods:
upsert({ userId, projectId, projectRoleName }) — create/update member with role lookuplist({ platformId, projectId?, projectRoleId? }) — paginated with user detailsgetRole({ userId, projectId }) — returns role (ADMIN if owner/platform admin)update({ id, projectId, platformId, role }) — change member's roledelete(projectId, memberId) — remove from projectgetIdsOfProjects({ userId, platformId }) — all project IDs user belongs toFrontend: projectMembersApi.list/update/delete backed by projectMembersHooks.useProjectMembers(). MembersSettings component shows combined table of active members, platform admins/operators, and pending invitations.
Entity: id, name, permissions[] (string array), platformId (nullable), type (DEFAULT/CUSTOM).
Default roles (type=DEFAULT, platformId=null):
Custom roles: Platform-scoped, created by platform admins with any combination of 26 permissions.
rbacService.assertPrincipalAccessToProject() routes by principal type:
principal.projectId === requestedProjectIdproject.platformId === principal.platform.idEntity: id, projectId, name, description, importedBy (FK user), fileId (FK), type (GIT_BRANCH/MANUAL/ROLLBACK).
Release workflow:
releasePlan() — compute diff (what flows/tables/connections would change)create() — apply diffs, serialize project state to File, record releaseFrontend: projectReleaseApi.diff() previews changes before commit. ApplyButton triggers create. ProjectReleasesPage lists history with rollback action per row.
Git sync (git-sync/):
Entity: id, projectId (one-to-one), name, pieces[] (string array), piecesFilterType (NONE/ALLOWED), locked (boolean).
NONE: All pieces availableALLOWED: Only pieces in pieces[] array visibleFilteredPieceBehavior.ALLOWED/BLOCKED) applied first, then project-levelplatformProjectService.getForPlatform() — lists projects with access control:
Endpoints (platform-project-controller.ts):
POST /v1/projects/:id — update; body UpdateProjectPlatformRequest accepts workerGroupId (validated against ^[a-z0-9_-]+$, applied in platformProjectService.update() only when platform_plan.isolatedWorkersEnabled is on).GET /v1/projects/worker-groups — platform-admin only; returns { groups: [{ label, slots }], sharedSlots } from online project-scope workers (those started with AP_PROJECT_WORKER=true) via machineService.listProjectWorkerGroups() for the assignment UI; returns 402 FEATURE_DISABLED when isolatedWorkersEnabled is off.