Skip to main content

Website Menu Builder

Overview

Menu Builder produces "menu pages" — mini-sites that open from LINE through LIFF or the in-app browser. Each menu carries its own public token, so end users can view it without signing in.

The module supports image uploads, cloning an entire existing menu, and reissuing a token when the original link has leaked to people who should not have it.

One thing worth knowing: this module's policy metadata uses PolicyModuleSystemModule rather than a policy of its own, preserving the behaviour of the original NestJS implementation.

Business Flow

Administrator side

  1. GET /api/menu-builder lists menus with pagination and filtering per QueryParamsMenuBuilderDto.
  2. POST /api/menu-builder creates a menu; the system generates its public token automatically.
  3. POST /api/menu-builder/upload-image uploads menu imagery, validating that the file really is an image.
  4. GET /api/menu-builder/:id and PUT /api/menu-builder/:id read and update the menu structure.
  5. POST /api/menu-builder/:id/clone copies an entire menu and issues a fresh token — useful for A/B tests or seasonal variants.
  6. POST /api/menu-builder/:id/regenerate-token issues a new token, invalidating the previous link immediately.
  7. DELETE /api/menu-builder/:id performs a soft delete by stamping the deleted_at column.

End-user side

  1. The user opens the link from LINE, which calls GET /api/menu-builder/public/:token. This route has no JWT guard and returns the menu structure for client-web to render.
  2. A second public path with similar behaviour exists in the publicmod module: GET /api/public/menu/:token.

A note on soft deletes: the entity has a deleted_at column but does not declare it as gorm.DeletedAt, so every read must add deleted_at IS NULL explicitly to match the original TypeORM behaviour. The delete itself stamps deleted_at = now() without a filter, which requires Unscoped().

Key Files & Functions

Core code lives in internal/modules/menubuilder/, comprising controller.go, service.go, and dto.go.

MethodRouteHandlerGuard / Policy
GET/api/menu-builder/public/:tokenh.findByPublicTokenpublic (no guard)
GET/api/menu-builderh.findAllread system_module
GET/api/menu-builder/:idh.findOneread system_module
POST/api/menu-builderh.createcreate system_module
POST/api/menu-builder/:id/cloneh.clonecreate system_module
POST/api/menu-builder/:id/regenerate-tokenh.regenerateTokenupdate system_module
POST/api/menu-builder/upload-imageh.uploadImagecreate system_module
PUT/api/menu-builder/:idh.updateupdate system_module
DELETE/api/menu-builder/:idh.deletedelete system_module

All routes except the public one are registered on the authed.Group("/menu-builder") group.

Connections to Other Services

  • Access control — administrator routes require global JwtAuth; the policy metadata is PolicyModuleSystemModule and is not yet enforced. The public route has no guard.
  • Tablesmenu_builder, line_oa
  • Storage Service — holds uploaded menu images.
  • Related modules — Public API (an alternative public path), Content Page (another mini-site format), and Content Link.