Manage users via Teams in GitLab and transition group sharing to Teams
## Problem [Related FigJam board](https://www.figma.com/board/qaNvvTAiN1thkz4RgeXmDp/Transition-group-sharing-to-Teams?node-id=0-1&p=f&t=NdaIstziUBSYvasQ-0) Groups in GitLab do two jobs at once: they organize projects into a namespace hierarchy, and they organize people and control their access. Organizations provide customer isolation, but the dual purpose lives *inside* each customer's boundary. Customers whose reporting lines and repository layout differ — which is most large customers — have no way to express that except by creating groups that exist only to hold people, and sharing them into the groups that hold work. - Around **15% of groups contain no projects at all** - Roughly **35% of group shares in the `gitlab-org` hierarchy** are a member-bag group shared into a group that holds work — Teams in all but name Three consequences follow, and they are what customers report: inheritance producing unexpected access levels, sharing that includes different populations depending on the target, and cognitive load from inheritance that is invisible until it surprises someone. The two original requests behind this epic are [share a group with a group](https://gitlab.com/gitlab-org/gitlab-ce/issues/33054) and [allow project settings to inherit from a group](https://gitlab.com/gitlab-org/gitlab-ee/issues/5255). ### Longer-term motivation These were the original motivations for this epic. They still describe where a Team concept should eventually pay off, but the access-control architecture below does not advance them: each needs an entity that can *aggregate* work rather than one that receives access. They are tracked in Wave 6 and in gitlab-org/gitlab#467558, not by the waves below. * **Reporting.** Few views let someone get a bird's-eye view of team activity. This is especially frustrating for managers, who lack a single place to answer "what is my team working on?" and "how can I effectively manage resourcing now and for the future?". * Tim's sheet: https://docs.google.com/spreadsheets/d/1WVp-79ojhfJtjXYnpMWN0QpXU2HRXf09-1wMOL1liwQ/ * **Communication.** Issues are terrific async communication tools, but a Team concept would be a foundation for richer async and real-time tooling. * **Portfolio management and workflows.** Triaging and assigning issues and code reviews gets easier if work can be assigned to a Team. ## Proposal A **Team** is an Organization-scoped entity that holds a roster of users and can be granted a role on a group or project. **A Team is a new kind of member**: the grant carries an existing role, and uses the same authority, the same role semantics, and the same inheritance as inviting a user. Teams grant access; they never own resources (ADR-003). A grant materializes real `Member` rows — one per roster user, on the target namespace, carrying the Team they came from (ADR-004). Project access, group abilities, seat counting, and audit events all read member rows already, so they support Teams without being taught about them. ```mermaid graph LR T["Team<br/>(Organization-scoped roster)"] T -->|"grant: a role on a namespace"| G["Group"] T -->|"grant"| PC["Project C"] G -->|"inherited, as any membership is"| PA["Project A"] G --> PB["Project B"] ``` Teams have their own tables, in the `Organizations` bounded context. A Team is not a namespace type, not a group with its features removed, and a grant is not a group share. **Source of truth:** the [Teams architecture blueprint](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/teams/) and its decision records, ADR-001 through ADR-008. Implementation detail lives in `doc/development/teams/`. ## Status A proof of concept exists behind the `teams` feature flag, per-Organization and disabled by default, with a group-share migration assistant behind `teams_share_migration`. Nothing is generally available, and the proof of concept is throwaway rather than a starting point. ## Scope In scope: the Team entity and its roster, grants on groups and projects, the Organization Teams section and the members page Teams tab, GraphQL and REST, correctness for seats, billing and audit events, and assisted conversion of clean-replacement group shares. Out of scope: - **Replacing groups, or restructuring the hierarchy.** Teams are additive, and mixed environments are a supported end state (ADR-001) - **Changing roles, permissions, or inheritance.** A Team grant behaves like any other membership. Changing how roles combine, or what an inherited assignment does at a descendant, is a separate proposal about the permissions system (ADR-004) - **Team ownership of resources.** A Team receives access and owns nothing. The Owner role at group and project level is unchanged (ADR-003) - **Horizontal aggregation.** Answering "what is my team working on" across the hierarchy needs a container entity, and a Team is not one — gitlab-org/gitlab#467558 ### What changed since the original proposal This epic originally proposed building Teams *on* groups, resolving access *through* group sharing, and having Teams own resources in place of individual Owners. The architecture review reversed all three: - Teams are their own entity, not a group with functionality removed - A grant is its own record, materialized as member rows, not a group share link - Teams never own resources, and no role is removed from groups or projects The description as it stood before this rewrite is attached for history: [epic-122-original-description.md](/uploads/72a02ae62bc02ab44dc2e4fa7d5b9f2f/epic-122-original-description.md). ## Delivery Sub-epics are grouped in waves, and each one carries its wave and its blueprint anchor. | Wave | Content | | --- | --- | | 0 | Decisions that gate more work — reconciling the blueprint with the functional roadmap | | 1 | Foundation: the Team primitive, grants, materialization into member rows, attribution and lifecycle | | 2 | Surfaces: GraphQL, REST, the Organization Teams section, the members page Teams tab, grant requests | | 3 | General-availability bars: audit events and the CE and EE seam, performance and scale verification, documentation and rollout | | 4 | Adoption: group-share migration to general availability, and teaching each group-as-principal feature about Teams | | 5 | Gated on roadmap decisions: custom roles on grants, organization-level resources | | 6 | Still to design: directory synchronization, access attribution, work aggregation | Three sub-epics are closed rather than delivered. Per-member role overrides was rejected as a concept. Seat counting and group-level enforcement became consequences of materializing member rows rather than work of their own. ## What does success look like? - An Organization owner creates a Team and manages its roster, and anyone who can manage members on a group or project can grant that Team a role there - A Team-granted user's access is indistinguishable from a direct member's everywhere access is read — enforcement, seats, billing, and audit - A customer running a member-bag group and a share can convert it to a Team without losing access or approvals - Effective access resolves under 1 second at p95 with 1,000+ Teams and 1,000+ projects, and grant and revoke return under 500 ms at p95 ## Open questions The blueprint's open questions are current. The ones that gate delivery: - **Seat capacity and roster additions.** A grant that does not fit the capacity fails whole, but somebody added to a Team that already holds grants on capacity-limited namespaces cannot be refused the same way - **Team structure.** Is a flat set with descriptive naming enough, or do customers need Teams to mirror their reporting structure? If nesting is needed, can it be organizational modelling only, with no permission inheritance between Teams? - **Enterprise identity.** How Team rosters synchronize with LDAP, SAML, and SCIM, given that directory sync is built around group membership - **Membership semantics for group-principal features**, which resolve direct members only, while a Team's roster is flat Answered since this epic was opened: team membership does not replace direct membership, since a user can hold both as separate rows; a Teams API is in scope on both protocols; and whether a Team can contain a Team is bounded by the Team-structure question above. ## What does this look like elsewhere in the market? The pattern is a roster of people that is granted access, kept separate from the container that holds work — the same split proposed here. * [Jira groups](https://confluence.atlassian.com/cloud/create-and-update-groups-744721627.html) * [Planview groups](https://success.planview.com/Planview_PPM_Pro/150_PPM_Pro_Administrator_Documentation/030_Permissions/040_Groups%2F%2FTeams/005_About_Groups) * [Azure DevOps groups](https://docs.microsoft.com/en-us/azure/devops/reference/process-templates/define-groups-teams-permissions-plug-in?view=azure-devops-2019) ## Designs Current mockups and the UI specification live in `doc/development/teams/`. - [teams_prototype.html](/uploads/51e41c1886161bcb29626a6a1a80a2f7/teams_prototype.html) — the 2018 prototype, kept for history
epic