172 lines
6.7 KiB
Markdown
172 lines
6.7 KiB
Markdown
# 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
|
||
```
|