This commit is contained in:
Your Name committed 2026-06-28 21:34:58 -04:00
1 parent 3965f4f4da
commit 70877882b0
82 files changed
+4353 -186

No files matched your search

+46
View File
@@ -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.
+1
View File
@@ -0,0 +1 @@
# Explorer Pre-Implementation Metadata
+179
View File
@@ -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.
+133
View File
@@ -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`
+10
View File
@@ -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