refactor(api-server): move meetings SQL into db.knowledge domain methods
Replace inline queryAll calls in routes-meetings.ts with two new domain methods on db.knowledge: listMeetings (powers GET /api/companies/:companyId/meetings) and getMeeting (used by the PATCH meeting handler). The MeetingListRow shape mirrors the historical inline projection so HTTP responses stay byte-stable. Also adds listKnowledgeEntries here for use by routes-misc.
This commit is contained in:
1 parent
79e57567b2
commit
de02351168
3 files changed
+83
-20
No files matched your search
@@ -2,15 +2,6 @@ import { z } from "zod";
|
||||
import { validateTaskCreation } from "../task-quality-gates";
|
||||
import type { AgentApiServer } from "./server-core";
|
||||
|
||||
type MeetingRow = {
|
||||
id: string; companyId: string; type: string; title: string;
|
||||
organizerAgentId: string; participantAgentIds: string;
|
||||
scheduledAt: string; durationMinutes: number;
|
||||
agendaJson: string; notesJson: string | null;
|
||||
decisionsJson: string | null; actionItemsJson: string | null;
|
||||
status: string; createdAt: string; updatedAt: string;
|
||||
};
|
||||
|
||||
export function registerMeetingRoutes(server: AgentApiServer) {
|
||||
const db = server.db;
|
||||
const onDomainChanged = server.onDomainChanged;
|
||||
@@ -70,19 +61,17 @@ export function registerMeetingRoutes(server: AgentApiServer) {
|
||||
server.json(res, 403, { error: "Company mismatch" });
|
||||
return;
|
||||
}
|
||||
const meetings = db.queryAll<MeetingRow>(
|
||||
"select id, company_id as companyId, type, title, organizer_agent_id as organizerAgentId, participant_agent_ids as participantAgentIds, scheduled_at as scheduledAt, duration_minutes as durationMinutes, agenda_json as agendaJson, notes_json as notesJson, decisions_json as decisionsJson, action_items_json as actionItemsJson, status, created_at as createdAt, updated_at as updatedAt from meetings where company_id = ? order by scheduled_at desc",
|
||||
token.companyId,
|
||||
);
|
||||
const meetings = db.listMeetings(token.companyId);
|
||||
server.json(res, 200, meetings);
|
||||
});
|
||||
|
||||
server.addRoute("PATCH", "/api/meetings/:meetingId", (_req, res, params, token, body) => {
|
||||
const rows = db.queryAll<MeetingRow>(
|
||||
"select id, company_id as companyId, type, title, organizer_agent_id as organizerAgentId, participant_agent_ids as participantAgentIds, scheduled_at as scheduledAt, duration_minutes as durationMinutes, agenda_json as agendaJson, notes_json as notesJson, decisions_json as decisionsJson, action_items_json as actionItemsJson, status, created_at as createdAt, updated_at as updatedAt from meetings where id = ? and company_id = ? limit 1",
|
||||
params.meetingId, token.companyId,
|
||||
);
|
||||
const existing = rows[0] ?? null;
|
||||
const meetingId = params.meetingId;
|
||||
if (!meetingId) {
|
||||
server.json(res, 400, { error: "Missing meetingId" });
|
||||
return;
|
||||
}
|
||||
const existing = db.getMeeting(meetingId, token.companyId);
|
||||
if (!existing) {
|
||||
server.json(res, 404, { error: "Meeting not found" });
|
||||
return;
|
||||
@@ -121,7 +110,7 @@ export function registerMeetingRoutes(server: AgentApiServer) {
|
||||
}
|
||||
}
|
||||
db.saveMeeting({
|
||||
id: params.meetingId,
|
||||
id: meetingId,
|
||||
companyId: token.companyId,
|
||||
type: data.type ?? "department_sync",
|
||||
title: data.title ?? "Meeting",
|
||||
|
||||
@@ -111,8 +111,11 @@ export class AppDatabase extends AppDatabaseBase {
|
||||
|
||||
saveMeeting(input: { id?: string | null; companyId: string; type: string; title: string; organizerAgentId?: string | null; participantAgentIds?: string; scheduledAt: string; durationMinutes?: number; agendaJson?: string; notesJson?: string; decisionsJson?: string; actionItemsJson?: string; status?: string }) { return this.knowledgeMod.saveMeeting(input); }
|
||||
deleteMeeting(id: string, companyId: string) { this.knowledgeMod.deleteMeeting(id, companyId); }
|
||||
listMeetings(companyId: string) { return this.knowledgeMod.listMeetings(companyId); }
|
||||
getMeeting(meetingId: string, companyId: string) { return this.knowledgeMod.getMeeting(meetingId, companyId); }
|
||||
saveKnowledgeEntry(input: { id?: string | null; companyId: string; category: string; topic: string; content: string; authorAgentId?: string | null; importance?: string; tagsJson?: string; referencedEntityType?: string | null; referencedEntityId?: string | null; sourceRunId?: string | null }) { return this.knowledgeMod.saveKnowledgeEntry(input); }
|
||||
deleteKnowledgeEntry(id: string, companyId: string) { this.knowledgeMod.deleteKnowledgeEntry(id, companyId); }
|
||||
listKnowledgeEntries(companyId: string) { return this.knowledgeMod.listKnowledgeEntries(companyId); }
|
||||
saveSprint(input: { id?: string | null; companyId: string; name: string; goal?: string; startDate: string; endDate: string; status?: string; retrospectiveNotes?: string; velocityPoints?: number; completedPoints?: number }) { return this.knowledgeMod.saveSprint(input); }
|
||||
deleteSprint(id: string, companyId: string) { this.knowledgeMod.deleteSprint(id, companyId); }
|
||||
|
||||
|
||||
@@ -2,11 +2,71 @@ import type { DatabaseSync } from "node:sqlite";
|
||||
import type { ReadAll } from "./helpers";
|
||||
import { ensureId, nowIso } from "./helpers";
|
||||
|
||||
/**
|
||||
* Meeting row shape returned by listMeetings / getMeeting — used by
|
||||
* meeting routes. Mirrors the historical inline SQL projection so HTTP
|
||||
* response bodies stay byte-stable.
|
||||
*/
|
||||
export type MeetingListRow = {
|
||||
id: string;
|
||||
companyId: string;
|
||||
type: string;
|
||||
title: string;
|
||||
organizerAgentId: string;
|
||||
participantAgentIds: string;
|
||||
scheduledAt: string;
|
||||
durationMinutes: number;
|
||||
agendaJson: string;
|
||||
notesJson: string | null;
|
||||
decisionsJson: string | null;
|
||||
actionItemsJson: string | null;
|
||||
status: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
const MEETING_LIST_COLUMNS =
|
||||
"select id, company_id as companyId, type, title, organizer_agent_id as organizerAgentId, participant_agent_ids as participantAgentIds, scheduled_at as scheduledAt, duration_minutes as durationMinutes, agenda_json as agendaJson, notes_json as notesJson, decisions_json as decisionsJson, action_items_json as actionItemsJson, status, created_at as createdAt, updated_at as updatedAt from meetings";
|
||||
|
||||
/**
|
||||
* Knowledge entry row shape returned by listKnowledgeEntries — used by
|
||||
* GET /api/companies/:companyId/knowledge. Mirrors the historical inline
|
||||
* SQL projection so HTTP responses stay byte-stable.
|
||||
*/
|
||||
export type KnowledgeListRow = {
|
||||
id: string;
|
||||
companyId: string;
|
||||
category: string;
|
||||
topic: string;
|
||||
content: string;
|
||||
authorAgentId: string;
|
||||
importance: string;
|
||||
tagsJson: string;
|
||||
referencedEntityType: string | null;
|
||||
referencedEntityId: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export function buildKnowledgeMethods(
|
||||
getDb: () => DatabaseSync,
|
||||
_readAll: ReadAll,
|
||||
readAll: ReadAll,
|
||||
) {
|
||||
return {
|
||||
listMeetings(companyId: string): MeetingListRow[] {
|
||||
return readAll<MeetingListRow>(
|
||||
`${MEETING_LIST_COLUMNS} where company_id = ? order by scheduled_at desc`,
|
||||
companyId,
|
||||
);
|
||||
},
|
||||
|
||||
getMeeting(meetingId: string, companyId: string): MeetingListRow | null {
|
||||
const row = getDb()
|
||||
.prepare(`${MEETING_LIST_COLUMNS} where id = ? and company_id = ? limit 1`)
|
||||
.get(meetingId, companyId) as MeetingListRow | undefined;
|
||||
return row ?? null;
|
||||
},
|
||||
|
||||
saveMeeting(input: {
|
||||
id?: string | null; companyId: string; type: string; title: string; organizerAgentId?: string | null;
|
||||
participantAgentIds?: string; scheduledAt: string; durationMinutes?: number;
|
||||
@@ -57,6 +117,17 @@ export function buildKnowledgeMethods(
|
||||
getDb().prepare("delete from knowledge_base where id = ? and company_id = ?").run(id, companyId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns all knowledge entries for a company, ordered by updated_at desc.
|
||||
* Used by GET /api/companies/:companyId/knowledge.
|
||||
*/
|
||||
listKnowledgeEntries(companyId: string): KnowledgeListRow[] {
|
||||
return readAll<KnowledgeListRow>(
|
||||
"select id, company_id as companyId, category, topic, content, author_agent_id as authorAgentId, importance, tags_json as tagsJson, referenced_entity_type as referencedEntityType, referenced_entity_id as referencedEntityId, created_at as createdAt, updated_at as updatedAt from knowledge_base where company_id = ? order by updated_at desc",
|
||||
companyId,
|
||||
);
|
||||
},
|
||||
|
||||
saveSprint(input: {
|
||||
id?: string | null; companyId: string; name: string; goal?: string;
|
||||
startDate: string; endDate: string; status?: string; retrospectiveNotes?: string;
|
||||
|
||||
Reference in new issue
Block a user