feat(memo): add and delete sections via RPC

Add memo.addSection and memo.deleteSection RPC methods with full-stack
implementation: contract types, Zod schemas, DB queries, RPC handlers,
UI buttons, and tests.

- memo.addSection: creates a new empty section, supports positional
  insert after a given section via afterSectionId
- memo.deleteSection: removes a section and cascades cleanup of its
  annotations, citations, and section reviews
- Outline sidebar: per-section delete button, + Add Section button
- Article area: + Add Section button after last section
- 9 new tests (15 total memo tests, 48 project-wide)
This commit is contained in:
2026-05-15 00:27:09 -04:00
parent 0624026af3
commit 0e5a31866f
6 changed files with 346 additions and 12 deletions

View File

@@ -211,6 +211,15 @@ export type RpcRequestMap = {
"model.deleteRow": { companyId: string; tab: string; row: number };
"model.runScenario": { companyId: string; scenario: string; overrides: Record<string, string> };
"memo.get": { companyId: string };
"memo.addSection": {
companyId: string;
title: string;
afterSectionId?: string;
};
"memo.deleteSection": {
companyId: string;
sectionId: string;
};
"memo.updateSection": {
companyId: string;
sectionId: string;
@@ -282,6 +291,12 @@ export type RpcResponseMap = {
annotations: MemoAnnotation[];
sectionReviews: MemoSectionReview[];
};
"memo.addSection": {
section: MemoSection;
};
"memo.deleteSection": {
ok: boolean;
};
"memo.updateSection": {
section: MemoSection;
status: "draft" | "review" | "final";

View File

@@ -93,6 +93,15 @@ export const RpcRequestSchemas = {
overrides: z.record(z.string()),
}),
"memo.get": z.object({ companyId: idString }),
"memo.addSection": z.object({
companyId: idString,
title: nonEmptyString,
afterSectionId: idString.optional(),
}),
"memo.deleteSection": z.object({
companyId: idString,
sectionId: idString,
}),
"memo.updateSection": z.object({
companyId: idString,
sectionId: idString,
@@ -178,6 +187,12 @@ export const RpcResponseSchemas = {
annotations: z.array(MemoAnnotationSchema),
sectionReviews: z.array(MemoSectionReviewSchema),
}),
"memo.addSection": z.object({
section: MemoSectionSchema,
}),
"memo.deleteSection": z.object({
ok: z.boolean(),
}),
"memo.updateSection": z.object({
section: MemoSectionSchema,
status: z.enum(["draft", "review", "final"]),