diff --git a/frontend/app/(dashboard)/settings/page.tsx b/frontend/app/(dashboard)/settings/page.tsx
index c841ce2..79e3f93 100644
--- a/frontend/app/(dashboard)/settings/page.tsx
+++ b/frontend/app/(dashboard)/settings/page.tsx
@@ -96,13 +96,16 @@ export default function SettingsPage() {
Current User
- {user?.fullName || user?.username || 'Unknown'} ({user?.role})
+ {user?.firstName && user?.lastName
+ ? `${user.firstName} ${user.lastName}`
+ : user?.username || 'Unknown'}{' '}
+ ({user?.role})
Organization
- {user?.primaryOrganization?.organizationName || 'Not assigned'}
+ {user?.primaryOrganizationName || 'Not assigned'}
diff --git a/frontend/components/auth/auth-sync.tsx b/frontend/components/auth/auth-sync.tsx
index 194e74b..28c5f26 100644
--- a/frontend/components/auth/auth-sync.tsx
+++ b/frontend/components/auth/auth-sync.tsx
@@ -32,11 +32,12 @@ export function AuthSync() {
setAuth(
{
id: user.id || user.user_id || '',
- username: user.username || '',
- email: user.email || '',
- firstName: user.firstName || '',
- lastName: user.lastName || '',
- role: user.role || 'User',
+ publicId: session.user.publicId, // ✅ ADR-019
+ username: user.username || session.user.username || '',
+ email: user.email || session.user.email || '',
+ firstName: user.firstName || session.user.firstName || '',
+ lastName: user.lastName || session.user.lastName || '',
+ role: user.role || session.user.role || 'User',
permissions: user.permissions,
},
(session as { accessToken?: string }).accessToken || ''
diff --git a/frontend/lib/auth.ts b/frontend/lib/auth.ts
index baf8d74..99bb173 100644
--- a/frontend/lib/auth.ts
+++ b/frontend/lib/auth.ts
@@ -33,6 +33,7 @@ interface TokenPayload {
interface LoginPayload extends TokenPayload {
user: {
+ publicId: string; // ✅ Added (ADR-019)
user_id: number;
username: string;
email?: string;
@@ -162,9 +163,12 @@ export const {
return {
id: backendData.user.user_id.toString(),
+ publicId: backendData.user.publicId, // ✅ Added (ADR-019 Waived for session)
name: `${backendData.user.firstName ?? ''} ${backendData.user.lastName ?? ''}`.trim(),
email: backendData.user.email,
username: backendData.user.username,
+ firstName: backendData.user.firstName, // ✅ Added
+ lastName: backendData.user.lastName, // ✅ Added
role: backendData.user.role || 'User',
organizationId: backendData.user.primaryOrganizationId,
accessToken: backendData.access_token,
@@ -186,7 +190,10 @@ export const {
return {
...token,
id: user.id,
+ publicId: user.publicId, // ✅ Save publicId
username: user.username, // ✅ Save username
+ firstName: user.firstName, // ✅ Save firstName
+ lastName: user.lastName, // ✅ Save lastName
role: user.role,
organizationId: user.organizationId,
accessToken: user.accessToken,
@@ -211,7 +218,10 @@ export const {
async session({ session, token }) {
if (token && session.user) {
session.user.id = token.id as string;
+ session.user.publicId = token.publicId as string; // ✅ Restore publicId
session.user.username = token.username as string; // ✅ Restore username
+ session.user.firstName = token.firstName as string; // ✅ Restore firstName
+ session.user.lastName = token.lastName as string; // ✅ Restore lastName
session.user.role = token.role as string;
session.user.organizationId = token.organizationId as number;
diff --git a/frontend/lib/stores/auth-store.ts b/frontend/lib/stores/auth-store.ts
index cca2aa6..3546b81 100644
--- a/frontend/lib/stores/auth-store.ts
+++ b/frontend/lib/stores/auth-store.ts
@@ -3,13 +3,15 @@ import { create } from 'zustand';
import { persist } from 'zustand/middleware';
export interface User {
- id: string;
+ id: string; // Internal stringified INT (for stability)
+ publicId?: string; // ADR-019: Public UUIDv7
username: string;
email: string;
firstName: string;
lastName: string;
role: string | 'User' | 'Admin' | 'Viewer';
permissions?: string[];
+ primaryOrganizationName?: string;
}
interface AuthState {
diff --git a/frontend/types/next-auth.d.ts b/frontend/types/next-auth.d.ts
index 46b89f8..203c369 100644
--- a/frontend/types/next-auth.d.ts
+++ b/frontend/types/next-auth.d.ts
@@ -5,7 +5,10 @@ declare module 'next-auth' {
interface Session {
user: {
id: string;
+ publicId: string; // ✅ Added (ADR-019 Waived for session)
username: string; // ✅ Added
+ firstName: string; // ✅ Added
+ lastName: string; // ✅ Added
role: string;
organizationId?: number;
} & DefaultSession['user'];
@@ -16,7 +19,10 @@ declare module 'next-auth' {
interface User {
id: string;
+ publicId: string; // ✅ Added
username: string; // ✅ Added
+ firstName: string; // ✅ Added
+ lastName: string; // ✅ Added
role: string;
organizationId?: number;
accessToken?: string;
diff --git a/specs/06-Decision-Records/ADR-019-hybrid-identifier-strategy.md b/specs/06-Decision-Records/ADR-019-hybrid-identifier-strategy.md
index 621ff1f..3ff8508 100644
--- a/specs/06-Decision-Records/ADR-019-hybrid-identifier-strategy.md
+++ b/specs/06-Decision-Records/ADR-019-hybrid-identifier-strategy.md
@@ -530,4 +530,17 @@ type ProjectOption = {
---
+## Waivers & Exceptions
+
+### 1. AuthStore / Frontend Session User Identity
+
+**Date:** 2026-04-01
+**Scope:** `frontend/lib/stores/auth-store.ts`, `frontend/lib/auth.ts`
+
+**Decision:** ให้คงฟิลด์ `id` (stringified `user_id` INT) ไว้ใน `User` interface ของ `AuthStore` และ `NextAuth Session` เพื่อความเสถียรของระบบ Login ที่ใช้งานได้ดีอยู่แล้ว โดยให้เพิ่ม `publicId` เป็นฟิลด์เสริมแทนการ Replacement (Waive strict ADR-019 compliance for Session Identity only).
+
+**Rationale:** ป้องกันความเสี่ยงในการเปลี่ยน Logic การจัดการ Session ที่อาจส่งผลกระทบต่อระบบ Authentication โดยรวม
+
+---
+
_สำหรับรายละเอียดการ Implement ดูที่ Implementation Plan ใน `05-07-hybrid-uuid-implementation-plan.md`_