x
This commit is contained in:
1 parent
3965f4f4da
commit
70877882b0
82 files changed
+4353
-186
No files matched your search
@@ -0,0 +1,171 @@
|
||||
# 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
|
||||
```
|
||||
Reference in new issue
Block a user