diff --git a/apps/mall/components/shell/TopBar.vue b/apps/mall/components/shell/TopBar.vue
index 64a1fdd..0ab59bb 100644
--- a/apps/mall/components/shell/TopBar.vue
+++ b/apps/mall/components/shell/TopBar.vue
@@ -18,17 +18,27 @@ const { t } = useI18n();
{{ t("shell.city") }}
-
- - {{ t("shell.welcome") }}{{ session.user?.display_name }}
- - |
- - {{ t("shell.userCenter") }}
- - |
- - {{ t("shell.logout") }}
-
-
- - {{ t("shell.login") }}
- - {{ t("shell.register") }}
-
+
+
+
+ - {{ t("shell.welcome") }}{{ session.user?.display_name }}
+ - |
+ - {{ t("shell.userCenter") }}
+ - |
+ - {{ t("shell.logout") }}
+
+
+ - {{ t("shell.login") }}
+ - {{ t("shell.register") }}
+
+
+ - {{ t("shell.login") }}
+ - {{ t("shell.register") }}
+
+
- |
- {{ t("shell.sellerJoin") }}
- |
diff --git a/apps/mall/locales/auth.ts b/apps/mall/locales/auth.ts
index 8870b8c..c92a3a3 100644
--- a/apps/mall/locales/auth.ts
+++ b/apps/mall/locales/auth.ts
@@ -29,9 +29,11 @@ export default {
resetSuccessHint: "Your password has been reset. Sign in with your new password.",
validationRequired: "Please complete all required fields.",
validationEmail: "Enter a valid email address.",
- validationPassword: "Password must be at least 6 characters.",
+ validationPassword: "Password must be at least 8 characters.",
validationMismatch: "Passwords do not match.",
requestFailed: "Unable to complete this request. Please try again.",
+ invalidCredentials: "Incorrect email or password.",
+ emailTaken: "That email is already registered.",
},
},
zh: {
@@ -64,9 +66,11 @@ export default {
resetSuccessHint: "您的密码已重置,请使用新密码登录。",
validationRequired: "请填写所有必填项。",
validationEmail: "请输入有效的邮箱地址。",
- validationPassword: "密码至少需要 6 位。",
+ validationPassword: "密码至少需要 8 位。",
validationMismatch: "两次输入的密码不一致。",
requestFailed: "操作失败,请稍后重试。",
+ invalidCredentials: "邮箱或密码不正确。",
+ emailTaken: "该邮箱已被注册。",
},
},
};
diff --git a/apps/mall/middleware/auth.ts b/apps/mall/middleware/auth.ts
index 3413cd0..9c0c26c 100644
--- a/apps/mall/middleware/auth.ts
+++ b/apps/mall/middleware/auth.ts
@@ -1,15 +1,10 @@
-export default defineNuxtRouteMiddleware(() => {
+export default defineNuxtRouteMiddleware(async () => {
if (import.meta.server) return;
- const token = localStorage.getItem("vmall.token");
- let role: string | null = null;
- try {
- const raw = localStorage.getItem("vmall.user");
- const user: unknown = raw ? JSON.parse(raw) : null;
- if (user && typeof user === "object" && "role" in user && typeof user.role === "string") {
- role = user.role;
- }
- } catch {
- role = null;
- }
- if (!token || role !== "customer") return navigateTo("/login");
+ const session = useSessionStore();
+ if (!session.token) session.hydrate();
+ if (!session.token) return navigateTo("/login");
+ // Trust the auth API's answer rather than whatever localStorage claims; a
+ // rejected token clears the session inside validate().
+ if (!(await session.validate())) return navigateTo("/login");
+ if (session.user?.role !== "customer") return navigateTo("/login");
});
diff --git a/apps/mall/nuxt.config.ts b/apps/mall/nuxt.config.ts
index 92ee754..24a598c 100644
--- a/apps/mall/nuxt.config.ts
+++ b/apps/mall/nuxt.config.ts
@@ -8,8 +8,8 @@ export default defineNuxtConfig({
apiBase: "http://localhost:8080/api",
// Domains served by the live backend; every other domain stays on the
// fixed-data adapter. Override with NUXT_PUBLIC_LIVE_DOMAINS='["catalog"]'.
- // See openspec/changes/replace-mock-api-wave-1/design.md.
- liveDomains: ["catalog", "currency"],
+ // See openspec/changes/replace-mock-api-wave-1/design.md and wave 2.
+ liveDomains: ["catalog", "currency", "auth"],
appName: "mall",
},
},
diff --git a/apps/mall/pages/forgot-password.vue b/apps/mall/pages/forgot-password.vue
index 263f7b5..f76a47a 100644
--- a/apps/mall/pages/forgot-password.vue
+++ b/apps/mall/pages/forgot-password.vue
@@ -35,7 +35,8 @@ function validate(): boolean {
errorKey.value = "auth.validationEmail";
return false;
}
- if (password.value.length < 6) {
+ // Matches the shared validationPassword message and the auth API's rule.
+ if (password.value.length < 8) {
errorKey.value = "auth.validationPassword";
return false;
}
diff --git a/apps/mall/pages/login.vue b/apps/mall/pages/login.vue
index 715611c..e299bf2 100644
--- a/apps/mall/pages/login.vue
+++ b/apps/mall/pages/login.vue
@@ -1,4 +1,6 @@