From 8861aa4c30c28baa56dba68c7bac27de26ae597d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Fri, 9 Oct 2026 11:22:44 -0400 Subject: [PATCH] Q204: meeting records that were never held are removed Co-Authored-By: Claude Opus 5.5 --- src/main/app/ipc-contracts/collaboration.ts | 4 --- src/main/app/ipc-handlers.ts | 4 --- .../database/migrations/109-drop-meetings.ts | 5 +++ src/main/database/schema.ts | 2 ++ src/main/services/meeting-service.ts | 36 ------------------- src/main/services/snapshot-service.ts | 1 - src/preload/index.ts | 2 -- src/shared/commands/collaboration.ts | 14 -------- src/shared/desktop-api.ts | 4 --- src/shared/domain.ts | 15 -------- src/shared/ipc.ts | 2 -- src/shared/snapshot-domain.ts | 2 -- tests/unit/domain-services.test.ts | 2 +- tests/unit/unused-records.test.ts | 8 +++++ 14 files changed, 16 insertions(+), 85 deletions(-) create mode 100644 src/main/database/migrations/109-drop-meetings.ts delete mode 100644 src/main/services/meeting-service.ts diff --git a/src/main/app/ipc-contracts/collaboration.ts b/src/main/app/ipc-contracts/collaboration.ts index 49023c09..e7e0a866 100644 --- a/src/main/app/ipc-contracts/collaboration.ts +++ b/src/main/app/ipc-contracts/collaboration.ts @@ -26,10 +26,6 @@ export const collaborationContracts = { }) satisfies z.ZodType, deleteKnowledgeEntry: z.strictObject({ orgId: id, entryId: id, deletedByEmployeeId: id }) satisfies z.ZodType, listKnowledgeRevisions: z.strictObject({ orgId: id, entryId: id }) satisfies z.ZodType, - createMeeting: z.strictObject({ - orgId: id, title: z.string(), meetingType: z.string(), scheduledAt: z.string().nullable(), durationMinutes: z.number(), agenda: z.string(), - }) satisfies z.ZodType, - deleteMeeting: z.strictObject({ orgId: id, meetingId: id }) satisfies z.ZodType, createSprint: z.strictObject({ orgId: id, name: z.string(), goal: z.string(), startDate: z.string(), endDate: z.string() }) satisfies z.ZodType, deleteSprint: z.strictObject({ orgId: id, sprintId: id }) satisfies z.ZodType, createChatSpace: z.strictObject({ diff --git a/src/main/app/ipc-handlers.ts b/src/main/app/ipc-handlers.ts index c2cd1f0b..b4b893da 100644 --- a/src/main/app/ipc-handlers.ts +++ b/src/main/app/ipc-handlers.ts @@ -23,7 +23,6 @@ import { OperationsService } from "../services/operations-service"; import { TaskExecutionService } from "../services/task-execution-service"; import { DocumentService } from "../services/document-service"; import { KnowledgeService } from "../services/knowledge-service"; -import { MeetingService } from "../services/meeting-service"; import { SprintService } from "../services/sprint-service"; import { ComposioConnectionService } from "../services/composio/composio-connection-service"; import { ConnectorGrantsService } from "../services/composio/connector-grants"; @@ -91,7 +90,6 @@ export function registerIpcHandlers(deps: IpcDeps): void { const operations = new OperationsService(deps.connection.db); const documents = new DocumentService(deps.connection.db); const knowledge = new KnowledgeService(deps.connection.db); - const meetingService = new MeetingService(deps.connection.db); const sprintService = new SprintService(deps.connection.db); const onboarding = new OnboardingService({ db: deps.connection.db, @@ -240,8 +238,6 @@ export function registerIpcHandlers(deps: IpcDeps): void { revision: r.revision, topic: r.topic, category: r.category, content: r.content, importance: r.importance, changedByType: r.changed_by_type, changedById: r.changed_by_id, reason: r.reason, createdAt: r.created_at, })))); - handle("createMeeting", (input) => mutate(() => meetingService.create(input))); - handle("deleteMeeting", (input) => mutate(() => meetingService.delete(input))); handle("createSprint", (input) => mutate(() => sprintService.create(input))); handle("deleteSprint", (input) => mutate(() => sprintService.delete(input))); handle("createApproval", (input) => mutate(() => approvals.create(input))); diff --git a/src/main/database/migrations/109-drop-meetings.ts b/src/main/database/migrations/109-drop-meetings.ts new file mode 100644 index 00000000..720cc0b2 --- /dev/null +++ b/src/main/database/migrations/109-drop-meetings.ts @@ -0,0 +1,5 @@ +// Meetings were saved but never held; the records are removed rather than kept as a promise. +export const dropMeetingsSchema = ` + drop index if exists idx_meetings_org; + drop table if exists meetings; +`; diff --git a/src/main/database/schema.ts b/src/main/database/schema.ts index 526b295e..2ba28df1 100644 --- a/src/main/database/schema.ts +++ b/src/main/database/schema.ts @@ -107,6 +107,7 @@ import { onboardingProgressSchema } from "./migrations/105-onboarding-progress"; import { viewStateSchema } from "./migrations/106-view-state"; import { searchPendingSchema } from "./migrations/107-search-pending"; import { dropAutomationRulesSchema } from "./migrations/108-drop-automation-rules"; +import { dropMeetingsSchema } from "./migrations/109-drop-meetings"; interface Migration { version: number; @@ -223,6 +224,7 @@ const MIGRATIONS: Migration[] = [ { version: 106, name: "view_state", sql: viewStateSchema }, { version: 107, name: "search_pending", sql: searchPendingSchema }, { version: 108, name: "drop_automation_rules", sql: dropAutomationRulesSchema }, + { version: 109, name: "drop_meetings", sql: dropMeetingsSchema }, ]; const SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1].version; diff --git a/src/main/services/meeting-service.ts b/src/main/services/meeting-service.ts deleted file mode 100644 index 4cdd9c43..00000000 --- a/src/main/services/meeting-service.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { CreateMeetingInput, DeleteMeetingInput } from "../../shared/commands"; -import { createId } from "../../shared/ids"; -import { AuditService } from "./audit-service"; - -export class MeetingService { - private readonly audit: AuditService; - - constructor(private readonly db: DatabaseSync) { - this.audit = new AuditService(db); - } - - create(input: CreateMeetingInput): string { - const id = createId("mtg"); - const now = new Date().toISOString(); - this.db.prepare(` - insert into meetings(id, org_id, title, meeting_type, status, scheduled_at, duration_minutes, agenda, notes, decisions, created_at, updated_at) - values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - `).run(id, input.orgId, input.title.trim(), input.meetingType, "scheduled", input.scheduledAt, input.durationMinutes, input.agenda.trim(), "", "", now, now); - this.audit.record({ - orgId: input.orgId, - entityType: "meeting", - entityId: id, - actorType: "system", - actorId: null, - action: "created", - payload: { title: input.title.trim(), meetingType: input.meetingType }, - }); - return id; - } - - delete(input: DeleteMeetingInput): void { - const result = this.db.prepare("delete from meetings where id = ? and org_id = ?").run(input.meetingId, input.orgId); - if (result.changes === 0) throw new Error("Meeting was not found."); - } -} diff --git a/src/main/services/snapshot-service.ts b/src/main/services/snapshot-service.ts index 76c4b736..d8747eaa 100644 --- a/src/main/services/snapshot-service.ts +++ b/src/main/services/snapshot-service.ts @@ -151,7 +151,6 @@ export class SnapshotService { auditEvents: recentInOrg(this.db, "audit_events", "created_at desc", 200, activeOrgId), documents: list(this.db, "documents", "updated_at desc"), knowledgeEntries: list(this.db, "knowledge_entries", "updated_at desc"), - meetings: list(this.db, "meetings", "scheduled_at desc"), sprints: list(this.db, "sprints", "start_date desc"), connectorAccounts: list(this.db, "connector_accounts", "toolkit_slug asc"), connectorGrants: list(this.db, "agent_connector_grants", "toolkit_slug asc, created_at asc"), diff --git a/src/preload/index.ts b/src/preload/index.ts index 85ca5ac1..f3df18b0 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -44,8 +44,6 @@ const api: DesktopApi = { updateKnowledgeEntry: (input) => invoke(IPC_CHANNELS.updateKnowledgeEntry, input), listDocumentVersions: (input) => invoke(IPC_CHANNELS.listDocumentVersions, input), listKnowledgeRevisions: (input) => invoke(IPC_CHANNELS.listKnowledgeRevisions, input), - createMeeting: (input) => invoke(IPC_CHANNELS.createMeeting, input), - deleteMeeting: (input) => invoke(IPC_CHANNELS.deleteMeeting, input), createSprint: (input) => invoke(IPC_CHANNELS.createSprint, input), deleteSprint: (input) => invoke(IPC_CHANNELS.deleteSprint, input), createApproval: (input) => invoke(IPC_CHANNELS.createApproval, input), diff --git a/src/shared/commands/collaboration.ts b/src/shared/commands/collaboration.ts index 6d89ec2b..7e57b032 100644 --- a/src/shared/commands/collaboration.ts +++ b/src/shared/commands/collaboration.ts @@ -104,20 +104,6 @@ export interface DeleteKnowledgeEntryInput { deletedByEmployeeId: string; } -export interface CreateMeetingInput { - orgId: string; - title: string; - meetingType: string; - scheduledAt: string | null; - durationMinutes: number; - agenda: string; -} - -export interface DeleteMeetingInput { - orgId: string; - meetingId: string; -} - export interface CreateSprintInput { orgId: string; name: string; diff --git a/src/shared/desktop-api.ts b/src/shared/desktop-api.ts index b48439d6..3131b7e6 100644 --- a/src/shared/desktop-api.ts +++ b/src/shared/desktop-api.ts @@ -19,9 +19,7 @@ import type { CreateApprovalInput, CreateDocumentInput, CreateGoalInput, - CreateMeetingInput, CreateSprintInput, - DeleteMeetingInput, DeleteSprintInput, CreateKnowledgeEntryInput, UpdateKnowledgeEntryInput, @@ -161,8 +159,6 @@ export interface DesktopApi { updateKnowledgeEntry(input: UpdateKnowledgeEntryInput): Promise>; listDocumentVersions(input: ListDocumentVersionsInput): Promise>; listKnowledgeRevisions(input: ListKnowledgeRevisionsInput): Promise>; - createMeeting(input: CreateMeetingInput): Promise>; - deleteMeeting(input: DeleteMeetingInput): Promise>; createSprint(input: CreateSprintInput): Promise>; deleteSprint(input: DeleteSprintInput): Promise>; createApproval(input: CreateApprovalInput): Promise>; diff --git a/src/shared/domain.ts b/src/shared/domain.ts index ce5b5fa4..ac853da7 100644 --- a/src/shared/domain.ts +++ b/src/shared/domain.ts @@ -244,21 +244,6 @@ export interface ApprovalRecord { decidedAt: string | null; } -export interface MeetingRecord { - id: string; - orgId: string; - title: string; - meetingType: string; - status: string; - scheduledAt: string | null; - durationMinutes: number; - agenda: string; - notes: string; - decisions: string; - createdAt: string; - updatedAt: string; -} - export interface SprintRecord { id: string; orgId: string; diff --git a/src/shared/ipc.ts b/src/shared/ipc.ts index 3e80af13..b5279e59 100644 --- a/src/shared/ipc.ts +++ b/src/shared/ipc.ts @@ -77,8 +77,6 @@ export const IPC_CHANNELS = { updateKnowledgeEntry: "agentcompany:update-knowledge-entry", listDocumentVersions: "agentcompany:list-document-versions", listKnowledgeRevisions: "agentcompany:list-knowledge-revisions", - createMeeting: "agentcompany:create-meeting", - deleteMeeting: "agentcompany:delete-meeting", createSprint: "agentcompany:create-sprint", deleteSprint: "agentcompany:delete-sprint", listConnectorCatalog: "agentcompany:list-connector-catalog", diff --git a/src/shared/snapshot-domain.ts b/src/shared/snapshot-domain.ts index f35ea324..ac3f6c11 100644 --- a/src/shared/snapshot-domain.ts +++ b/src/shared/snapshot-domain.ts @@ -28,7 +28,6 @@ import type { FileObjectRecord, GoalRecord, KnowledgeEntryRecord, - MeetingRecord, MigrationReportRecord, OrganizationRecord, PolicyRuleRecord, @@ -126,7 +125,6 @@ export interface AppSnapshot { auditEvents: AuditEventRecord[]; documents: DocumentRecord[]; knowledgeEntries: KnowledgeEntryRecord[]; - meetings: MeetingRecord[]; sprints: SprintRecord[]; connectorAccounts: ConnectorAccountRecord[]; connectorGrants: ConnectorGrantRecord[]; diff --git a/tests/unit/domain-services.test.ts b/tests/unit/domain-services.test.ts index 84053a1c..0eec1fb7 100644 --- a/tests/unit/domain-services.test.ts +++ b/tests/unit/domain-services.test.ts @@ -36,7 +36,7 @@ describe("domain services", () => { const connection = createConnection(); const rows = connection.db.prepare("select version from schema_migrations order by version asc").all() as Array<{ version: number }>; - expect(rows.map((row) => row.version)).toEqual([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]); + expect(rows.map((row) => row.version)).toEqual([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, 109]); connection.close(); }); diff --git a/tests/unit/unused-records.test.ts b/tests/unit/unused-records.test.ts index 0133f4d9..3c801ad7 100644 --- a/tests/unit/unused-records.test.ts +++ b/tests/unit/unused-records.test.ts @@ -13,3 +13,11 @@ test("automation rules are gone: no table, no channels", () => { expect(tables.map((row) => row.name)).not.toContain("automation_rules"); expect(Object.keys(IPC_CHANNELS).filter((key) => /automation/i.test(key))).toEqual([]); }); + +test("meeting records are gone: no table, no channels", () => { + const connection = new DatabaseConnection(join(tmpdir(), `agentcompany-new-${randomUUID()}.db`)); + const tables = connection.db.prepare("select name from sqlite_master where type = 'table'").all() as Array<{ name: string }>; + connection.close(); + expect(tables.map((row) => row.name)).not.toContain("meetings"); + expect(Object.keys(IPC_CHANNELS).filter((key) => /meeting/i.test(key))).toEqual([]); +});