6.7 KiB
Handoff Report — Explorer 3, Milestone 2
1. Observation
Direct observations from codebase inspection:
-
Prisma Models: File:
apps/backend/prisma/schema.prisma, lines 638–658:model Menu { id Int @id @default(autoincrement()) name String @unique // e.g., "header", "footer" payload Json? isActive Boolean @default(true) items MenuItem[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model MenuItem { id Int @id @default(autoincrement()) menuId Int menu Menu @relation(fields: [menuId], references: [id], onDelete: Cascade) label String url String order Int @default(0) translations MenuItemTranslation[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } -
TypeScript Interfaces: File:
packages/types/index.ts, lines 195–208:export interface MenuItem { id: number label: string url: string order: number translations?: any[] } export interface Menu { id: number name: string items: MenuItem[] payload?: any } -
Elysia Backend Routes: File:
apps/backend/src/routes/menus.ts, lines 34–58:const { name, items } = body as { name: string; items?: { label: string; url: string; order: number }[] }; ... body: t.Object({ name: t.String(), items: t.Optional(t.Array(t.Object({ label: t.String(), url: t.String(), order: t.Number() }))) })And lines 62–66:
const { items, payload, isActive } = body as { payload?: any; isActive?: boolean; items: { id?: number; label: string; url: string; order: number; translations?: { langCode: string; label: string }[] }[] }; -
MCP Validation Helper: File:
apps/mcp-server/menu-tools.ts, lines 158–170:function validateMenuItems(items: any) { const issues: string[] = []; const warnings: string[] = []; if (!Array.isArray(items)) { issues.push("items must be an array"); return { issues, warnings }; } items.forEach((item, index) => { if (!isPlainObject(item)) { issues.push(`items[${index}] must be a plain object`); return; } -
MCP Schema: File:
apps/mcp-server/menu-toolkit.ts, lines 34–74, the definition ofupsert_menu:{ name: "upsert_menu", description: "Update or create a complete menu by replacing its items. Optional payload/isActive support covers tree-based menus and menu state. Uses proper diff & sync for translations.", inputSchema: { type: "object", properties: { name: { type: "string", description: "Name of the menu (e.g. main, footer-explore)" }, dryRun: { type: "boolean", description: "Preview the mutation without saving it" }, payload: { oneOf: [{ type: "object" }, { type: "array" }], description: "Optional menu payload for tree-based menus such as main" }, isActive: { type: "boolean", description: "Optional active state for the menu" }, items: { type: "array", description: "Array of menu items", items: { type: "object", properties: { id: { type: "number", description: "ID of existing item (optional)" }, label: { type: "string", description: "Label of the menu item" }, url: { type: "string", description: "URL of the menu item" }, order: { type: "number", description: "Order sequence" }, translations: {
2. Logic Chain
- Database Schema: To store
rootImagefor Menu, andcolumnImage/hoverImagefor MenuItem, we must add nullable string fields (String?) to these models inschema.prisma. - TypeScript Declarations: The TypeScript project imports standard types from
@homaroma/types(packages/types/index.ts). These interfaces must match the database schemas by addingrootImage?: string | null,columnImage?: string | null, andhoverImage?: string | null. - API Validation: The backend validates POST/PUT requests using Elysia TypeBox (
t.Object). Adding the new fields as optional nullable strings (t.Optional(t.Nullable(t.String()))) enables the backend to validate incoming values correctly while maintaining backward compatibility. - API Mapping: The database update transactions inside
menus.tsmap the validated payload to Prisma database queries. We must update thecreateandupdatequeries to assignrootImagefor Menu, andcolumnImage/hoverImagefor MenuItem. - MCP Schema & Helper: The MCP toolkit contains utility validation for items before sending PUT requests. Adding validation rules in
validateMenuItemsprevents MCP validation blocks. UpdatingMENU_TOOL_DEFINITIONSexposes the new input parameters to AI clients interacting withupsert_menu.
3. Caveats
- Seeding Script: The seed file (
apps/backend/prisma/seed.cjs) upserts default core menus. It does not contain image values, but since the new fields are fully optional, no updates are strictly required there. - Frontend Fallbacks: Client code (SPA and Website) must handle null values safely. The actual layout rendering logic (DesktopMegaMenu) is a separate frontend concern that must be updated dynamically to read these fields.
- Transpiled Route Artifacts: There are transpiled
.jsand.d.tsfiles inside the routes folder, meaning a clean build step is required after modifications to typescript source files.
4. Conclusion
The strategy outlines a safe, fully backward-compatible database, route, and MCP tool update. The exact changes required in the four files have been mapped and documented in detail in analysis.md. The next step is to delegate the implementation tasks to the Implementer agent.
5. Verification Method
To independently verify the final implementation:
- Schema Check:
Confirm that the prisma client generates successfully by running:
bunx prisma generate - Database Migration Status:
Run the following command to ensure migrations are applied cleanly without conflicts:
bunx prisma migrate status - Route Integration & Tests:
Execute the backend build script to verify there are no syntax or type mismatch errors:
Execute the workspace test command:
npm run build --workspace apps/backendnpm run test