From af2bd744fba7a09f4c3bde1503d8c5ddb265a83a Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Mon, 23 Mar 2026 17:44:05 +0200 Subject: [PATCH] feat: add Zero schema with 6 table definitions and relationships - Create zero/tables/inbox.ts (notifications) - Create zero/tables/documents.ts (documents, search_source_connectors) - Create zero/tables/chat.ts (new_chat_messages, chat_comments, chat_session_state) - Create zero/schema.ts (combines tables, defines relationships, exports zql) - Consolidate Zero type augmentations into types/zero.d.ts --- .../types/{zero-auth.d.ts => zero.d.ts} | 3 ++ surfsense_web/zero/schema.ts | 41 +++++++++++++++++++ surfsense_web/zero/tables/chat.ts | 34 +++++++++++++++ surfsense_web/zero/tables/documents.ts | 31 ++++++++++++++ surfsense_web/zero/tables/inbox.ts | 16 ++++++++ 5 files changed, 125 insertions(+) rename surfsense_web/types/{zero-auth.d.ts => zero.d.ts} (70%) create mode 100644 surfsense_web/zero/schema.ts create mode 100644 surfsense_web/zero/tables/chat.ts create mode 100644 surfsense_web/zero/tables/documents.ts create mode 100644 surfsense_web/zero/tables/inbox.ts diff --git a/surfsense_web/types/zero-auth.d.ts b/surfsense_web/types/zero.d.ts similarity index 70% rename from surfsense_web/types/zero-auth.d.ts rename to surfsense_web/types/zero.d.ts index 7d5007b23..5b74bce33 100644 --- a/surfsense_web/types/zero-auth.d.ts +++ b/surfsense_web/types/zero.d.ts @@ -1,3 +1,5 @@ +import type { Schema } from "@/zero/schema"; + export type Context = | { userId: string; @@ -7,5 +9,6 @@ export type Context = declare module "@rocicorp/zero" { interface DefaultTypes { context: Context; + schema: Schema; } } diff --git a/surfsense_web/zero/schema.ts b/surfsense_web/zero/schema.ts new file mode 100644 index 000000000..c1f7cf951 --- /dev/null +++ b/surfsense_web/zero/schema.ts @@ -0,0 +1,41 @@ +import { createSchema, createBuilder, relationships } from "@rocicorp/zero"; +import { chatCommentTable, chatSessionStateTable, newChatMessageTable } from "./tables/chat"; +import { documentTable, searchSourceConnectorTable } from "./tables/documents"; +import { notificationTable } from "./tables/inbox"; + +const chatCommentRelationships = relationships(chatCommentTable, ({ one }) => ({ + message: one({ + sourceField: ["messageId"], + destSchema: newChatMessageTable, + destField: ["id"], + }), + parent: one({ + sourceField: ["parentId"], + destSchema: chatCommentTable, + destField: ["id"], + }), +})); + +const newChatMessageRelationships = relationships(newChatMessageTable, ({ many }) => ({ + comments: many({ + sourceField: ["id"], + destSchema: chatCommentTable, + destField: ["messageId"], + }), +})); + +export const schema = createSchema({ + tables: [ + notificationTable, + documentTable, + searchSourceConnectorTable, + newChatMessageTable, + chatCommentTable, + chatSessionStateTable, + ], + relationships: [chatCommentRelationships, newChatMessageRelationships], +}); + +export type Schema = typeof schema; + +export const zql = createBuilder(schema); diff --git a/surfsense_web/zero/tables/chat.ts b/surfsense_web/zero/tables/chat.ts new file mode 100644 index 000000000..b8b7fbb93 --- /dev/null +++ b/surfsense_web/zero/tables/chat.ts @@ -0,0 +1,34 @@ +import { table, string, number, json } from "@rocicorp/zero"; + +export const newChatMessageTable = table("new_chat_messages") + .columns({ + id: number(), + role: string(), + content: json(), + threadId: number().from("thread_id"), + authorId: string().optional().from("author_id"), + createdAt: number().from("created_at"), + }) + .primaryKey("id"); + +export const chatCommentTable = table("chat_comments") + .columns({ + id: number(), + messageId: number().from("message_id"), + threadId: number().from("thread_id"), + parentId: number().optional().from("parent_id"), + authorId: string().optional().from("author_id"), + content: string(), + createdAt: number().from("created_at"), + updatedAt: number().from("updated_at"), + }) + .primaryKey("id"); + +export const chatSessionStateTable = table("chat_session_state") + .columns({ + id: number(), + threadId: number().from("thread_id"), + aiRespondingToUserId: string().optional().from("ai_responding_to_user_id"), + updatedAt: number().from("updated_at"), + }) + .primaryKey("id"); diff --git a/surfsense_web/zero/tables/documents.ts b/surfsense_web/zero/tables/documents.ts new file mode 100644 index 000000000..c50fc959b --- /dev/null +++ b/surfsense_web/zero/tables/documents.ts @@ -0,0 +1,31 @@ +import { table, string, number, boolean, json } from "@rocicorp/zero"; + +export const documentTable = table("documents") + .columns({ + id: number(), + title: string(), + documentType: string().from("document_type"), + searchSpaceId: number().from("search_space_id"), + createdById: string().optional().from("created_by_id"), + status: json(), + createdAt: number().from("created_at"), + }) + .primaryKey("id"); + +export const searchSourceConnectorTable = table("search_source_connectors") + .columns({ + id: number(), + name: string(), + connectorType: string().from("connector_type"), + isIndexable: boolean().from("is_indexable"), + lastIndexedAt: number().optional().from("last_indexed_at"), + config: json(), + enableSummary: boolean().from("enable_summary"), + periodicIndexingEnabled: boolean().from("periodic_indexing_enabled"), + indexingFrequencyMinutes: number().optional().from("indexing_frequency_minutes"), + nextScheduledAt: number().optional().from("next_scheduled_at"), + searchSpaceId: number().from("search_space_id"), + userId: string().from("user_id"), + createdAt: number().from("created_at"), + }) + .primaryKey("id"); diff --git a/surfsense_web/zero/tables/inbox.ts b/surfsense_web/zero/tables/inbox.ts new file mode 100644 index 000000000..3eca9522f --- /dev/null +++ b/surfsense_web/zero/tables/inbox.ts @@ -0,0 +1,16 @@ +import { table, string, number, boolean, json } from "@rocicorp/zero"; + +export const notificationTable = table("notifications") + .columns({ + id: number(), + userId: string().from("user_id"), + searchSpaceId: number().optional().from("search_space_id"), + type: string(), + title: string(), + message: string(), + read: boolean(), + metadata: json().optional(), + createdAt: number().from("created_at"), + updatedAt: number().optional().from("updated_at"), + }) + .primaryKey("id");