Overview
The areas table stores product areas or categories used to organize feature requests. Each area represents a logical grouping of features within the product.
Fields
Primary key. Fixed-length identifier for the area (typically a UUID or custom ID).
Display name of the area. Must be unique.
URL-friendly identifier for the area. Must be unique.
Detailed description of what this area encompasses.
Optional Slack or chat channel ID for notifications related to this area.
Relationships
Areas are referenced by requests through the requests.areaIds array field. This creates a many-to-many relationship where:
- A single request can belong to multiple areas
- A single area can be associated with multiple requests
The relationship is maintained through an array column rather than a junction table. Use array containment queries to find requests by area.
Indexes
Unique constraint on the name field.
Unique constraint on the slug field.
Example queries
Query all areas
import { db } from './db';
import { areas } from './schema';
const allAreas = await db.query.areas.findMany({
orderBy: (areas, { asc }) => [asc(areas.name)],
});
Get area by slug
import { db } from './db';
import { areas } from './schema';
import { eq } from 'drizzle-orm';
const area = await db.query.areas.findFirst({
where: eq(areas.slug, 'authentication'),
});
Find requests in a specific area
import { db } from './db';
import { requests, areas } from './schema';
import { eq, arrayContains } from 'drizzle-orm';
// First get the area
const area = await db.query.areas.findFirst({
where: eq(areas.slug, 'authentication'),
});
// Then find requests containing this area ID
if (area) {
const requestsInArea = await db.query.requests.findMany({
where: arrayContains(requests.areaIds, [area.id]),
with: {
user: true,
},
});
}
Create a new area
import { db } from './db';
import { areas } from './schema';
import { randomUUID } from 'crypto';
const newArea = await db.insert(areas).values({
id: randomUUID(),
name: 'Authentication',
slug: 'authentication',
description: 'User authentication, SSO, and identity management features',
firehoseChannel: 'C01234567',
}).returning();
Update area details
import { db } from './db';
import { areas } from './schema';
import { eq } from 'drizzle-orm';
const updated = await db
.update(areas)
.set({
description: 'Updated description for the area',
firehoseChannel: 'C98765432',
})
.where(eq(areas.slug, 'authentication'))
.returning();
Get area usage statistics
import { db } from './db';
import { areas, requests } from './schema';
import { sql, arrayContains } from 'drizzle-orm';
// Count how many requests reference each area
const areaStats = await Promise.all(
(await db.select().from(areas)).map(async (area) => {
const count = await db
.select({ count: sql<number>`count(*)` })
.from(requests)
.where(arrayContains(requests.areaIds, [area.id]));
return {
...area,
requestCount: count[0].count,
};
})
);
Delete an area
import { db } from './db';
import { areas } from './schema';
import { eq } from 'drizzle-orm';
// Note: This will not cascade delete. You should update or remove
// the area ID from requests.areaIds arrays before deleting
await db.delete(areas).where(eq(areas.id, 'area-id-here'));
When deleting an area, make sure to remove its ID from all requests.areaIds arrays first, as the deletion will not cascade automatically.
Search areas
import { db } from './db';
import { areas } from './schema';
import { or, ilike } from 'drizzle-orm';
const searchTerm = '%auth%';
const results = await db.query.areas.findMany({
where: or(
ilike(areas.name, searchTerm),
ilike(areas.description, searchTerm)
),
});