Swadhin Biswas feat(api): add runner, analytics, packages, and security services · 3/6/2026
28f7954
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/**
* Teams Schema - Drizzle ORM
* Defines teams within organizations
*/
import { relations } from "drizzle-orm";
import { pgTable, primaryKey, text, timestamp } from "drizzle-orm/pg-core";
import { organizations } from "./organizations";
import { repositories } from "./repositories";
import { users } from "./users";
/**
* Teams table - groups within organizations
*/
export const teams = pgTable("teams", {
id: text("id").primaryKey(),
organizationId: text("organization_id")
.notNull()
.references(() => organizations.id, { onDelete: "cascade" }),
name: text("name").notNull(),
slug: text("slug").notNull(),
description: text("description"),
privacy: text("privacy").default("visible"), // visible, secret
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow(),
});
/**
* Team members - users belonging to teams
*/
export const teamMembers = pgTable(
"team_members",
{
teamId: text("team_id")
.notNull()
.references(() => teams.id, { onDelete: "cascade" }),
userId: text("user_id")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
role: text("role").notNull().default("member"), // maintainer, member
createdAt: timestamp("created_at").notNull().defaultNow(),
},
(t) => ({
pk: primaryKey({ columns: [t.teamId, t.userId] }),
}),
);
/**
* Team-Repository mappings — controls team access to repositories
*/
export const teamRepositories = pgTable(
"team_repositories",
{
teamId: text("team_id")
.notNull()
.references(() => teams.id, { onDelete: "cascade" }),
repositoryId: text("repository_id")
.notNull()
.references(() => repositories.id, { onDelete: "cascade" }),
permission: text("permission").notNull().default("read"), // admin, write, read
createdAt: timestamp("created_at").notNull().defaultNow(),
},
(t) => ({
pk: primaryKey({ columns: [t.teamId, t.repositoryId] }),
}),
);
// Relations
export const teamsRelations = relations(teams, ({ one, many }) => ({
organization: one(organizations, {
fields: [teams.organizationId],
references: [organizations.id],
}),
members: many(teamMembers),
repositories: many(teamRepositories),
}));
export const teamMembersRelations = relations(teamMembers, ({ one }) => ({
team: one(teams, {
fields: [teamMembers.teamId],
references: [teams.id],
}),
user: one(users, {
fields: [teamMembers.userId],
references: [users.id],
}),
}));
export const teamRepositoriesRelations = relations(
teamRepositories,
({ one }) => ({
team: one(teams, {
fields: [teamRepositories.teamId],
references: [teams.id],
}),
repository: one(repositories, {
fields: [teamRepositories.repositoryId],
references: [repositories.id],
}),
}),
);
// Types
export type Team = typeof teams.$inferSelect;
export type NewTeam = typeof teams.$inferInsert;
export type TeamMember = typeof teamMembers.$inferSelect;
export type TeamRepository = typeof teamRepositories.$inferSelect;