feat(favorites): 사용자별 메뉴 즐겨찾기

사이드바 leaf 메뉴 옆 별표로 토글하고, 사이드바 최상단 '즐겨찾기'
섹션에 등록된 메뉴를 모아 보여준다. 테넌트 DB 별로 격리.

- V020 + StartupSchemaMigrator: USER_MENU_FAVORITES (USER_ID,
  MENU_OBJID UNIQUE) 메타·테넌트 DB 동기 멱등 생성
- 백엔드: GET/POST /api/favorites/menus, DELETE
  /api/favorites/menus/{menuObjid} — FavoritesController/Service
  + mapper/favorites.xml (MENU_INFO JOIN)
- 프론트: favoritesAPI 클라이언트 + FavoritesContext (낙관적
  toggle/롤백) + (main)/layout 에 Provider 마운트
- AppLayout: leaf/sub-item 옆 Star 토글 (등록 시 primary 컬러,
  미등록 시 0.35 dimmed) + 사이드바 최상단 favorites 섹션. uiMenus
  의 leaf 평탄화 결과를 isFavorite 으로 필터링해 권한 필터/메뉴
  클릭 핸들러를 그대로 재사용

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hjjeong
2026-05-12 11:29:18 +09:00
parent 1bd0fd8b80
commit 8bdc9a958f
9 changed files with 437 additions and 4 deletions
@@ -89,7 +89,22 @@ public class StartupSchemaMigrator {
"ALTER TABLE DEPT_INFO DROP COLUMN IF EXISTS SALES_YN",
"ALTER TABLE DEPT_INFO DROP COLUMN IF EXISTS SHOW_IN_CHART",
"ALTER TABLE DEPT_INFO DROP COLUMN IF EXISTS ERP_MANAGED",
"ALTER TABLE DEPT_INFO DROP COLUMN IF EXISTS DATA_TYPE"
"ALTER TABLE DEPT_INFO DROP COLUMN IF EXISTS DATA_TYPE",
// V020: 사용자별 메뉴 즐겨찾기 테이블.
// 메타 DB 는 Flyway V020 으로도 적용되지만 프로비저닝된 테넌트 DB 는 부팅 때 동기화.
// CREATE IF NOT EXISTS 로 멱등성 보장.
"""
CREATE TABLE IF NOT EXISTS USER_MENU_FAVORITES (
OBJID BIGSERIAL PRIMARY KEY,
USER_ID VARCHAR(100) NOT NULL,
MENU_OBJID VARCHAR(50) NOT NULL,
SORT_ORDER INTEGER NOT NULL DEFAULT 0,
CREATED_AT TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT UQ_USER_MENU_FAVORITES UNIQUE (USER_ID, MENU_OBJID)
)
""",
"CREATE INDEX IF NOT EXISTS IDX_USER_MENU_FAVORITES_USER ON USER_MENU_FAVORITES (USER_ID)"
);
@EventListener(ApplicationReadyEvent.class)