feat: teams within a project

Projects keep teams of members in their settings (settings.teams; people
outside the project are dropped, teams are archived, not removed; absent
when saving means unchanged). Tickets go to a team (`team`, also filtered
in the list and in MCP search_issues), and a comment mentioning
@[Frontend](team-FRONT) tells each of its members. Settings has the teams
with their members, the ticket a «Equipo» select, the list a team filter,
and «@» offers the teams after the people.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 16:20:35 +02:00
parent 4acf629106
commit 869acd3f1f
41 changed files with 895 additions and 13 deletions

View File

@@ -243,6 +243,28 @@ export class AreaOptionBodyDto {
archived = false;
}
export class TeamBodyDto {
@ApiProperty({ example: 'FRONTEND' }) @Matches(SETTING_ID) id!: string;
@ApiProperty({ example: 'Frontend', maxLength: 40 })
@IsString()
@MinLength(1)
@MaxLength(40)
name!: string;
@ApiPropertyOptional({
type: [String],
description: 'Pireon user ids of project members (others are dropped)',
})
@IsOptional()
@IsArray()
@ArrayMaxSize(200)
@IsString({ each: true })
memberIds: string[] = [];
@ApiPropertyOptional({ type: Boolean, default: false })
@IsOptional()
@IsBoolean()
archived = false;
}
export class CustomFieldDefinitionBodyDto {
@ApiProperty({ example: 'BROWSER' }) @Matches(SETTING_ID) id!: string;
@ApiProperty({ example: 'Navegador', maxLength: 40 })
@@ -319,6 +341,17 @@ export class ProjectSettingsBodyDto {
@Type(() => CustomFieldDefinitionBodyDto)
customFields?: CustomFieldDefinitionBodyDto[];
@ApiPropertyOptional({
type: [TeamBodyDto],
description: 'Absent: unchanged. Teams cannot be removed: archive them.',
})
@IsOptional()
@IsArray()
@ArrayMaxSize(30)
@ValidateNested({ each: true })
@Type(() => TeamBodyDto)
teams?: TeamBodyDto[];
@ApiPropertyOptional({
description:
'Definition of done: tickets reach a DONE status only with their checklist ticked (owners and admins may override). Absent: unchanged',
@@ -584,6 +617,12 @@ export class IssueSearchQueryDto extends PageQueryDto {
@Matches(SETTING_ID, { each: true })
area?: string[];
@ApiPropertyOptional({ type: [String], description: 'Team ids' })
@IsOptional()
@Transform(toList)
@Matches(SETTING_ID, { each: true })
team?: string[];
@ApiPropertyOptional({
enum: IssuePriority,
enumName: 'IssuePriority',
@@ -729,6 +768,16 @@ class IssueFieldsDto {
@Matches(SETTING_ID)
area?: string | null;
@ApiPropertyOptional({
type: String,
nullable: true,
example: 'FRONTEND',
description: "A team id of the project's settings",
})
@IsOptional()
@Matches(SETTING_ID)
team?: string | null;
@ApiPropertyOptional({ enum: IssuePriority, enumName: 'IssuePriority' })
@IsOptional()
@IsEnum(IssuePriority)