From fb90403b7ca61c35d46396ffa0edd6fed97f7e8e Mon Sep 17 00:00:00 2001 From: chan Date: Thu, 18 Jun 2026 16:53:46 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(auth):=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=9E=AC=EC=84=A4=EC=A0=95=20=EB=A6=AC=EB=8B=A4?= =?UTF-8?q?=EC=9D=B4=EB=A0=89=ED=8A=B8=20=EC=96=B8=EC=96=B4=20=EB=B3=B4?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EB=B3=84=20=EB=B6=84=EA=B8=B0=20=EC=B0=A8=EB=8B=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 백엔드 ProcessPasswordResetToken 리다이렉션 경로에 최우선 선호 로케일 주소(ko/en) 동적 생성 적용 (레이스 컨디션 방지 및 로딩 갇힘 해결) 2. ForgotPasswordScreen 발송 성공 후 빈 네비게이터 팝 현상 제거 (GoRouter context.pop() 및 context.go() 사용) 3. 로그인 후 화면(내정보 프로필 페이지)에서 불필요한 비밀번호 분실 버튼 제거 정책 반영 --- backend/internal/handler/auth_handler.go | 12 +++++++++++- .../auth/presentation/forgot_password_screen.dart | 15 ++++++++++++++- .../profile/presentation/pages/profile_page.dart | 5 ----- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/backend/internal/handler/auth_handler.go b/backend/internal/handler/auth_handler.go index 019b1656..dae3e471 100644 --- a/backend/internal/handler/auth_handler.go +++ b/backend/internal/handler/auth_handler.go @@ -4144,7 +4144,17 @@ func (h *AuthHandler) ProcessPasswordResetToken(c *fiber.Ctx) error { ale.LoginIDs["loginId_normalized"] = loginID userfrontURL := h.resolveUserfrontURL(c) - redirectBase, parseErr := url.Parse(userfrontURL + "/reset-password") + locale := "ko" + acceptLang := c.Get("Accept-Language") + if acceptLang != "" { + // Accept-Language 헤더는 선호도가 가장 높은 순서대로 쉼표로 구분되어 나열됩니다. (예: ko-KR,ko;q=0.9,en-US;q=0.8) + // 따라서 첫 번째 쉼표 이전의 가장 첫 번째 세그먼트가 사용자가 최우선으로 선호하는 언어입니다. + firstLang := strings.Split(acceptLang, ",")[0] + if strings.Contains(strings.ToLower(firstLang), "en") { + locale = "en" + } + } + redirectBase, parseErr := url.Parse(fmt.Sprintf("%s/%s/reset-password", strings.TrimRight(userfrontURL, "/"), locale)) if parseErr != nil { ale.Status = fiber.StatusInternalServerError ale.LatencyMs = time.Since(startTime) diff --git a/userfront/lib/features/auth/presentation/forgot_password_screen.dart b/userfront/lib/features/auth/presentation/forgot_password_screen.dart index 8c01e4cd..9b72a485 100644 --- a/userfront/lib/features/auth/presentation/forgot_password_screen.dart +++ b/userfront/lib/features/auth/presentation/forgot_password_screen.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import '../../../core/i18n/locale_utils.dart'; +import '../../../core/services/auth_token_store.dart'; import '../../../core/services/auth_proxy_service.dart'; import '../../../core/ui/toast_service.dart'; import 'package:userfront/i18n.dart'; @@ -48,7 +51,17 @@ class _ForgotPasswordScreenState extends State { ); if (mounted) { ToastService.success(tr('msg.userfront.forgot.sent')); - Navigator.of(context).pop(); + if (context.canPop()) { + context.pop(); + } else { + final isLoggedIn = AuthTokenStore.hasToken(); + final localeCode = extractLocaleFromPath(Uri.base) ?? resolvePreferredLocaleCode(); + if (isLoggedIn) { + context.go('/$localeCode/profile'); + } else { + context.go('/$localeCode/signin'); + } + } } } catch (e) { if (mounted) { diff --git a/userfront/lib/features/profile/presentation/pages/profile_page.dart b/userfront/lib/features/profile/presentation/pages/profile_page.dart index 4ed3e63b..d023365c 100644 --- a/userfront/lib/features/profile/presentation/pages/profile_page.dart +++ b/userfront/lib/features/profile/presentation/pages/profile_page.dart @@ -1097,11 +1097,6 @@ class _ProfilePageState extends ConsumerState { ) : Text(tr('ui.userfront.profile.password.change')), ), - const SizedBox(width: 12), - TextButton( - onPressed: () => context.go('/recovery'), - child: Text(tr('ui.userfront.profile.password.forgot')), - ), ], ), ], From 9af038271d1008baed180dbb37b9d412be04a39e Mon Sep 17 00:00:00 2001 From: chan Date: Thu, 18 Jun 2026 17:43:09 +0900 Subject: [PATCH 2/2] =?UTF-8?q?chore(i18n):=20TenantFineGrainedPermissions?= =?UTF-8?q?Page=20=EB=88=84=EB=9D=BD=EB=90=9C=20=EB=8B=A4=EA=B5=AD?= =?UTF-8?q?=EC=96=B4=20=ED=82=A4=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EC=A0=95=EC=A0=81=20=EA=B2=80=EC=82=AC=20=ED=86=B5=EA=B3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. TenantFineGrainedPermissionsPage 컴포넌트에서 사용하는 msg/ui 관련 9개 번역 키를 locales(template.toml, ko.toml, en.toml)에 추가 2. 누락된 키 매핑 및 한국어/영어 번역 값 보정으로 로컬 CI 정적 검사(make code-check-lint) 통과 완료 --- locales/en.toml | 9 +++++++++ locales/ko.toml | 9 +++++++++ locales/template.toml | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/locales/en.toml b/locales/en.toml index 9990de93..b6a4e8e2 100644 --- a/locales/en.toml +++ b/locales/en.toml @@ -283,6 +283,9 @@ no_users_found = "No Users Found" protected_relation = "This relation is protected and cannot be changed here." super_admin_description = "Grant or revoke system super administrator access." super_admin_grant_success = "Super administrator access granted." +super_admin_grant_queue_empty = "Add users to grant from the search results on the left." +super_admin_grant_users_required = "Please add one or more users to grant." +super_admin_search_empty = "Please enter a search term." super_admin_revoke_success = "Super administrator access revoked." super_admin_users_required = "Select at least one user." target_tenant_picker_desc = "Choose the tenant scope for this permission." @@ -1500,6 +1503,12 @@ target_org_picker = "Select organization" target_queue_empty = "No targets selected" target_queue_remove = "Remove target" target_tenant_picker_title = "Select tenant" +search_results = "results" +super_admin_grant_queue_add = "Add to targets" +super_admin_grant_queue_remove = "Remove from targets" +super_admin_grant_targets = "Grant Targets" +super_admin_search = "Search User" +super_admin_search_placeholder = "Search UUID, name, email, phone number" target_tenant_required_option = "Target tenant required" user_list = "User List" diff --git a/locales/ko.toml b/locales/ko.toml index be4ba144..c4f282e3 100644 --- a/locales/ko.toml +++ b/locales/ko.toml @@ -283,6 +283,9 @@ no_users_found = "등록된 사용자가 없습니다." protected_relation = "보호된 관계라 이 화면에서 변경할 수 없습니다." super_admin_description = "시스템 Super Admin 권한을 부여하거나 회수합니다." super_admin_grant_success = "Super Admin 권한을 부여했습니다." +super_admin_grant_queue_empty = "부여할 사용자를 왼쪽 검색 결과에서 추가하세요." +super_admin_grant_users_required = "부여할 사용자를 하나 이상 추가하세요." +super_admin_search_empty = "검색어를 입력하세요." super_admin_revoke_success = "Super Admin 권한을 회수했습니다." super_admin_users_required = "사용자를 한 명 이상 선택해 주세요." target_tenant_picker_desc = "이 권한에 적용할 테넌트 범위를 선택합니다." @@ -1500,6 +1503,12 @@ target_org_picker = "조직 선택" target_queue_empty = "선택된 대상이 없습니다." target_queue_remove = "대상 제거" target_tenant_picker_title = "테넌트 선택" +search_results = "건" +super_admin_grant_queue_add = "부여 대상 추가" +super_admin_grant_queue_remove = "부여 대상 제거" +super_admin_grant_targets = "부여 대상자" +super_admin_search = "사용자 검색" +super_admin_search_placeholder = "UUID, 이름, 이메일, 전화번호 검색" target_tenant_required_option = "대상 테넌트 필수" user_list = "대상 사용자" diff --git a/locales/template.toml b/locales/template.toml index 73c0cfe1..9c47a53c 100644 --- a/locales/template.toml +++ b/locales/template.toml @@ -283,6 +283,9 @@ no_users_found = "" protected_relation = "" super_admin_description = "" super_admin_grant_success = "" +super_admin_grant_queue_empty = "" +super_admin_grant_users_required = "" +super_admin_search_empty = "" super_admin_revoke_success = "" super_admin_users_required = "" target_tenant_picker_desc = "" @@ -1500,6 +1503,12 @@ target_org_picker = "" target_queue_empty = "" target_queue_remove = "" target_tenant_picker_title = "" +search_results = "" +super_admin_grant_queue_add = "" +super_admin_grant_queue_remove = "" +super_admin_grant_targets = "" +super_admin_search = "" +super_admin_search_placeholder = "" target_tenant_required_option = "" user_list = ""