Skip to main content

Label Model

The Label model represents organizational labels synced from Plane.so, used for categorizing and filtering work items and flows.

Schema Definition

model Label {
id String @id @default(uuid())
planeId String @unique
name String
color String
description String?
projectId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)

@@map("labels")
}

Field Descriptions

Primary Identification

FieldTypeDescription
idStringUUID primary key
planeIdStringUnique Plane.so label identifier

Label Properties

FieldTypeDescription
nameStringLabel name (e.g., "bug", "feature", "urgent")
colorStringHex color code (e.g., "#FF6B6B", "#4ECDC4")
descriptionString?Optional description of the label's purpose

Relations

FieldTypeDescription
projectIdStringReference to Project.id

Metadata

FieldTypeDescription
createdAtDateTimeLabel sync timestamp
updatedAtDateTimeLast update timestamp

Relationships

Belongs To

  • project: Project - The project this label belongs to (Cascade delete)

Usage Examples

Create Synced Label

const label = await prisma.label.create({
data: {
planeId: "plane-label-123",
name: "bug",
color: "#FF6B6B",
description: "Bug reports and issues",
projectId: "project-456"
}
});

Update Label Properties

await prisma.label.update({
where: { planeId: "plane-label-123" },
data: {
color: "#E74C3C",
description: "Critical bugs and issues"
}
});

Get Labels by Project

const projectLabels = await prisma.label.findMany({
where: { projectId: "project-456" },
orderBy: { name: "asc" }
});

Find Labels by Name

const bugLabels = await prisma.label.findMany({
where: {
name: "bug",
project: {
integration: {
isActive: true
}
}
}
});

Color System

Predefined Color Palette

const LABEL_COLORS = [
'#FF6B6B', // Red - urgent, critical
'#FFA726', // Orange - high priority
'#FFEB3B', // Yellow - medium priority
'#4CAF50', // Green - completed, success
'#2196F3', // Blue - info, default
'#9C27B0', // Purple - feature, enhancement
'#E91E63', // Pink - bug, issue
'#009688', // Teal - testing, qa
'#795548', // Brown - documentation
'#607D8B' // Grey - maintenance
];

Color Assignment Logic

function assignLabelColor(labelName: string): string {
const nameHash = labelName.split('').reduce((hash, char) => {
return ((hash << 5) - hash) + char.charCodeAt(0);
}, 0);

return LABEL_COLORS[Math.abs(nameHash) % LABEL_COLORS.length];
}

Sync Operations

Bulk Label Sync

async function syncProjectLabels(projectId: string, planeLabels: any[]) {
const operations = planeLabels.map(label =>
prisma.label.upsert({
where: { planeId: label.id },
update: {
name: label.name,
color: label.color,
description: label.description,
updatedAt: new Date()
},
create: {
planeId: label.id,
name: label.name,
color: label.color || assignLabelColor(label.name),
description: label.description,
projectId: projectId
}
})
);

await prisma.$transaction(operations);
}

Label Cleanup

async function cleanupOrphanedLabels() {
// Remove labels that no longer exist in Plane
const orphanedLabels = await prisma.label.findMany({
where: {
// Logic to identify orphaned labels
}
});

await prisma.label.deleteMany({
where: {
id: { in: orphanedLabels.map(l => l.id) }
}
});
}

Label Usage Analytics

Most Used Labels

async function getPopularLabels(projectId: string) {
// This would require joining with work items
// Implementation depends on how labels are used in work items
const labelUsage = await prisma.workItem.groupBy({
by: ['labels'],
where: { projectId },
_count: true
});

return labelUsage.sort((a, b) => b._count - a._count);
}

Label Distribution

async function getLabelDistribution(projectId: string) {
const workItems = await prisma.workItem.findMany({
where: { projectId },
select: { labels: true }
});

const labelCounts: Record<string, number> = {};

workItems.forEach(item => {
item.labels.forEach(label => {
labelCounts[label] = (labelCounts[label] || 0) + 1;
});
});

return Object.entries(labelCounts)
.map(([label, count]) => ({ label, count }))
.sort((a, b) => b.count - a.count);
}

Performance Considerations

Indexing

  • Unique index on planeId for sync operations
  • Index on projectId for project filtering
  • Index on name for label name searches
  • Index on updatedAt for sync status

Query Optimization

  • Use select to fetch only needed fields
  • Cache frequently used labels
  • Use batch operations for bulk syncs
  • Implement pagination for large label lists

Best Practices

Naming Conventions

  • Use lowercase with hyphens: bug-fix, feature-request
  • Keep names descriptive but concise
  • Use consistent prefixes: priority-*, type-*, status-*

Color Consistency

  • Use colors consistently across projects
  • Choose accessible color combinations
  • Consider colorblind users when selecting colors

Maintenance

  • Regular cleanup of unused labels
  • Update label descriptions as usage evolves
  • Audit label usage periodically
  • Merge similar labels when appropriate

Integration

  • Sync labels regularly from Plane
  • Handle label conflicts gracefully
  • Preserve local label customizations
  • Implement label mapping for migrations