# Handoff Report — Explorer 3, Milestone 2 ## 1. Observation Direct observations from codebase inspection: 1. **Prisma Models**: File: `apps/backend/prisma/schema.prisma`, lines 638–658: ```prisma 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 } ``` 2. **TypeScript Interfaces**: File: `packages/types/index.ts`, lines 195–208: ```typescript export interface MenuItem { id: number label: string url: string order: number translations?: any[] } export interface Menu { id: number name: string items: MenuItem[] payload?: any } ``` 3. **Elysia Backend Routes**: File: `apps/backend/src/routes/menus.ts`, lines 34–58: ```typescript 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: ```typescript const { items, payload, isActive } = body as { payload?: any; isActive?: boolean; items: { id?: number; label: string; url: string; order: number; translations?: { langCode: string; label: string }[] }[] }; ``` 4. **MCP Validation Helper**: File: `apps/mcp-server/menu-tools.ts`, lines 158–170: ```typescript 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; } ``` 5. **MCP Schema**: File: `apps/mcp-server/menu-toolkit.ts`, lines 34–74, the definition of `upsert_menu`: ```typescript { 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 1. **Database Schema**: To store `rootImage` for Menu, and `columnImage`/`hoverImage` for MenuItem, we must add nullable string fields (`String?`) to these models in `schema.prisma`. 2. **TypeScript Declarations**: The TypeScript project imports standard types from `@homaroma/types` (`packages/types/index.ts`). These interfaces must match the database schemas by adding `rootImage?: string | null`, `columnImage?: string | null`, and `hoverImage?: string | null`. 3. **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. 4. **API Mapping**: The database update transactions inside `menus.ts` map the validated payload to Prisma database queries. We must update the `create` and `update` queries to assign `rootImage` for Menu, and `columnImage`/`hoverImage` for MenuItem. 5. **MCP Schema & Helper**: The MCP toolkit contains utility validation for items before sending PUT requests. Adding validation rules in `validateMenuItems` prevents MCP validation blocks. Updating `MENU_TOOL_DEFINITIONS` exposes the new input parameters to AI clients interacting with `upsert_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 `.js` and `.d.ts` files 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: 1. **Schema Check**: Confirm that the prisma client generates successfully by running: ```bash bunx prisma generate ``` 2. **Database Migration Status**: Run the following command to ensure migrations are applied cleanly without conflicts: ```bash bunx prisma migrate status ``` 3. **Route Integration & Tests**: Execute the backend build script to verify there are no syntax or type mismatch errors: ```bash npm run build --workspace apps/backend ``` Execute the workspace test command: ```bash npm run test ```