x
This commit is contained in:
1 parent
3965f4f4da
commit
70877882b0
82 files changed
+4353
-186
No files matched your search
@@ -0,0 +1,46 @@
|
||||
# BRIEFING — 2026-06-29T01:19:30Z
|
||||
|
||||
## Mission
|
||||
Investigate menu fetching and rendering across apps/spa, apps/website, apps/admin, and apps/backend to locate models, routes, rendering components, and editor components.
|
||||
|
||||
## 🔒 My Identity
|
||||
- Archetype: Teamwork explorer
|
||||
- Roles: Read-only investigation, code analyzer, report synthesizer
|
||||
- Working directory: /home/ti/git/homaroma/.agents/explorer_pre_impl_1
|
||||
- Original parent: f5557127-1c9c-40d2-90e6-d996a7381786
|
||||
- Milestone: Menu exploration and codebase analysis
|
||||
|
||||
## 🔒 Key Constraints
|
||||
- Read-only investigation — do NOT implement
|
||||
- CODE_ONLY network mode: No external queries or HTTP clients
|
||||
|
||||
## Current Parent
|
||||
- Conversation ID: f5557127-1c9c-40d2-90e6-d996a7381786
|
||||
- Updated: not yet
|
||||
|
||||
## Investigation State
|
||||
- **Explored paths**:
|
||||
- `packages/types/index.ts`
|
||||
- `apps/spa/src/store/menuStore.ts`
|
||||
- `apps/website/src/components/navigation/menuTypes.ts`
|
||||
- `apps/backend/src/routes/menus.ts`
|
||||
- `apps/backend/prisma/schema.prisma`
|
||||
- `apps/spa/src/components/Navbar.tsx`
|
||||
- `apps/spa/src/components/DesktopMegaMenu.tsx`
|
||||
- `apps/spa/src/components/MobileDrawer.tsx`
|
||||
- `apps/website/src/components/Navbar.tsx`
|
||||
- `apps/website/src/components/navigation/DesktopMegaMenu.tsx`
|
||||
- `apps/website/src/components/navigation/MobileDrawer.tsx`
|
||||
- `apps/admin/src/pages/MenuManagerPage.tsx`
|
||||
- **Key findings**:
|
||||
- Prisma schema currently lacks `rootImage` (for `Menu`), `columnImage` (for `MenuItem`), and `hoverImage` (for `MenuItem`).
|
||||
- `DesktopMegaMenu` in `apps/spa` uses hardcoded Picsum seed URLs for the 3-image layout compartments.
|
||||
- `DesktopMegaMenu` in `apps/website` has no image placeholders/ compartments implemented yet.
|
||||
- `MenuManagerPage` has a `TreeNodeEditor` that lets you configure menu title/label translations and URLs, but lacks fields to manage image URLs.
|
||||
- **Unexplored areas**: None.
|
||||
|
||||
## Key Decisions Made
|
||||
- Fully audit menu schemas, routes, rendering layout, and admin controllers before suggesting edits.
|
||||
|
||||
## Artifact Index
|
||||
- /home/ti/git/homaroma/.agents/explorer_pre_impl_1/analysis.md — Detailed analysis report of menu systems
|
||||
@@ -0,0 +1,7 @@
|
||||
## 2026-06-29T01:18:30Z
|
||||
Please investigate the current codebase to locate all occurrences of menu fetching and rendering in apps/spa, apps/website, and apps/admin. Specifically:
|
||||
1. Identify all TypeScript definitions of MenuItem, Menu, and MegaMenuPayload across all applications.
|
||||
2. Locate the Elysia routes for menus in apps/backend/src/routes/menus.ts, and note how validation and database updates are structured.
|
||||
3. Locate where main menu and dropdown panels are rendered in apps/spa and apps/website.
|
||||
4. Locate the MenuManagerPage in apps/admin (or apps/spa) and how the payload is constructed and edited.
|
||||
Write your findings to /home/ti/git/homaroma/.agents/explorer_pre_impl_1/analysis.md and reply with a summary.
|
||||
@@ -0,0 +1 @@
|
||||
# Explorer Pre-Implementation Metadata
|
||||
@@ -0,0 +1,179 @@
|
||||
# Codebase Analysis: Menu Fetching, Rendering, and Modeling
|
||||
|
||||
This document provides a detailed investigation and mapping of the menu systems across the HomAroma applications.
|
||||
|
||||
---
|
||||
|
||||
## 1. TypeScript Type Definitions for Menus
|
||||
|
||||
TypeScript definitions for menus are spread across the shared types package and individual application stores/components.
|
||||
|
||||
### Shared / Package Definitions
|
||||
**File**: `packages/types/index.ts`
|
||||
These define the database-facing structures and basic relational entities.
|
||||
```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
|
||||
}
|
||||
```
|
||||
|
||||
### SPA Application definitions
|
||||
**File**: `apps/spa/src/store/menuStore.ts`
|
||||
These define the recursive client-side tree structure used by the Mega Menu payload.
|
||||
```typescript
|
||||
export interface MenuLink {
|
||||
label: Record<string, string>;
|
||||
url?: string;
|
||||
links?: MenuLink[];
|
||||
}
|
||||
|
||||
export interface MenuColumn {
|
||||
title: Record<string, string>;
|
||||
links: MenuLink[];
|
||||
}
|
||||
|
||||
export interface MegaMenuPayload {
|
||||
id?: string;
|
||||
nodeId?: string;
|
||||
label: Record<string, string>;
|
||||
url?: string;
|
||||
columns?: MenuColumn[];
|
||||
}
|
||||
```
|
||||
|
||||
### Website Storefront definitions
|
||||
**File**: `apps/website/src/components/navigation/menuTypes.ts`
|
||||
Similar to the SPA definitions but more flexible, supporting both localized translation maps and plain string fallbacks.
|
||||
```typescript
|
||||
export interface MenuLink {
|
||||
label: Record<string, string> | string
|
||||
url?: string
|
||||
links?: MenuLink[]
|
||||
}
|
||||
|
||||
export interface MenuColumn {
|
||||
title: Record<string, string> | string
|
||||
links: MenuLink[]
|
||||
}
|
||||
|
||||
export interface MegaMenuPayload {
|
||||
id?: string
|
||||
nodeId?: string
|
||||
label: Record<string, string> | string
|
||||
url?: string
|
||||
columns?: MenuColumn[]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Elysia Backend Routes
|
||||
|
||||
**File**: `apps/backend/src/routes/menus.ts`
|
||||
The backend exposes routes under the prefix `/menus` to manage menu structure, fetch menus, and update metadata.
|
||||
|
||||
### Route List and Functionality
|
||||
- **`GET /`**: Retrieves all menus, including their menu items sorted by `order` in ascending order and all associated translations.
|
||||
- **`GET /:name`**: Retrieves a single menu by name. If it is not found in the database, it returns a default fallback structure:
|
||||
```json
|
||||
{ "name": "name", "items": [], "payload": null, "isActive": false }
|
||||
```
|
||||
- **`POST /`** *(Admin only)*: Creates a menu with an optional array of flat items.
|
||||
- **`PUT /:name`** *(Admin only)*: The main entry point to upsert/save a menu's tree payload. If the menu does not exist, it is created. It then uses a database transaction (`prisma.$transaction`) to:
|
||||
1. Retrieve all existing `MenuItem` entries.
|
||||
2. Compute item differences and delete any old `MenuItem`s not present in the payload.
|
||||
3. Iterate over the input items. If an item exists, it updates `label`, `url`, and `order`, and upserts its language translations in `MenuItemTranslation`.
|
||||
4. If the item is new, it creates a new `MenuItem` and its nested translations.
|
||||
- **`PATCH /items/:id/translations`**: Directly manages/patches the translations for a single `MenuItem` for a set list of supported languages (`['th', 'en', 'ja', 'zh', 'vi', 'ko']`).
|
||||
|
||||
### Request Validation
|
||||
Elysia validates request payloads using TypeBox schemas. The `PUT /:name` schema is:
|
||||
```typescript
|
||||
{
|
||||
body: t.Object({
|
||||
payload: t.Optional(t.Any()),
|
||||
isActive: t.Optional(t.Boolean()),
|
||||
items: t.Array(t.Object({
|
||||
id: t.Optional(t.Number()),
|
||||
label: t.String(),
|
||||
url: t.String(),
|
||||
order: t.Number(),
|
||||
translations: t.Optional(t.Array(t.Object({
|
||||
langCode: t.String(),
|
||||
label: t.String()
|
||||
})))
|
||||
}))
|
||||
})
|
||||
}
|
||||
```
|
||||
*Note: The `payload` field is validated as `t.Optional(t.Any())`. This means backend validation is schema-less for the JSON tree structure stored in `Menu.payload`.*
|
||||
|
||||
---
|
||||
|
||||
## 3. Frontend Menu Rendering
|
||||
|
||||
The main menu and dropdown panels are fetched and rendered differently in `apps/spa` and `apps/website`.
|
||||
|
||||
### A. SPA Frontend (`apps/spa`)
|
||||
- **Fetching**: Fetched via the Zustand store (`useMenuStore`) inside `apps/spa/src/components/Navbar.tsx` on component mount (`fetchMegaMenu()`).
|
||||
- **Desktop Mega Menu (`apps/spa/src/components/DesktopMegaMenu.tsx`)**:
|
||||
- Maps `items` (i.e. `MegaMenuPayload[]`) horizontally to trigger buttons.
|
||||
- Dropdown panels are positioned absolutely flush below the navbar using a CSS custom property `--navbar-bottom` computed dynamically by the `Navbar`.
|
||||
- **Image Placements (Currently Mocked)**:
|
||||
- *Root Image (Far Left)*: Mocked using `<img src={`https://picsum.photos/seed/root-${uniqueId}/400/400`} />`.
|
||||
- *Column Image (Inside Center Grid)*: Renders a 1:1 ratio square thumbnail above/next to each column title, mocked using `<img src={`https://picsum.photos/seed/col-${uniqueId}-${idx}/200/200`} />`.
|
||||
- *Link Hover Image (Far Right)*: Tracks the hovered link inside `onMouseEnter` of each link list item. The hovered image URL is stored in local state `hoveredImage` and rendered inside the right column. It is mocked using `https://picsum.photos/seed/link-${uniqueId}-${idx}-${lIdx}/400/400`.
|
||||
- **Mobile Drawer (`apps/spa/src/components/MobileDrawer.tsx`)**:
|
||||
- Uses stack-based navigation to transition between parent menus and child links.
|
||||
- Does **not** render any images.
|
||||
|
||||
### B. Website Storefront (`apps/website`)
|
||||
- **Fetching**: Fetched during Server-Side Rendering (SSR) in `apps/website/src/app/[lang]/layout.tsx` (`getMegaMenu(lang)`) and passed down to client-side components to eliminate layout shifts or content flashes.
|
||||
- **Desktop Mega Menu (`apps/website/src/components/navigation/DesktopMegaMenu.tsx`)**:
|
||||
- Renders a horizontal trigger list and dropdown panels similarly to the SPA.
|
||||
- **Current Gap**: The 3-image layout (Root, Column, Hover) is **not yet implemented**. It only renders the columns and links list structure.
|
||||
- **Mobile Drawer (`apps/website/src/components/navigation/MobileDrawer.tsx`)**:
|
||||
- Stack-based hierarchical navigation drawer.
|
||||
- Hides the complex image elements.
|
||||
|
||||
---
|
||||
|
||||
## 4. Admin Menu Manager Page
|
||||
|
||||
**File**: `apps/admin/src/pages/MenuManagerPage.tsx`
|
||||
|
||||
The `MenuManagerPage` is where administrators configure the flat footer links and the hierarchical mega menu payload.
|
||||
|
||||
### Construction and Editing
|
||||
- **Hierarchy Representation**: The page uses a recursive sub-component `TreeNodeEditor` to build and edit the menu structure:
|
||||
- **Root Nodes (MegaMenuPayload)**:
|
||||
- Editable fields: translations for `label`, `url`.
|
||||
- Contains child array: `columns` (representing `MenuColumn`s).
|
||||
- **Column Nodes (MenuColumn)**:
|
||||
- Editable fields: translations for `title`.
|
||||
- Contains child array: `links` (representing `MenuLink`s).
|
||||
- **Link Nodes (MenuLink)**:
|
||||
- Editable fields: translations for `label`, `url`.
|
||||
- Allows further nested links.
|
||||
- **Save Operations**:
|
||||
- Triggered by submitting the form.
|
||||
- Makes a `PUT` request to `${API_BASE}/menus/${selectedMenuName}`.
|
||||
- For the `main` menu, the payload consists of:
|
||||
```json
|
||||
{
|
||||
"items": [],
|
||||
"payload": [...] // Complete JSON tree structures built via TreeNodeEditor
|
||||
}
|
||||
```
|
||||
- **Current Gap**: There are no input controls in `TreeNodeEditor` to set `rootImage`, `columnImage`, or `hoverImage` values.
|
||||
@@ -0,0 +1,133 @@
|
||||
# Handoff Report: Menu Exploration & Investigation
|
||||
|
||||
## 1. Observation
|
||||
|
||||
- **Types Definitions**:
|
||||
- `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
|
||||
}
|
||||
```
|
||||
- `apps/spa/src/store/menuStore.ts` lines 4–21:
|
||||
```typescript
|
||||
export interface MenuLink {
|
||||
label: Record<string, string>;
|
||||
url?: string;
|
||||
links?: MenuLink[];
|
||||
}
|
||||
|
||||
export interface MenuColumn {
|
||||
title: Record<string, string>;
|
||||
links: MenuLink[];
|
||||
}
|
||||
|
||||
export interface MegaMenuPayload {
|
||||
id?: string;
|
||||
nodeId?: string;
|
||||
label: Record<string, string>;
|
||||
url?: string;
|
||||
columns?: MenuColumn[];
|
||||
}
|
||||
```
|
||||
- `apps/website/src/components/navigation/menuTypes.ts` lines 1–18:
|
||||
```typescript
|
||||
export interface MenuLink {
|
||||
label: Record<string, string> | string
|
||||
url?: string
|
||||
links?: MenuLink[]
|
||||
}
|
||||
|
||||
export interface MenuColumn {
|
||||
title: Record<string, string> | string
|
||||
links: MenuLink[]
|
||||
}
|
||||
|
||||
export interface MegaMenuPayload {
|
||||
id?: string
|
||||
nodeId?: string
|
||||
label: Record<string, string> | string
|
||||
url?: string
|
||||
columns?: MenuColumn[]
|
||||
}
|
||||
```
|
||||
|
||||
- **Elysia Backend Routes**:
|
||||
- `apps/backend/src/routes/menus.ts` line 5 defines route prefix `/menus`.
|
||||
- `PUT /:name` (lines 60–147) receives `items` and `payload`, upserts the menu model, and executes `tx.menuItem` operations in a Prisma transaction (`prisma.$transaction`).
|
||||
- Validation schema (lines 132–147) defines `payload: t.Optional(t.Any())`.
|
||||
- Database schema: `apps/backend/prisma/schema.prisma` lines 638–670 specifies:
|
||||
```prisma
|
||||
model Menu {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @unique
|
||||
payload Json?
|
||||
isActive Boolean @default(true)
|
||||
items MenuItem[]
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
- **Storefront & Admin UI Rendering**:
|
||||
- `apps/spa/src/components/DesktopMegaMenu.tsx` lines 86–130 renders three hardcoded mockup images from `picsum.photos` for:
|
||||
- Left side root menu mockup: `picsum.photos/seed/root-...`
|
||||
- Column thumbnail: `picsum.photos/seed/col-...`
|
||||
- Right side hover link preview: `picsum.photos/seed/link-...`
|
||||
- `apps/website/src/components/navigation/DesktopMegaMenu.tsx` lines 73–94 maps columns and links but currently lacks any image placements (root, column, or hover).
|
||||
- `apps/admin/src/pages/MenuManagerPage.tsx` lines 311–327 maps `currentMenu.payload` recursive tree configuration via `TreeNodeEditor` but has no inputs for image URLs.
|
||||
|
||||
---
|
||||
|
||||
## 2. Logic Chain
|
||||
|
||||
1. **Prisma Schema Constraints**: Currently, the `Menu` and `MenuItem` database models do not have columns for `rootImage`, `columnImage`, or `hoverImage` (`apps/backend/prisma/schema.prisma`). Because these are missing in the schema, the backend cannot yet store flat values directly related to menus/menu-items.
|
||||
2. **Payload Structure**: The `PUT /:name` route accepts an unvalidated JSON tree in `payload` and stores it directly as a `Json` database column. Thus, the client applications can structure the payload freely.
|
||||
3. **TypeScript Contracts**: The client applications (`apps/spa` and `apps/website`) define different structures for recursive `MegaMenuPayload`, but both map to the database JSON field.
|
||||
4. **Current SPA Rendering Logic**: The SPA megamenu dropdown implements the three visual image compartments but relies entirely on static mockup links from picsum.photos.
|
||||
5. **Next.js storefront (`apps/website`)**: Does not render any images inside its desktop megamenu layout.
|
||||
6. **Admin Interface (`apps/admin`)**: The `MenuManagerPage`'s recursive `TreeNodeEditor` component permits editing names and URLs, but has no provisions for specifying the image links.
|
||||
|
||||
---
|
||||
|
||||
## 3. Caveats
|
||||
|
||||
- We assumed that all menus are stored using the Elysia menu routes and no direct raw SQL queries bypass them.
|
||||
- We did not check the exact media uploader functionality since we only focused on how URLs are represented in menu definitions.
|
||||
- The `isActive` flag toggle behavior on the website storefront was not fully traced since it does not affect structural data definitions.
|
||||
|
||||
---
|
||||
|
||||
## 4. Conclusion
|
||||
|
||||
- **Backend / Database Changes Needed**:
|
||||
- Prisma schema needs updates: `rootImage` on `Menu`, and `columnImage` / `hoverImage` on `MenuItem`.
|
||||
- Type validation schemas inside Elysia and typescript interfaces must be expanded to include these optional image fields.
|
||||
- **Frontend Changes Needed**:
|
||||
- `apps/admin/src/pages/MenuManagerPage.tsx`: Expand `TreeNodeEditor` to support text/upload inputs for the 3 image types depending on the node type (root, column, link).
|
||||
- `apps/spa/src/components/DesktopMegaMenu.tsx`: Replace hardcoded Picsum placeholders with dynamic data retrieved from the payload.
|
||||
- `apps/website/src/components/navigation/DesktopMegaMenu.tsx`: Implement the 3-image layout using `next/image` to match the SPA design.
|
||||
|
||||
---
|
||||
|
||||
## 5. Verification Method
|
||||
|
||||
- Check project compilation using:
|
||||
```bash
|
||||
npm run build --workspaces --if-present
|
||||
```
|
||||
- Inspect file paths to verify the location of changes:
|
||||
- Prisma schema: `apps/backend/prisma/schema.prisma`
|
||||
- Types: `packages/types/index.ts`, `apps/spa/src/store/menuStore.ts`, `apps/website/src/components/navigation/menuTypes.ts`
|
||||
- Routes: `apps/backend/src/routes/menus.ts`
|
||||
- Components: `apps/admin/src/pages/MenuManagerPage.tsx`, `apps/spa/src/components/DesktopMegaMenu.tsx`, `apps/website/src/components/navigation/DesktopMegaMenu.tsx`
|
||||
@@ -0,0 +1,10 @@
|
||||
# Progress
|
||||
|
||||
Last visited: 2026-06-29T01:19:30Z
|
||||
|
||||
- [x] Initialized ORIGINAL_REQUEST.md and BRIEFING.md
|
||||
- [x] Investigate TypeScript definitions of MenuItem, Menu, and MegaMenuPayload
|
||||
- [x] Locate Elysia routes in apps/backend/src/routes/menus.ts
|
||||
- [x] Find main menu and dropdown panel rendering in apps/spa and apps/website
|
||||
- [x] Find MenuManagerPage in apps/admin (or apps/spa)
|
||||
- [x] Compile analysis.md and handoff.md
|
||||
Reference in new issue
Block a user