513 lines
39 KiB
TypeScript
513 lines
39 KiB
TypeScript
// Public entry point for the storage layer.
|
|
// Implementation is split into domain modules under server/storage/
|
|
|
|
import { users, organizations, userSessions, invitations, userCustomFields, userCustomValues, forms, formTabs, formFields, formStatuses, statusTransitions, tasks, taskFieldValues, fieldHistory, taskMessages, userNotifications, messageReads, bookmarkFolders, bookmarks, bots, botSubscriptions, botSessions, dataTables, dataTableRows, dataTablePermissions, externalServices, regularTableRows, fieldTemplates, customTabModules, taskTabValues, deviceTokens, userPresence, webPushSubscriptions, customPages, type User, type Organization, type UserSession, type Invitation, type InsertUser, type InsertOrganization, type InsertUserSession, type InsertInvitation, type UserWithOrganization, type UserCustomField, type UserCustomValue, type CreateUserCustomField, type UpdateUserCustomField, type UserProfileTab, type UserProfileField, type UserProfileFieldValue, type UserProfileAuditLog, type InsertUserProfileTab, type InsertUserProfileField, type InsertUserProfileFieldValue, type InsertUserProfileAuditLog, userProfileAuditLog, type Form, type FormTab, type FormField, type FormStatus, type StatusTransition, type Task, type TaskFieldValue, type FieldHistory, type TaskMessage, type TaskMessageWithAuthor, type UserNotification, type MessageRead, type InsertMessageRead, type BookmarkFolder, type Bookmark, type InsertForm, type InsertFormTab, type InsertFormField, type InsertFormStatus, type InsertStatusTransition, type InsertTask, type InsertTaskFieldValue, type InsertFieldHistory, type InsertTaskMessage, type InsertUserNotification, type InsertBookmarkFolder, type InsertBookmark, type Bot, type BotSubscription, type BotSession, type InsertBot, type InsertBotSubscription, type InsertBotSession, type BotWithSubscriptions, type DataTable, type DataTableRow, type DataTablePermission, type DataTableAccessRule, type InsertDataTableAccessRule, type InsertDataTable, type InsertDataTableRow, type InsertDataTablePermission, type DataTableWithRows, type DataTableFull, type ExternalService, type InsertExternalService, type RegularTableRow, type InsertRegularTableRow, type FieldTemplate, type InsertFieldTemplate, type CustomTabModule, type InsertCustomTabModule, type TaskTabValue, type InsertTaskTabValue, type DeviceToken, type InsertDeviceToken, type UserPresence, type InsertUserPresence, type WebPushSubscription, type CustomPage, type InsertCustomPage } from "@shared/schema";
|
|
import { organizationApiKeys, type OrganizationApiKey, type ApiKeyScopes } from "@shared/schema";
|
|
import { automations, type Automation, type InsertAutomation } from "@shared/schema";
|
|
import { taskRelations, type TaskRelation, type InsertTaskRelation } from "@shared/schema";
|
|
import { taskReminders, type TaskReminder, type InsertTaskReminder } from "@shared/schema";
|
|
import { ragSettings, type RagSetting, embeddingQueue } from "@shared/schema";
|
|
import { llmProviders, type LlmProvider, type InsertLlmProvider } from "@shared/schema";
|
|
import { systemConfig } from "@shared/schema";
|
|
import { taskAuditLog, type TaskAuditLog, type InsertTaskAuditLog } from "@shared/schema";
|
|
import { taskRoles, type TaskRole, taskUserAccess, type TaskUserAccess, roleMembers, roles, taskAssignees, type TaskAssignee } from "@shared/schema";
|
|
import { userOfflineSubscriptions, type UserOfflineSubscription, type InsertUserOfflineSubscription } from "@shared/schema";
|
|
import type { SafeUser } from "@shared/schema";
|
|
import { db } from "./db";
|
|
import { eq, and, or, desc, asc, exists, isNull, isNotNull, sql, ilike, inArray, lte } from "drizzle-orm";
|
|
import { alias } from "drizzle-orm/pg-core";
|
|
import crypto from "crypto";
|
|
import { formatUserName } from "./utils/formatUserName";
|
|
import type { DirectoryRowsPageOptions } from "./storage/data-tables-core.storage";
|
|
|
|
export interface RelatedTreeNode {
|
|
id: number;
|
|
title: string;
|
|
formId: number;
|
|
formName: string;
|
|
fieldName: string;
|
|
isFinal: boolean;
|
|
statusName: string | null;
|
|
statusColor: string | null;
|
|
nodes: RelatedTreeNode[];
|
|
}
|
|
|
|
export interface IStorage {
|
|
// Organizations
|
|
getOrganization(id: number): Promise<Organization | undefined>;
|
|
getOrganizationBySlug(slug: string): Promise<Organization | undefined>;
|
|
createOrganization(organization: InsertOrganization): Promise<Organization>;
|
|
|
|
// Users
|
|
getUser(id: number): Promise<User | undefined>;
|
|
getUserWithOrganization(id: number): Promise<UserWithOrganization | undefined>;
|
|
getUserByEmail(email: string, organizationId?: number): Promise<User | undefined>;
|
|
getUserByEmailAndSlug(email: string, slug: string): Promise<UserWithOrganization | undefined>;
|
|
getUsersByOrganization(organizationId: number, options?: { since?: Date }): Promise<SafeUser[]>;
|
|
listUsers(organizationId: number, options?: import('./storage/users.storage').ListUsersOptions): Promise<import('./storage/users.storage').ListUsersResult>;
|
|
getLinkedTasksForUser(userId: number, organizationId: number): Promise<
|
|
Array<{
|
|
task: Task;
|
|
form: { id: number; name: string };
|
|
status: FormStatus | null;
|
|
field: FormField;
|
|
}>
|
|
>;
|
|
getUserByResetPasswordToken(token: string): Promise<User | undefined>;
|
|
createUser(insertUser: InsertUser): Promise<User>;
|
|
updateUser(id: number, updates: Partial<User>): Promise<User>;
|
|
deleteUser(id: number): Promise<void>;
|
|
|
|
// User offline subscriptions
|
|
getUserOfflineSubscriptions(userId: number, organizationId: number): Promise<UserOfflineSubscription[]>;
|
|
getUserOfflineSubscription(userId: number, formId: number): Promise<UserOfflineSubscription | undefined>;
|
|
upsertUserOfflineSubscription(subscription: InsertUserOfflineSubscription): Promise<UserOfflineSubscription>;
|
|
deleteUserOfflineSubscription(userId: number, formId: number): Promise<void>;
|
|
|
|
// User sessions
|
|
// Токены передаются в plain-виде; хэширование (sha256) — внутри реализации (шаг 0.6).
|
|
createUserSession(session: InsertUserSession): Promise<UserSession>;
|
|
getUserSessionByToken(refreshToken: string): Promise<UserSession | undefined>;
|
|
getUserSessionByParentToken(parentRefreshToken: string): Promise<UserSession | undefined>;
|
|
getActiveSessionInFamily(familyId: string): Promise<UserSession | undefined>;
|
|
rotateUserSession(sessionId: number, newSession: InsertUserSession): Promise<UserSession>;
|
|
listUserSessions(userId: number): Promise<UserSession[]>;
|
|
getUserSessionById(id: number): Promise<UserSession | undefined>;
|
|
revokeSessionById(id: number): Promise<void>;
|
|
markSessionReplaced(sessionId: number, replacedByToken: string): Promise<void>;
|
|
revokeSession(refreshToken: string): Promise<void>;
|
|
revokeSessionFamily(familyId: string): Promise<void>;
|
|
revokeAllUserSessions(userId: number): Promise<void>;
|
|
deleteUserSession(refreshToken: string): Promise<void>;
|
|
deleteUserSessions(userId: number): Promise<void>;
|
|
|
|
// Invitations
|
|
createInvitation(invitation: InsertInvitation): Promise<Invitation>;
|
|
getInvitationByToken(token: string): Promise<Invitation | undefined>;
|
|
getInvitationsByOrganization(organizationId: number): Promise<Invitation[]>;
|
|
markInvitationAsUsed(token: string): Promise<Invitation>;
|
|
deleteInvitation(id: number, organizationId: number): Promise<void>;
|
|
|
|
// User Custom Fields
|
|
getUserCustomFields(organizationId: number): Promise<UserCustomField[]>;
|
|
getUserCustomField(id: number, organizationId: number): Promise<UserCustomField | undefined>;
|
|
createUserCustomField(organizationId: number, field: CreateUserCustomField): Promise<UserCustomField>;
|
|
updateUserCustomField(id: number, organizationId: number, updates: UpdateUserCustomField): Promise<UserCustomField>;
|
|
deleteUserCustomField(id: number, organizationId: number): Promise<void>;
|
|
reorderUserCustomFields(organizationId: number, fieldIds: number[]): Promise<void>;
|
|
|
|
// User Custom Values
|
|
getUserCustomValues(userId: number, organizationId: number): Promise<UserCustomValue[]>;
|
|
setUserCustomValue(userId: number, fieldId: number, value: string | null, organizationId: number): Promise<UserCustomValue>;
|
|
setUserCustomValues(userId: number, values: Array<{ fieldId: number; value: string | null }>, organizationId: number): Promise<void>;
|
|
|
|
// User Profile Tabs
|
|
getUserProfileTabs(organizationId: number): Promise<UserProfileTab[]>;
|
|
getUserProfileTabsByCreationOrder(organizationId: number): Promise<UserProfileTab[]>;
|
|
bulkSaveUserProfileTabs(organizationId: number, tabs: Array<{ id?: number; name: string; code: string; position?: number; displayOrder?: number }>): Promise<UserProfileTab[]>;
|
|
|
|
// User Profile Fields
|
|
getUserProfileFields(organizationId: number): Promise<UserProfileField[]>;
|
|
getUserProfileFieldsByCreationOrder(organizationId: number): Promise<UserProfileField[]>;
|
|
getUserProfileFieldById(id: number, organizationId: number): Promise<UserProfileField | undefined>;
|
|
bulkSaveUserProfileFields(organizationId: number, fieldIdsToDelete: number[], fields: Array<{ id?: number; name: string; code: string; type: string; isRequired?: boolean; placeholder?: string | null; defaultValue?: string | null; validationRules?: unknown; options?: unknown; position?: number | null; displayOrder?: number | null; tabId?: number | null; linkedFormId?: number | null; companyAutofill?: unknown; maxFileCount?: number | null; maxFileSizeMB?: number | null; autoProlongation?: boolean | null; autoProlongationLabel?: string | null }>): Promise<UserProfileField[]>;
|
|
|
|
// User Profile Field Values
|
|
getUserProfileFieldValues(userId: number): Promise<UserProfileFieldValue[]>;
|
|
getUserProfileFieldValue(userId: number, fieldId: number): Promise<UserProfileFieldValue | undefined>;
|
|
createUserProfileFieldValue(insertValue: InsertUserProfileFieldValue): Promise<UserProfileFieldValue>;
|
|
createUserProfileFieldValueWithAudit(insertValue: InsertUserProfileFieldValue, organizationId: number, changedBy: number): Promise<UserProfileFieldValue>;
|
|
updateUserProfileFieldValue(userId: number, fieldId: number, updates: Partial<UserProfileFieldValue>): Promise<UserProfileFieldValue>;
|
|
updateUserProfileFieldValueWithAudit(userId: number, fieldId: number, updates: Partial<UserProfileFieldValue>, organizationId: number, changedBy: number): Promise<UserProfileFieldValue>;
|
|
deleteUserProfileFieldValue(userId: number, fieldId: number): Promise<void>;
|
|
deleteUserProfileFieldValueWithAudit(userId: number, fieldId: number, organizationId: number, changedBy: number): Promise<void>;
|
|
getUserProfileDetail(userId: number, organizationId: number): Promise<{ user: any; tabs: UserProfileTab[]; fields: UserProfileField[]; fieldValues: UserProfileFieldValue[] }>;
|
|
|
|
// User Profile Audit Log
|
|
getUserProfileAuditLog(userId: number, organizationId: number): Promise<UserProfileAuditLog[]>;
|
|
createUserProfileAuditLog(insertValue: InsertUserProfileAuditLog): Promise<UserProfileAuditLog>;
|
|
|
|
// Forms
|
|
getForm(id: number, organizationId: number): Promise<Form | undefined>;
|
|
getFormsByOrganization(organizationId: number): Promise<Form[]>;
|
|
createForm(insertForm: InsertForm): Promise<Form>;
|
|
updateForm(id: number, organizationId: number, updates: Partial<Form>): Promise<Form>;
|
|
deleteForm(id: number, organizationId: number): Promise<void>;
|
|
getTasksCountByForm(formId: number): Promise<{ total: number; active: number; completed: number }>;
|
|
getTaskCountsByStatus(formId: number, organizationId: number): Promise<Array<{ statusId: number; name: string; color: string; count: number }>>;
|
|
getFormsWithOfflineCache(organizationId: number): Promise<Form[]>;
|
|
getOfflineCacheConfig(id: number, organizationId: number): Promise<Form['offlineCache']>;
|
|
updateFormOfflineCache(id: number, organizationId: number, config: Form['offlineCache']): Promise<Form>;
|
|
|
|
// Form Tabs
|
|
getFormTabs(formId: number, organizationId: number): Promise<FormTab[]>;
|
|
getFormTabsByCreationOrder(formId: number, organizationId: number): Promise<FormTab[]>;
|
|
getFormTab(id: number, formId: number, organizationId: number): Promise<FormTab | undefined>;
|
|
createFormTab(insertTab: InsertFormTab): Promise<FormTab>;
|
|
updateFormTab(id: number, formId: number, organizationId: number, updates: Partial<FormTab>): Promise<FormTab>;
|
|
deleteFormTab(id: number, formId: number, organizationId: number): Promise<void>;
|
|
bulkSaveFormTabs(formId: number, organizationId: number, tabs: Array<{ id?: number; name: string; code: string; type: string; tableColumns?: unknown }>): Promise<FormTab[]>;
|
|
|
|
// Form Fields
|
|
getFormFields(formId: number, organizationId: number): Promise<FormField[]>;
|
|
getFormFieldsByCreationOrder(formId: number, organizationId: number): Promise<FormField[]>;
|
|
getDeletedFormFields(formId: number, organizationId: number): Promise<FormField[]>;
|
|
restoreFormField(id: number, formId: number, organizationId: number): Promise<FormField>;
|
|
getFormFieldById(id: number, organizationId: number): Promise<FormField | undefined>;
|
|
createFormField(insertField: InsertFormField): Promise<FormField>;
|
|
updateFormField(id: number, formId: number, organizationId: number, updates: Partial<FormField>): Promise<FormField>;
|
|
deleteFormField(id: number, formId: number, organizationId: number): Promise<void>;
|
|
bulkSaveFormFields(formId: number, organizationId: number, fieldIdsToDelete: number[], fields: Array<{ id?: number; name: string; code: string; type: string; isRequired?: boolean; placeholder?: string | null; defaultValue?: string | null; validationRules?: unknown; options?: unknown; tabId?: number | null; linkedFormId?: number | null; taskRelationType?: string | null; companyAutofill?: unknown; maxFileCount?: number | null; maxFileSizeMB?: number | null; linkToUserProfile?: boolean | null }>): Promise<FormField[]>;
|
|
|
|
// Form Statuses
|
|
getFormStatuses(formId: number, organizationId: number): Promise<FormStatus[]>;
|
|
createFormStatus(insertStatus: InsertFormStatus): Promise<FormStatus>;
|
|
updateFormStatus(id: number, formId: number, organizationId: number, updates: Partial<FormStatus>): Promise<FormStatus>;
|
|
deleteFormStatus(id: number, formId: number, organizationId: number): Promise<void>;
|
|
bulkSaveFormStatuses(formId: number, organizationId: number, statusIdsToDelete: number[], statuses: Array<{ id?: number; name: string; color?: string; isInitial?: boolean; isFinal?: boolean }>): Promise<FormStatus[]>;
|
|
|
|
// Status Transitions
|
|
getStatusTransitions(formId: number, organizationId: number): Promise<StatusTransition[]>;
|
|
createStatusTransition(insertTransition: InsertStatusTransition): Promise<StatusTransition>;
|
|
updateStatusTransition(id: number, formId: number, organizationId: number, updates: Partial<StatusTransition>): Promise<StatusTransition>;
|
|
deleteStatusTransition(id: number, formId: number, organizationId: number): Promise<void>;
|
|
|
|
// Tasks
|
|
getTask(id: number, organizationId: number): Promise<Task | undefined>;
|
|
getTaskDetail(id: number, organizationId: number): Promise<{
|
|
task: Task;
|
|
form: Form;
|
|
fields: FormField[];
|
|
statuses: FormStatus[];
|
|
tabs: FormTab[];
|
|
transitions: StatusTransition[];
|
|
fieldValues: TaskFieldValue[];
|
|
subtasks: Task[];
|
|
messages: TaskMessageWithAuthor[];
|
|
users: Array<SafeUser & { fullName: string }>;
|
|
hasRelations: boolean;
|
|
assignees: Array<TaskAssignee & { user: { id: number; firstName: string | null; lastName: string | null; email: string } }>;
|
|
} | null>;
|
|
getTasksByForm(formId: number, organizationId: number): Promise<Task[]>;
|
|
getTasksWithFieldsByForm(formId: number, organizationId: number): Promise<Task[]>;
|
|
getTasksWithFieldsByFormOptimized(formId: number, organizationId: number, options?: { limit?: number; offset?: number; assignedTo?: number; since?: Date }): Promise<{ tasks: Task[]; total: number }>;
|
|
getTasksByOrganization(organizationId: number, options?: {
|
|
limit?: number;
|
|
offset?: number;
|
|
sortBy?: 'updatedAt' | 'createdAt';
|
|
order?: 'asc' | 'desc';
|
|
statusId?: number;
|
|
assignedTo?: number;
|
|
minimal?: boolean;
|
|
excludeDescription?: boolean;
|
|
cursor?: import('./utils/task-pagination').TasksCursor | null;
|
|
}): Promise<Task[] | Partial<Task>[]>;
|
|
getTasksCountByOrganization(organizationId: number): Promise<number>;
|
|
createTask(insertTask: InsertTask): Promise<Task>;
|
|
updateTask(id: number, organizationId: number, updates: Partial<Task>): Promise<Task>;
|
|
updateTaskIfNotModified(id: number, organizationId: number, updates: Partial<Task>, requiredUpdatedAt: Date): Promise<Task | null>;
|
|
deleteTask(id: number, organizationId: number): Promise<void>;
|
|
searchTasksByKeyword(organizationId: number, query: string, limit?: number): Promise<(Pick<Task, 'id' | 'title' | 'description' | 'formId' | 'currentStatusId' | 'isCompleted'> & { statusName: string | null; statusColor: string | null; statusIsFinal: boolean | null })[]>;
|
|
|
|
// Task Field Values
|
|
getTaskFieldValues(taskId: number, organizationId: number): Promise<TaskFieldValue[]>;
|
|
getTasksByIds(taskIds: number[], organizationId: number): Promise<Task[]>;
|
|
getTaskFieldValuesByTaskIds(taskIds: number[], organizationId: number): Promise<TaskFieldValue[]>;
|
|
createTaskFieldValue(insertValue: InsertTaskFieldValue): Promise<TaskFieldValue>;
|
|
updateTaskFieldValue(taskId: number, fieldId: number, organizationId: number, updates: Partial<TaskFieldValue>): Promise<TaskFieldValue>;
|
|
bulkUpsertTaskFieldValues(taskId: number, formId: number, updates: Array<{ fieldId: number; value: unknown }>): Promise<TaskFieldValue[]>;
|
|
deleteTaskFieldValue(taskId: number, fieldId: number, organizationId: number): Promise<void>;
|
|
|
|
// Field History
|
|
getFieldHistory(taskId: number, fieldId: number, organizationId: number): Promise<FieldHistory[]>;
|
|
createFieldHistory(insertHistory: InsertFieldHistory): Promise<FieldHistory>;
|
|
|
|
// Task Messages (Chat)
|
|
getTaskMessages(taskId: number, organizationId: number, afterId?: number, viewerUserId?: number): Promise<TaskMessageWithAuthor[]>;
|
|
getTaskMessage(messageId: number, organizationId: number): Promise<TaskMessageWithAuthor | undefined>;
|
|
getTaskMessagesByIds(messageIds: number[], organizationId: number): Promise<TaskMessage[]>;
|
|
getTaskMessagesByTaskIds(taskIds: number[], organizationId: number): Promise<TaskMessage[]>;
|
|
createTaskMessage(insertMessage: any, organizationId: number): Promise<any>;
|
|
updateTaskMessage(id: number, organizationId: number, updates: Partial<TaskMessage>): Promise<TaskMessage>;
|
|
deleteTaskMessage(id: number, organizationId: number): Promise<void>;
|
|
|
|
// Message Reads (Read Receipts)
|
|
markMessageAsRead(messageId: number, userId: number, organizationId: number): Promise<MessageRead>;
|
|
getMessageReads(messageId: number, organizationId: number): Promise<MessageRead[]>;
|
|
getMessageReadsByUser(userId: number, organizationId: number): Promise<MessageRead[]>;
|
|
isMessageReadByUser(messageId: number, userId: number, organizationId: number): Promise<boolean>;
|
|
|
|
// Bookmark Folders
|
|
getBookmarkFolder(id: number, organizationId: number, userId: number): Promise<BookmarkFolder | undefined>;
|
|
getBookmarkFoldersByOrganization(organizationId: number, userId: number): Promise<BookmarkFolder[]>;
|
|
getBookmarkFoldersByParent(parentId: number | null, organizationId: number, userId: number): Promise<BookmarkFolder[]>;
|
|
createBookmarkFolder(insertFolder: InsertBookmarkFolder): Promise<BookmarkFolder>;
|
|
updateBookmarkFolder(id: number, organizationId: number, updates: Partial<BookmarkFolder>, userId: number): Promise<BookmarkFolder>;
|
|
deleteBookmarkFolder(id: number, organizationId: number, userId: number): Promise<void>;
|
|
normalizeBookmarkFolderPositions(organizationId: number, userId: number): Promise<void>;
|
|
batchUpdateBookmarkFolderPositions(items: { id: number; position: number }[], organizationId: number, userId: number): Promise<void>;
|
|
|
|
// Bookmarks
|
|
getBookmark(id: number, organizationId: number, userId: number): Promise<Bookmark | undefined>;
|
|
getBookmarksByFolder(folderId: number | null, organizationId: number, userId: number): Promise<Bookmark[]>;
|
|
getBookmarksByOrganization(organizationId: number, userId: number): Promise<Bookmark[]>;
|
|
createBookmark(insertBookmark: InsertBookmark): Promise<Bookmark>;
|
|
updateBookmark(id: number, organizationId: number, updates: Partial<Bookmark>, userId: number): Promise<Bookmark>;
|
|
deleteBookmark(id: number, organizationId: number, userId: number): Promise<void>;
|
|
normalizeBookmarkPositions(organizationId: number, userId: number): Promise<void>;
|
|
batchUpdateBookmarkPositions(items: { id: number; position: number }[], organizationId: number, userId: number): Promise<void>;
|
|
|
|
// User Notifications
|
|
getUnreadNotificationCount(userId: number, organizationId: number): Promise<number>;
|
|
getUserNotifications(userId: number, organizationId: number, isRead?: boolean): Promise<UserNotification[]>;
|
|
createUserNotification(insertNotification: InsertUserNotification): Promise<UserNotification>;
|
|
markNotificationAsRead(id: number, userId: number, organizationId: number): Promise<UserNotification>;
|
|
markAllNotificationsAsRead(userId: number, organizationId: number): Promise<void>;
|
|
markTaskNotificationsAsRead(taskId: number, userId: number, organizationId: number): Promise<void>;
|
|
deleteNotification(id: number, userId: number, organizationId: number): Promise<void>;
|
|
|
|
// User Search
|
|
searchUsers(query: string, organizationId: number, limit?: number): Promise<SafeUser[]>;
|
|
|
|
// Bots
|
|
getBot(id: number, organizationId: number): Promise<Bot | undefined>;
|
|
getBotByLogin(login: string, organizationId: number): Promise<Bot | undefined>;
|
|
getBotsByOrganization(organizationId: number): Promise<Bot[]>;
|
|
getBotWithSubscriptions(id: number, organizationId: number): Promise<BotWithSubscriptions | undefined>;
|
|
searchBots(query: string, organizationId: number, limit?: number): Promise<Bot[]>;
|
|
createBot(insertBot: InsertBot): Promise<Bot>;
|
|
updateBot(id: number, organizationId: number, updates: Partial<Bot>): Promise<Bot>;
|
|
deleteBot(id: number, organizationId: number): Promise<void>;
|
|
|
|
// Bot Subscriptions
|
|
getBotSubscriptions(botId: number, organizationId: number): Promise<BotSubscription[]>;
|
|
getBotSubscriptionsByForm(formId: number, organizationId: number): Promise<BotSubscription[]>;
|
|
getBotSubscriptionsByStatus(statusId: number, organizationId: number): Promise<BotSubscription[]>;
|
|
getBotSubscriptionsByTransition(transitionId: number, organizationId: number): Promise<BotSubscription[]>;
|
|
createBotSubscription(insertSubscription: InsertBotSubscription): Promise<BotSubscription>;
|
|
updateBotSubscription(id: number, organizationId: number, updates: Partial<BotSubscription>): Promise<BotSubscription>;
|
|
deleteBotSubscription(id: number, organizationId: number): Promise<void>;
|
|
|
|
// Bot Sessions
|
|
createBotSession(session: InsertBotSession): Promise<BotSession>;
|
|
getBotSessionByToken(refreshToken: string): Promise<BotSession | undefined>;
|
|
deleteBotSession(refreshToken: string): Promise<void>;
|
|
deleteBotSessions(botId: number): Promise<void>;
|
|
|
|
// Data Tables
|
|
getDataTable(id: number, organizationId: number): Promise<DataTable | undefined>;
|
|
getDataTablesByOrganization(organizationId: number): Promise<DataTable[]>;
|
|
getDataTablesWithAccess(userId: number, organizationId: number): Promise<DataTable[]>;
|
|
getDataTableFull(id: number, organizationId: number): Promise<DataTableFull | undefined>;
|
|
createDataTable(table: InsertDataTable & { organizationId: number; createdBy: number }): Promise<DataTable>;
|
|
updateDataTable(id: number, organizationId: number, updates: Partial<DataTable>): Promise<DataTable>;
|
|
deleteDataTable(id: number, organizationId: number): Promise<void>;
|
|
|
|
// Data Table Rows
|
|
getDataTableRows(tableId: number, organizationId: number): Promise<DataTableRow[]>;
|
|
getDataTableRowsPaged(tableId: number, organizationId: number, opts?: DirectoryRowsPageOptions): Promise<{ rows: DataTableRow[]; total: number }>;
|
|
getDataTableRowCounts(organizationId: number): Promise<Map<number, number>>;
|
|
getDataTableRow(id: number, tableId: number, organizationId: number): Promise<DataTableRow | undefined>;
|
|
createDataTableRow(row: InsertDataTableRow): Promise<DataTableRow>;
|
|
updateDataTableRow(id: number, tableId: number, organizationId: number, updates: Partial<DataTableRow>): Promise<DataTableRow>;
|
|
deleteDataTableRow(id: number, tableId: number, organizationId: number): Promise<void>;
|
|
bulkCreateDataTableRows(tableId: number, rows: { values: string[]; parentId?: number | null; position?: number }[]): Promise<DataTableRow[]>;
|
|
bulkDeleteDataTableRows(tableId: number, organizationId: number): Promise<void>;
|
|
applyDataTableSync(tableId: number, deleted: { id: number }[], added: { values: string[]; position: number }[], reordered: { id: number; newPosition: number }[], positionUpdates: { id: number; position: number }[]): Promise<void>;
|
|
applyDataTableDiff(tableId: number, upsertRows: { values: string[] }[], deleteKeys: string[], currentRows: DataTableRow[]): Promise<{ added: DataTableRow[]; updated: DataTableRow[]; deleted: DataTableRow[] }>;
|
|
|
|
// Data Table Permissions
|
|
getDataTablePermissions(tableId: number, organizationId: number): Promise<(DataTablePermission & { user: { id: number; firstName: string; lastName: string; email: string } })[]>;
|
|
getDataTablePermission(tableId: number, userId: number): Promise<DataTablePermission | undefined>;
|
|
getUserTableRole(tableId: number, userId: number, createdBy: number, organizationId?: number): Promise<'admin' | 'editor' | 'reader' | null>;
|
|
setDataTablePermission(permission: InsertDataTablePermission): Promise<DataTablePermission>;
|
|
deleteDataTablePermission(tableId: number, userId: number): Promise<void>;
|
|
|
|
// Data Table Access Rules
|
|
getDataTableAccessRules(tableId: number, organizationId: number): Promise<DataTableAccessRule[]>;
|
|
createDataTableAccessRule(data: InsertDataTableAccessRule): Promise<DataTableAccessRule>;
|
|
deleteDataTableAccessRule(id: number, organizationId: number): Promise<void>;
|
|
getLinkedFormsForTable(tableId: number, organizationId: number): Promise<{ id: number; name: string }[]>;
|
|
|
|
// External Services
|
|
getExternalServices(organizationId: number): Promise<ExternalService[]>;
|
|
getExternalService(id: number, organizationId: number): Promise<ExternalService | undefined>;
|
|
getExternalServiceByType(serviceType: string, organizationId: number): Promise<ExternalService | undefined>;
|
|
createExternalService(service: InsertExternalService): Promise<ExternalService>;
|
|
updateExternalService(id: number, organizationId: number, updates: Partial<ExternalService>): Promise<ExternalService>;
|
|
deleteExternalService(id: number, organizationId: number): Promise<void>;
|
|
|
|
// Regular Table Rows (for type='table' tabs)
|
|
getRegularTableRows(taskId: number, tabId: number): Promise<RegularTableRow[]>;
|
|
getRegularTableRow(id: number, taskId: number, tabId: number): Promise<RegularTableRow | undefined>;
|
|
createRegularTableRow(row: InsertRegularTableRow): Promise<RegularTableRow>;
|
|
updateRegularTableRow(id: number, taskId: number, tabId: number, updates: Partial<RegularTableRow>): Promise<RegularTableRow>;
|
|
deleteRegularTableRow(id: number, taskId: number, tabId: number): Promise<void>;
|
|
|
|
// Field Templates
|
|
getFieldTemplates(organizationId: number): Promise<FieldTemplate[]>;
|
|
getFieldTemplate(id: number, organizationId: number): Promise<FieldTemplate | undefined>;
|
|
getFieldTemplateByCode(code: string, organizationId: number): Promise<FieldTemplate | undefined>;
|
|
createFieldTemplate(field: InsertFieldTemplate): Promise<FieldTemplate>;
|
|
updateFieldTemplate(id: number, organizationId: number, updates: Partial<FieldTemplate>): Promise<FieldTemplate>;
|
|
deleteFieldTemplate(id: number, organizationId: number): Promise<void>;
|
|
|
|
// Custom Tab Modules
|
|
getCustomTabModules(organizationId: number): Promise<CustomTabModule[]>;
|
|
getCustomTabModule(id: number, organizationId: number): Promise<CustomTabModule | undefined>;
|
|
getCustomTabModuleByType(type: string, organizationId: number): Promise<CustomTabModule | undefined>;
|
|
createCustomTabModule(module: InsertCustomTabModule): Promise<CustomTabModule>;
|
|
updateCustomTabModule(id: number, organizationId: number, updates: Partial<CustomTabModule>): Promise<CustomTabModule>;
|
|
deleteCustomTabModule(id: number, organizationId: number): Promise<void>;
|
|
getFormIdsByTabModuleType(type: string, organizationId: number): Promise<number[]>;
|
|
getFormTabByModuleType(formId: number, type: string, organizationId: number): Promise<FormTab | undefined>;
|
|
// Custom JS Pages
|
|
getCustomPages(organizationId: number): Promise<CustomPage[]>;
|
|
getCustomPage(id: number, organizationId: number): Promise<CustomPage | undefined>;
|
|
getCustomPageBySlug(slug: string, organizationId: number): Promise<CustomPage | undefined>;
|
|
createCustomPage(page: InsertCustomPage): Promise<CustomPage>;
|
|
updateCustomPage(id: number, organizationId: number, updates: Partial<InsertCustomPage>): Promise<CustomPage>;
|
|
deleteCustomPage(id: number, organizationId: number): Promise<void>;
|
|
|
|
// Automations
|
|
getAutomations(organizationId: number): Promise<Automation[]>;
|
|
getOfflineAutomations(organizationId: number): Promise<Automation[]>;
|
|
getAutomation(id: number, organizationId: number): Promise<Automation | undefined>;
|
|
createAutomation(automation: InsertAutomation): Promise<Automation>;
|
|
updateAutomation(id: number, organizationId: number, updates: Partial<InsertAutomation>): Promise<Automation>;
|
|
deleteAutomation(id: number, organizationId: number): Promise<void>;
|
|
|
|
// Task Tab Values (per-task data for custom modules)
|
|
getTaskTabValues(taskId: number, tabId: number): Promise<TaskTabValue | undefined>;
|
|
getTaskTabValuesByTask(taskId: number): Promise<TaskTabValue[]>;
|
|
upsertTaskTabValues(taskId: number, tabId: number, values: Record<string, any>): Promise<TaskTabValue>;
|
|
|
|
// Organization API Keys (MCP)
|
|
createApiKey(organizationId: number, createdBy: number, label: string, scopes?: ApiKeyScopes | null, botId?: number | null): Promise<{ key: string; record: OrganizationApiKey }>;
|
|
updateApiKey(id: number, organizationId: number, data: { label?: string; scopes?: ApiKeyScopes | null }): Promise<OrganizationApiKey | undefined>;
|
|
listApiKeys(organizationId: number): Promise<OrganizationApiKey[]>;
|
|
deleteApiKey(id: number, organizationId: number): Promise<void>;
|
|
getApiKeyByHash(rawKey: string): Promise<OrganizationApiKey | undefined>;
|
|
getApiKeyByLegacyHash(rawKey: string): Promise<OrganizationApiKey | undefined>;
|
|
touchApiKey(id: number): Promise<void>;
|
|
getApiKeyByBotId(botId: number, organizationId: number): Promise<OrganizationApiKey | undefined>;
|
|
setApiKeyActive(id: number, organizationId: number, isActive: boolean): Promise<void>;
|
|
detachApiKeyFromBot(id: number, organizationId: number): Promise<void>;
|
|
|
|
// Task Relations
|
|
upsertTaskRelation(data: { parentTaskId: number; childTaskId: number; fieldId?: number | null; organizationId: number }): Promise<TaskRelation>;
|
|
|
|
// Task Roles
|
|
getTaskRoles(taskId: number, organizationId: number): Promise<Array<TaskRole & { role: { id: number; name: string; parentId: number | null } }>>;
|
|
addTaskRole(taskId: number, roleId: number, organizationId: number): Promise<TaskRole>;
|
|
removeTaskRole(taskId: number, roleId: number, organizationId: number): Promise<void>;
|
|
|
|
// Task Assignees (multiple users)
|
|
getTaskAssignees(taskId: number, organizationId: number): Promise<Array<TaskAssignee & { user: { id: number; firstName: string | null; lastName: string | null; email: string } }>>;
|
|
addTaskAssignee(taskId: number, userId: number, organizationId: number): Promise<TaskAssignee>;
|
|
removeTaskAssignee(taskId: number, userId: number, organizationId: number): Promise<void>;
|
|
|
|
// Task User Access
|
|
getTaskUserAccess(taskId: number, organizationId: number): Promise<Array<TaskUserAccess & { user: { id: number; firstName: string | null; lastName: string | null; email: string } }>>;
|
|
recordTaskInteraction(taskId: number, userId: number, organizationId: number, grantedVia: string, roleId?: number | null): Promise<void>;
|
|
recordTaskInteractionAuto(taskId: number, userId: number, organizationId: number): Promise<void>;
|
|
upsertTaskUserAccess(taskId: number, userId: number, organizationId: number, grantedVia: string): Promise<void>;
|
|
recordTransitionAccess(taskId: number, userId: number, organizationId: number, roleId: number | null, statusId: number): Promise<void>;
|
|
revokeTaskUserAccess(taskId: number, userId: number, organizationId: number): Promise<void>;
|
|
canUserAccessTask(taskId: number, userId: number, organizationId: number, appRole: string): Promise<boolean>;
|
|
getAccessibleTaskIds(userId: number, organizationId: number, appRole: string): Promise<Set<number> | null>;
|
|
resolveTaskAccessGrant(taskId: number, userId: number, organizationId: number): Promise<{ grantedVia: string; roleId: number | null }>;
|
|
|
|
// Form Access Rules
|
|
getFormAccessRules(formId: number, organizationId: number): Promise<import('@shared/schema').FormAccessRule[]>;
|
|
createFormAccessRule(data: import('@shared/schema').InsertFormAccessRule): Promise<import('@shared/schema').FormAccessRule>;
|
|
updateFormAccessRule(id: number, organizationId: number, updates: Partial<Pick<import('@shared/schema').FormAccessRule, 'accessLevel'>>): Promise<import('@shared/schema').FormAccessRule>;
|
|
deleteFormAccessRule(id: number, organizationId: number): Promise<void>;
|
|
transferFormOwnership(formId: number, organizationId: number, newAuthorId: number): Promise<void>;
|
|
canUserAccessForm(userId: number, formId: number, organizationId: number, requiredLevel?: 'participate' | 'view_all' | 'admin'): Promise<boolean>;
|
|
|
|
deleteTaskRelationByField(fieldId: number, taskId: number, organizationId: number): Promise<void>;
|
|
getTaskRelations(taskId: number, organizationId: number): Promise<TaskRelation[]>;
|
|
|
|
// Task Reminders
|
|
getTaskReminders(taskId: number, organizationId: number): Promise<TaskReminder[]>;
|
|
createTaskReminder(data: InsertTaskReminder): Promise<TaskReminder>;
|
|
deleteTaskReminder(id: number, organizationId: number): Promise<void>;
|
|
getDueReminders(): Promise<TaskReminder[]>;
|
|
markReminderSent(id: number): Promise<void>;
|
|
getUsersByRole(role: string, organizationId: number): Promise<SafeUser[]>;
|
|
getUsersByOrgRoleId(roleId: number, organizationId: number): Promise<SafeUser[]>;
|
|
|
|
// Task Audit Log
|
|
addTaskAuditLog(entry: InsertTaskAuditLog): Promise<TaskAuditLog>;
|
|
getTaskAuditLog(taskId: number, organizationId: number): Promise<TaskAuditLog[]>;
|
|
|
|
// Task Views
|
|
recordTaskView(taskId: number, userId: number, organizationId: number): Promise<void>;
|
|
|
|
// Roles
|
|
getRoles(organizationId: number): Promise<(import('@shared/schema').Role & { memberCount: number; members: { id: number; userId: number; user: { id: number; firstName: string; lastName: string; email: string } }[]; manager: { id: number; firstName: string; lastName: string; middleName: string | null; email: string } | null })[]>;
|
|
getRole(id: number, organizationId: number): Promise<import('@shared/schema').Role | undefined>;
|
|
createRole(data: { organizationId: number; name: string; description?: string | null; parentId?: number | null; managerId?: number | null }): Promise<import('@shared/schema').Role>;
|
|
updateRole(id: number, organizationId: number, updates: { name?: string; description?: string | null; parentId?: number | null; managerId?: number | null }): Promise<import('@shared/schema').Role>;
|
|
deleteRole(id: number, organizationId: number): Promise<void>;
|
|
getRoleMembers(roleId: number, organizationId: number): Promise<(import('@shared/schema').Role & { members: { id: number; userId: number; user: { id: number; firstName: string; lastName: string; email: string } }[]; manager: { id: number; firstName: string; lastName: string; middleName: string | null; email: string } | null })>;
|
|
addRoleMember(roleId: number, userId: number, organizationId: number): Promise<void>;
|
|
removeRoleMember(roleId: number, userId: number, organizationId: number): Promise<void>;
|
|
getRoleMembersByRole(roleId: number): Promise<{ id: number; userId: number; createdAt: Date | null }[]>;
|
|
getUserRoles(userId: number, organizationId: number): Promise<import('@shared/schema').Role[]>;
|
|
|
|
// Super Admins
|
|
getSuperAdminByEmail(email: string): Promise<import('@shared/schema').SuperAdmin | undefined>;
|
|
getSuperAdminById(id: number): Promise<import('@shared/schema').SuperAdmin | undefined>;
|
|
getAllSuperAdmins(): Promise<import('@shared/schema').SuperAdmin[]>;
|
|
createSuperAdmin(data: import('@shared/schema').InsertSuperAdmin): Promise<import('@shared/schema').SuperAdmin>;
|
|
deleteSuperAdmin(id: number): Promise<void>;
|
|
getSuperAdminCount(): Promise<number>;
|
|
updateSuperAdminLastLogin(id: number): Promise<void>;
|
|
updateSuperAdminPassword(id: number, passwordHash: string): Promise<void>;
|
|
getAllOrganizationsWithStats(): Promise<Array<import('@shared/schema').Organization & { totalUsers: number; activeUsers: number; totalTasks: number; lastActivity: Date | null; billingBalance: string; billingCurrency: string }>>;
|
|
updateOrganization(id: number, updates: Partial<import('@shared/schema').Organization>): Promise<import('@shared/schema').Organization>;
|
|
getOrganizationDetailedStats(organizationId: number): Promise<{ forms: number; tasks: number; totalUsers: number; activeUsers: number; lastActivity: Date | null }>;
|
|
|
|
// Billing
|
|
getBillingSettings(organizationId: number): Promise<import('@shared/schema').OrganizationBilling | null>;
|
|
getOrCreateBillingSettings(organizationId: number): Promise<import('@shared/schema').OrganizationBilling>;
|
|
updateBillingSettings(organizationId: number, updates: Partial<import('@shared/schema').OrganizationBilling>): Promise<import('@shared/schema').OrganizationBilling>;
|
|
addBillingCredit(organizationId: number, amount: number, description: string, createdBy?: number): Promise<import('@shared/schema').BillingTransaction>;
|
|
getBillingTransactions(organizationId: number, limit?: number): Promise<import('@shared/schema').BillingTransaction[]>;
|
|
setBillingBlocked(organizationId: number, blocked: boolean): Promise<void>;
|
|
getBillingSummary(organizationId: number): Promise<{ balance: string; pricePerUser: string; currency: string; nextBillingDate: string | null; billingBlocked: boolean; activeUsers: number; estimatedCharge: string }>;
|
|
processBillingCycle(): Promise<void>;
|
|
|
|
// RAG Settings
|
|
getRagSettings(organizationId: number): Promise<RagSetting | undefined>;
|
|
upsertRagSettings(organizationId: number, updates: Partial<Omit<RagSetting, 'organizationId' | 'updatedAt'>>): Promise<RagSetting>;
|
|
|
|
// Embedding Queue
|
|
enqueueEmbedding(organizationId: number, entityType: 'form' | 'task' | 'task_message', entityId: number, operation?: 'upsert' | 'delete'): Promise<void>;
|
|
getPendingEmbeddingQueue(limit?: number): Promise<Array<{ id: number; organizationId: number; entityType: 'form' | 'task' | 'task_message'; entityId: number; operation: 'upsert' | 'delete' }>>;
|
|
markEmbeddingQueueProcessed(ids: number[]): Promise<void>;
|
|
clearEmbeddingQueue(): Promise<void>;
|
|
|
|
// LLM Providers
|
|
getLlmProviders(organizationId: number): Promise<LlmProvider[]>;
|
|
getLlmProvider(id: number, organizationId: number): Promise<LlmProvider | undefined>;
|
|
createLlmProvider(data: InsertLlmProvider): Promise<LlmProvider>;
|
|
updateLlmProvider(id: number, organizationId: number, updates: Partial<Omit<LlmProvider, 'id' | 'organizationId' | 'createdAt'>>): Promise<LlmProvider>;
|
|
deleteLlmProvider(id: number, organizationId: number): Promise<void>;
|
|
|
|
// System Config
|
|
getSystemConfig(key: string): Promise<string | null>;
|
|
setSystemConfig(key: string, value: string): Promise<void>;
|
|
|
|
// Web Push
|
|
registerWebPushSubscription(userId: number, organizationId: number, endpoint: string, subscription: string): Promise<void>;
|
|
unregisterWebPushSubscription(endpoint: string): Promise<void>;
|
|
getWebPushSubscriptions(userId: number, organizationId: number): Promise<any[]>;
|
|
getWebPushSubscriptionsByOrganization(organizationId: number): Promise<any[]>;
|
|
clearAllWebPushSubscriptions(): Promise<number>;
|
|
}
|
|
|
|
export { DatabaseStorage, storage } from "./storage/index";
|