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