Skip to content

Schema Types Reference

This guide documents all TypeScript types available in the @repo/database package. Understanding these types is essential for working with the database layer and ensuring type safety across the codebase.

Type Categories

Base

Direct table rows

Extended

With relations

Utility

Reusable fragments
// Importing types from @repo/database
import type {
userType, // Base types
TaskWithLabels, // Extended types
UserSummary, // Utility types
} from "@repo/database";

Types for users, authentication, and sessions.

userType Base

Full user record from the user table. Contains all user profile data including authentication status and ban information.

type userType = {
id: string;
name: string;
displayName: string | null;
email: string;
emailVerified: boolean;
image: string | null;
createdAt: Date;
updatedAt: Date;
role: string | null;
banned: boolean | null;
banReason: string | null;
banExpires: Date | null;
};

UserSummary Utility

Lightweight user data for display purposes. Used whenever you need to show user information (avatars, names) without loading the full user record. Derived from userType.

Used in

TaskWithLabels.createdBy TaskWithLabels.assignees CommentsWithAuthor.createdBy taskTimelineWithActor.actor ReleaseWithTasks.createdBy
type UserSummary = {
id: string;
name: string;
image: string | null;
displayName?: string | null;
};
// Related constants for queries:
import { userSummaryColumns } from "@repo/database";
const task = await db.query.task.findFirst({
with: {
createdBy: { columns: userSummaryColumns },
},
});

sessionType Base

User session record for authentication. Tracks login sessions with device info.

type sessionType = {
id: string;
expiresAt: Date;
token: string;
createdAt: Date;
updatedAt: Date;
ipAddress: string | null;
userAgent: string | null;
userId: string;
impersonatedBy: string | null;
};

accountType Base

OAuth account linkage (GitHub, Doras, etc.). Links external auth providers to users.

type accountType = {
id: string;
accountId: string;
providerId: string;
userId: string;
accessToken: string | null;
refreshToken: string | null;
idToken: string | null;
accessTokenExpiresAt: Date | null;
refreshTokenExpiresAt: Date | null;
scope: string | null;
password: string | null;
createdAt: Date;
updatedAt: Date;
};

Types for tasks and related entities - the core of Sayr’s functionality.

taskType Base

Base task record from the database. Note: createdBy is a string (user ID) in this type, not a UserSummary.

type taskType = {
id: string;
organizationId: string;
shortId: number | null;
visible: "public" | "private";
createdAt: Date | null;
updatedAt: Date | null;
title: string | null;
description: NodeJSON | null;
status: "backlog" | "todo" | "in-progress" | "done" | "canceled";
priority: "none" | "low" | "medium" | "high" | "urgent";
createdBy: string | null; // User ID
category: string | null;
releaseId: string | null;
voteCount: number;
};

TaskWithLabels Extended

The primary task type used throughout the application. Includes all related data needed for display in task lists, detail pages, and API responses.

Used in

Task list views Task detail pages WebSocket updates API responses
type TaskWithLabels = Omit<taskType, "createdBy"> & {
labels: labelType[];
assignees: UserSummary[];
createdBy?: UserSummary | null;
organization?: {
id: string;
name: string;
slug: string;
logo: string | null;
};
comments?: CommentsWithAuthor;
githubIssue?: githubIssueType;
description: NodeJSON;
};
// Uses Omit because base type has createdBy: string
// but we need createdBy: UserSummary

taskAssigneeType Base

Join table for task-user assignments. Links users to tasks they're assigned to.

type taskAssigneeType = {
taskId: string;
organizationId: string;
userId: string;
};

taskVoteType Base

User vote on a task. Supports both authenticated and anonymous voting via fingerprinting.

type taskVoteType = {
id: string;
organizationId: string;
taskId: string;
userId: string | null; // null for anon
anonHash: string | null; // fingerprint
createdAt: Date | null;
};

Types for task comments, reactions, and edit history.

taskCommentType Base

Base comment record. Supports public and internal visibility for team-only comments.

type taskCommentType = {
id: string;
organizationId: string;
taskId: string | null;
createdAt: Date | null;
updatedAt: Date | null;
content: NodeJSON | null;
createdBy: string | null; // User ID
visibility: "public" | "internal";
};

CommentsWithAuthor Extended

Comments array with resolved author information. Used when displaying comments in task detail views.

Used in

Task detail views Comment lists TaskWithLabels.comments
type CommentsWithAuthor = Array<
Omit<taskCommentType, "createdBy"> & {
createdBy: UserSummary | null;
content: NodeJSON;
}
>;

taskCommentReactionType Base

Emoji reaction on a comment. Each user can react once per emoji per comment.

type taskCommentReactionType = {
id: string;
organizationId: string;
taskId: string;
commentId: string;
userId: string;
emoji: string; // Raw emoji character
createdAt: Date | null;
};

taskCommentHistoryType Base

Edit history for a comment. Stores previous versions when comments are edited.

type taskCommentHistoryType = {
id: string;
organizationId: string;
taskId: string | null;
commentId: string;
editedAt: Date | null;
editedBy: string | null;
content: NodeJSON | null;
};

Types for task activity timeline and event tracking.

taskTimelineType Base

Base timeline event record. Tracks all changes made to a task including status changes, assignments, and comments.

type taskTimelineType = {
id: string;
taskId: string;
organizationId: string;
actorId: string | null;
eventType: TimelineEventType;
fromValue: unknown; // Previous value
toValue: unknown; // New value
content: NodeJSON | null;
createdAt: Date | null;
};
type TimelineEventType =
| "status_change" | "priority_change"
| "comment" | "label_added" | "label_removed"
| "assignee_added" | "assignee_removed"
| "created" | "updated"
| "category_change" | "release_change";

taskTimelineWithActor Extended

Timeline event with resolved actor and visibility. Used when displaying task activity feeds.

Used in

Task activity feeds Timeline components
type taskTimelineWithActor = taskTimelineType & {
visibility: "public" | "internal";
actor?: UserSummary;
updatedAt?: Date | null;
reactions?: {
total: number;
reactions: Record<string, {
count: number;
users: string[];
}>;
};
};

Types for organizations, membership, and teams.

organizationType Base

Base organization record. Contains org profile and settings.

type organizationType = {
id: string;
name: string;
slug: string;
logo: string | null;
bannerImg: string | null;
description: string;
createdAt: Date | null;
updatedAt: Date | null;
privateId: string;
};

OrganizationWithMembers Extended

Organization with its member list loaded. Used for org details with team members.

Used in

Organization settings Member management
interface OrganizationWithMembers extends organizationType {
members: (OrganizationMemberType & {
user: userType
})[];
}

OrganizationMemberType Base

A user's membership in an organization. Links users to orgs.

type OrganizationMemberType = {
id: string;
userId: string;
organizationId: string;
createdAt: Date | null;
};

OrganizationTeamType Base

A team within an organization with granular permissions.

type OrganizationTeamType = {
id: string;
organizationId: string;
name: string;
description: string | null;
permissions: TeamPermissions;
createdAt: Date | null;
updatedAt: Date;
};

TeamPermissions Utility

Granular permission structure for teams. Uses Discord-style inheritance: if ANY team grants a permission, the user has it.

interface TeamPermissions {
admin: {
administrator: boolean;
manageMembers: boolean;
manageTeams: boolean;
};
content: {
manageCategories: boolean;
manageLabels: boolean;
manageViews: boolean;
};
tasks: {
create: boolean;
editAny: boolean;
deleteAny: boolean;
assign: boolean;
changeStatus: boolean;
changePriority: boolean;
};
moderation: {
manageComments: boolean;
approveSubmissions: boolean;
manageVotes: boolean;
};
}

Types for releases and milestones.

releaseType Base

Base release record for tracking milestones and versioned releases.

type releaseType = {
id: string;
organizationId: string;
name: string;
slug: string;
description: NodeJSON | null;
status: "planned" | "in-progress" | "released" | "archived";
targetDate: Date | null;
releasedAt: Date | null;
color: string | null;
icon: string | null;
createdBy: string | null;
createdAt: Date | null;
updatedAt: Date | null;
};

ReleaseWithTasks Extended

Release with its associated tasks. Used for release detail pages and roadmap views.

Used in

Release pages Roadmap views
type ReleaseWithTasks = Omit<releaseType, "createdBy"> & {
tasks: TaskWithLabels[];
createdBy?: UserSummary | null;
};

Types for organizing tasks with labels and categories.

labelType Base

A reusable label within an organization. Supports visibility settings for public/private labels.

type labelType = {
id: string;
organizationId: string;
name: string;
color: string | null; // Hex (#RRGGBB)
visible: "public" | "private";
createdAt: Date | null;
};

taskLabelType Base

Join table for task-label assignments. Links labels to tasks.

type taskLabelType = {
id: string;
taskId: string;
organizationId: string;
labelId: string;
};

categoryType Base

A category/project within an organization. Used for grouping related tasks.

type categoryType = {
id: string;
organizationId: string;
name: string;
color: string | null; // HSLA
icon: string | null;
createdAt: Date | null;
};

Types for task templates that pre-fill values when creating new tasks.

issueTemplateType Base

Base template record for creating tasks with preset values.

type issueTemplateType = {
id: string;
organizationId: string;
name: string;
titlePrefix: string | null;
description: NodeJSON | null;
status: string | null;
priority: string | null;
categoryId: string | null;
createdAt: Date | null;
updatedAt: Date | null;
};

issueTemplateWithRelations Extended

Template with labels, assignees, and category loaded. Used when displaying and applying templates.

Used in

Template selection UI Task creation forms
type issueTemplateWithRelations = issueTemplateType & {
labels: labelType[];
assignees: UserSummary[];
category?: {
id: string;
name: string;
color: string | null;
icon: string | null;
} | null;
};

Types for GitHub sync features and issue linking.

githubInstallationType Base

GitHub App installation record. Tracks which orgs have installed the GitHub app.

type githubInstallationType = {
id: string;
organizationId: string | null;
installationId: number;
userId: string | null;
createdAt: Date;
updatedAt: Date;
};

githubRepositoryType Base

A repository linked to an installation. Maps GitHub repos to Sayr categories.

type githubRepositoryType = {
id: string;
installationId: number;
repoId: number;
repoName: string;
organizationId: string | null;
categoryId: string | null;
userId: string | null;
createdAt: Date;
updatedAt: Date;
};

githubIssueType Base

A GitHub issue synced to a Sayr task. Links external issues to internal tasks.

type githubIssueType = {
id: string;
repositoryId: string;
organizationId: string;
issueNumber: number;
issueUrl: string;
taskId: string;
createdAt: Date;
updatedAt: Date;
};

Additional utility and configuration types.

NodeJSON Utility

Represents TipTap/ProseMirror rich text content stored as JSONB in the database.

Used in

task.description taskComment.content taskTimeline.content release.description
interface NodeJSON {
type: string;
marks?: Array<{
type: string;
attrs?: Record<string, any>;
}>;
text?: string;
content?: NodeJSON[];
attrs?: Record<string, any>;
}

savedViewType Base

A saved filter/view configuration for tasks. Stores user-created views with filters and display settings.

type savedViewType = {
id: string;
organizationId: string;
createdById: string | null;
name: string;
slug: string | null;
logo: string | null;
filterParams: string;
viewConfig: {
mode: "list" | "kanban";
groupBy: "status" | "priority" | "assignee" | "category";
subGroupBy?: "status" | "priority" | "assignee" | "category" | "none";
showCompletedTasks: boolean;
color?: string;
icon?: string;
};
createdAt: Date | null;
updatedAt: Date | null;
};

inviteType Base

Organization invitation record. Tracks pending and accepted invites.

type inviteType = {
id: string;
organizationId: string;
email: string;
userId: string | null;
invitedById: string;
role: string;
inviteCode: string;
status: "pending" | "accepted" | "declined" | "expired";
createdAt: Date | null;
expiresAt: Date | null;
};

ApikeyType Base

API key record with rate limiting support. Used for external API access.

type ApikeyType = {
id: string;
name: string | null;
start: string | null;
prefix: string | null;
key: string; // Hashed
userId: string;
enabled: boolean;
rateLimitEnabled: boolean;
rateLimitTimeWindow: number | null;
rateLimitMax: number | null;
requestCount: number;
remaining: number | null;
lastRequest: Date | null;
expiresAt: Date | null;
permissions: string | null;
metadata: unknown;
createdAt: Date;
updatedAt: Date;
};

Drizzle provides automatic type inference from your schema definitions:

import { schema } from "@repo/database";
// SELECT result type (what you get from queries)
type Task = typeof schema.task.$inferSelect;
// INSERT input type (what you pass to inserts)
type NewTask = typeof schema.task.$inferInsert;

When queries include relations, define extended types in packages/database/schema/index.ts:

// Good: Use Omit when overriding a field type
export type TaskWithLabels = Omit<taskType, "createdBy"> & {
labels: labelType[];
createdBy?: UserSummary | null; // Changed from string to UserSummary
};
// Bad: Intersection creates impossible type (string & UserSummary = never)
export type TaskWithLabels = taskType & {
createdBy: UserSummary;
};

Always use userSummaryColumns when fetching user data for display:

import { userSummaryColumns } from "@repo/database";
const task = await db.query.task.findFirst({
where: eq(task.id, taskId),
with: {
createdBy: { columns: userSummaryColumns },
assignees: {
with: { user: { columns: userSummaryColumns } },
},
},
});