Files
homaroma/.agents/explorer_m2_3/handoff.md
T
2026-06-28 21:34:58 -04:00

6.7 KiB
Raw Blame History

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:

    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:

    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:

    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 }[] }[] 
    };
    
  4. 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;
        }
    
  5. MCP Schema: File: apps/mcp-server/menu-toolkit.ts, lines 34–74, the definition of upsert_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

  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:
    bunx prisma generate
    
  2. Database Migration Status: Run the following command to ensure migrations are applied cleanly without conflicts:
    bunx prisma migrate status
    
  3. Route Integration & Tests: Execute the backend build script to verify there are no syntax or type mismatch errors:
    npm run build --workspace apps/backend
    
    Execute the workspace test command:
    npm run test