@finema/finework-layer 0.2.50 → 0.2.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,592 @@
1
+ # Architecture Documentation
2
+
3
+ ## 🏛️ System Architecture
4
+
5
+ ### Overview
6
+
7
+ `@finema/finework-layer` follows a **layered architecture** pattern, serving as a middle layer between the core UI library and application-specific implementations.
8
+
9
+ ```
10
+ ┌─────────────────────────────────────────┐
11
+ │ Application Layer │
12
+ │ (Consuming Nuxt Projects) │
13
+ └─────────────────┬───────────────────────┘
14
+ │ extends
15
+ ┌─────────────────▼───────────────────────┐
16
+ │ @finema/finework-layer │
17
+ │ • Components │
18
+ │ • Composables │
19
+ │ • Layouts │
20
+ │ • Middleware │
21
+ │ • Constants │
22
+ └─────────────────┬───────────────────────┘
23
+ │ extends
24
+ ┌─────────────────▼───────────────────────┐
25
+ │ @finema/core │
26
+ │ • Base Components │
27
+ │ • Data Loaders │
28
+ │ • Form Utilities │
29
+ │ • Core Composables │
30
+ └─────────────────┬───────────────────────┘
31
+ │ uses
32
+ ┌─────────────────▼───────────────────────┐
33
+ │ @nuxt/ui │
34
+ │ • UI Components │
35
+ │ • Design System │
36
+ │ • Theming │
37
+ └─────────────────────────────────────────┘
38
+ ```
39
+
40
+ ---
41
+
42
+ ## 📦 Module Structure
43
+
44
+ ### 1. Components Layer
45
+
46
+ **Purpose:** Reusable UI components specific to Finework applications
47
+
48
+ ```
49
+ app/components/
50
+ ├── Button/
51
+ │ ├── ActionIcon.vue # Icon-only action buttons
52
+ │ └── Back.vue # Back navigation button
53
+ ├── Layout/
54
+ │ ├── Admin/
55
+ │ │ ├── index.vue # Main admin layout
56
+ │ │ └── Sidebar.vue # Admin sidebar navigation
57
+ │ ├── User/
58
+ │ │ └── index.vue # User-facing layout
59
+ │ └── Apps.vue # App switcher popover
60
+ ├── InfoItemList.vue # Key-value display component
61
+ └── StatusBox.vue # Loading/error/empty states
62
+ ```
63
+
64
+ **Design Principles:**
65
+ - **Composition over Inheritance:** Components compose smaller components
66
+ - **Single Responsibility:** Each component has one clear purpose
67
+ - **Type Safety:** All props and emits are typed
68
+ - **Accessibility:** ARIA labels and keyboard navigation
69
+
70
+ ### 2. Composables Layer
71
+
72
+ **Purpose:** Reusable business logic and state management
73
+
74
+ ```
75
+ app/composables/
76
+ ├── useAuth.ts # Authentication & authorization
77
+ └── useRequestOptions.ts # HTTP request configuration
78
+ ```
79
+
80
+ **Key Patterns:**
81
+ - **Singleton Stores:** Using Pinia for shared state (e.g., `auth.me`)
82
+ - **Computed Properties:** Reactive derived state
83
+ - **Side Effects:** Watchers for state synchronization
84
+
85
+ ### 3. Middleware Layer
86
+
87
+ **Purpose:** Route-level guards and logic
88
+
89
+ ```
90
+ app/middleware/
91
+ ├── auth.ts # Authentication guard
92
+ ├── permissions.ts # Permission-based access
93
+ ├── guest.ts # Guest-only routes
94
+ └── common.ts # Common pre-route logic
95
+ ```
96
+
97
+ **Execution Order:**
98
+ 1. `common.ts` - Always runs first
99
+ 2. `auth.ts` - Checks authentication
100
+ 3. `permissions.ts` - Validates permissions
101
+ 4. `guest.ts` - Redirects authenticated users
102
+
103
+ ### 4. Constants Layer
104
+
105
+ **Purpose:** Centralized configuration and constants
106
+
107
+ ```
108
+ app/constants/
109
+ └── routes.ts # Route definitions
110
+ ```
111
+
112
+ **Benefits:**
113
+ - Type-safe route references
114
+ - Single source of truth
115
+ - Easy refactoring
116
+ - Auto-completion support
117
+
118
+ ---
119
+
120
+ ## 🔄 Data Flow Architecture
121
+
122
+ ### Authentication Flow
123
+
124
+ ```
125
+ ┌──────────────┐
126
+ │ Browser │
127
+ └──────┬───────┘
128
+ │ 1. Navigate to protected route
129
+
130
+ ┌──────────────────────┐
131
+ │ Middleware Chain │
132
+ │ ├─ common.ts │
133
+ │ ├─ auth.ts │
134
+ │ └─ permissions.ts │
135
+ └──────┬───────────────┘
136
+ │ 2. Check token cookie
137
+
138
+ ┌──────────────────────┐
139
+ │ useAuth() │
140
+ │ ├─ token │
141
+ │ ├─ me (store) │
142
+ │ └─ fetchMe() │
143
+ └──────┬───────────────┘
144
+ │ 3. Fetch user if needed
145
+
146
+ ┌──────────────────────┐
147
+ │ API Request │
148
+ │ GET /me │
149
+ │ Authorization: ... │
150
+ └──────┬───────────────┘
151
+ │ 4. Update store
152
+
153
+ ┌──────────────────────┐
154
+ │ Pinia Store │
155
+ │ auth.me.value │
156
+ └──────┬───────────────┘
157
+ │ 5. Render page
158
+
159
+ ┌──────────────────────┐
160
+ │ Page Component │
161
+ └──────────────────────┘
162
+ ```
163
+
164
+ ### Data Loading Flow
165
+
166
+ ```
167
+ ┌──────────────┐
168
+ │ Component │
169
+ │ onMounted() │
170
+ └──────┬───────┘
171
+ │ 1. Call loader.run()
172
+
173
+ ┌──────────────────────┐
174
+ │ useObjectLoader │
175
+ │ (from @finema/core) │
176
+ └──────┬───────────────┘
177
+ │ 2. Make HTTP request
178
+
179
+ ┌──────────────────────┐
180
+ │ useRequestOptions │
181
+ │ ├─ auth() │
182
+ │ ├─ base() │
183
+ │ └─ file() │
184
+ └──────┬───────────────┘
185
+ │ 3. Add headers/config
186
+
187
+ ┌──────────────────────┐
188
+ │ Axios Request │
189
+ └──────┬───────────────┘
190
+ │ 4. Response
191
+
192
+ ┌──────────────────────┐
193
+ │ Loader State │
194
+ │ ├─ status │
195
+ │ │ ├─ isLoading │
196
+ │ │ ├─ isSuccess │
197
+ │ │ └─ isError │
198
+ │ └─ data │
199
+ └──────┬───────────────┘
200
+ │ 5. Reactive update
201
+
202
+ ┌──────────────────────┐
203
+ │ StatusBox │
204
+ │ Shows appropriate │
205
+ │ state │
206
+ └──────────────────────┘
207
+ ```
208
+
209
+ ---
210
+
211
+ ## 🎨 Component Architecture
212
+
213
+ ### StatusBox Pattern
214
+
215
+ **Problem:** Every data-loading component needs to handle:
216
+ - Loading state
217
+ - Error state
218
+ - Empty state
219
+ - Success state
220
+
221
+ **Solution:** `StatusBox` component abstracts this logic
222
+
223
+ ```vue
224
+ <StatusBox :status="loader.status.value" :data="loader.data.value">
225
+ <template #default="{ data }">
226
+ <!-- Only renders when data is successfully loaded -->
227
+ </template>
228
+ </StatusBox>
229
+ ```
230
+
231
+ **Benefits:**
232
+ - Consistent UX across all pages
233
+ - Reduced boilerplate
234
+ - Centralized error handling
235
+ - Easy to update globally
236
+
237
+ ### Layout Pattern
238
+
239
+ **Problem:** Different user roles need different layouts
240
+
241
+ **Solution:** Composable layout components
242
+
243
+ ```
244
+ LayoutAdmin
245
+ ├─ Sidebar (collapsible)
246
+ ├─ Header (user menu, apps)
247
+ └─ Main content area
248
+
249
+ LayoutUser
250
+ ├─ Top navbar
251
+ ├─ Breadcrumbs
252
+ └─ Main content area
253
+ ```
254
+
255
+ **Features:**
256
+ - Responsive design
257
+ - Mobile-friendly
258
+ - Consistent navigation
259
+ - Role-based menus
260
+
261
+ ---
262
+
263
+ ## 🔐 Security Architecture
264
+
265
+ ### Authentication Layers
266
+
267
+ 1. **Cookie-based Token Storage**
268
+ - HttpOnly cookie (set by backend)
269
+ - Secure flag in production
270
+ - SameSite protection
271
+
272
+ 2. **Middleware Guards**
273
+ - Route-level protection
274
+ - Automatic redirects
275
+ - Token validation
276
+
277
+ 3. **Permission System**
278
+ - Module-based permissions
279
+ - Role hierarchy (USER < ADMIN < SUPER)
280
+ - Fine-grained access control
281
+
282
+ ### Permission Matrix
283
+
284
+ ```typescript
285
+ interface IUserAccessLevel {
286
+ pmo: Permission // PMO module access
287
+ clockin: Permission // Clock-in module access
288
+ timesheet: Permission // Timesheet module access
289
+ setting: Permission // Settings module access
290
+ }
291
+
292
+ enum Permission {
293
+ NONE = 'NONE', // No access
294
+ USER = 'USER', // Basic user access
295
+ ADMIN = 'ADMIN', // Admin access
296
+ SUPER = 'SUPER' // Super admin access
297
+ }
298
+ ```
299
+
300
+ **Example Checks:**
301
+
302
+ ```typescript
303
+ // Single permission check
304
+ hasPermission(UserModule.PMO, Permission.ADMIN)
305
+
306
+ // Multiple permission check (OR logic)
307
+ hasPermission(UserModule.PMO, Permission.ADMIN, Permission.SUPER)
308
+
309
+ // Route-level guard
310
+ definePageMeta({
311
+ accessGuard: {
312
+ permissions: ['pmo:ADMIN', 'pmo:SUPER']
313
+ }
314
+ })
315
+ ```
316
+
317
+ ---
318
+
319
+ ## 🚀 Performance Optimizations
320
+
321
+ ### 1. Auto-imports
322
+
323
+ **Configuration:**
324
+ ```typescript
325
+ // nuxt.config.ts
326
+ imports: {
327
+ dirs: ['./constants', './loaders', './helpers', './types']
328
+ }
329
+ ```
330
+
331
+ **Benefits:**
332
+ - Smaller bundle size (tree-shaking)
333
+ - Better DX (no import statements)
334
+ - Faster compilation
335
+
336
+ ### 2. Component Auto-registration
337
+
338
+ All components in `app/components/` are automatically registered:
339
+
340
+ ```vue
341
+ <!-- No import needed -->
342
+ <StatusBox />
343
+ <InfoItemList />
344
+ <ButtonActionIcon />
345
+ ```
346
+
347
+ ### 3. Lazy Loading
348
+
349
+ ```typescript
350
+ // Lazy load heavy components
351
+ const HeavyChart = defineAsyncComponent(() =>
352
+ import('./components/HeavyChart.vue')
353
+ )
354
+ ```
355
+
356
+ ### 4. State Caching
357
+
358
+ ```typescript
359
+ // useAuth caches user data for 1 minute
360
+ const isShouldFetch = () => {
361
+ if (!value.value || !timestamp.value) return true
362
+ return Date.now() - timestamp.value > 1000 * 60 * 1
363
+ }
364
+ ```
365
+
366
+ ---
367
+
368
+ ## 🧪 Testing Strategy
369
+
370
+ ### Component Testing
371
+
372
+ ```typescript
373
+ import { mount } from '@nuxt/test-utils'
374
+ import StatusBox from '~/components/StatusBox.vue'
375
+
376
+ describe('StatusBox', () => {
377
+ it('shows loading state', () => {
378
+ const wrapper = mount(StatusBox, {
379
+ props: {
380
+ status: { isLoading: true },
381
+ data: null
382
+ }
383
+ })
384
+ expect(wrapper.find('Loader').exists()).toBe(true)
385
+ })
386
+ })
387
+ ```
388
+
389
+ ### Integration Testing
390
+
391
+ ```typescript
392
+ import { setup, $fetch } from '@nuxt/test-utils'
393
+
394
+ describe('Auth Flow', () => {
395
+ await setup({
396
+ // Test configuration
397
+ })
398
+
399
+ it('redirects unauthenticated users', async () => {
400
+ const response = await $fetch('/protected-route')
401
+ expect(response.redirected).toBe(true)
402
+ })
403
+ })
404
+ ```
405
+
406
+ ---
407
+
408
+ ## 📊 State Management
409
+
410
+ ### Pinia Stores
411
+
412
+ ```typescript
413
+ // Defined inline in composables
414
+ const me = defineStore('auth.me', () => {
415
+ const value = ref<IUser | null>(null)
416
+ const timestamp = ref<number | null>(null)
417
+
418
+ const set = (user: IUser | null) => {
419
+ value.value = user
420
+ }
421
+
422
+ return { value, set, timestamp }
423
+ })()
424
+ ```
425
+
426
+ **Benefits:**
427
+ - Composition API style
428
+ - TypeScript support
429
+ - Devtools integration
430
+ - SSR-friendly
431
+
432
+ ---
433
+
434
+ ## 🎯 Design Patterns
435
+
436
+ ### 1. Composable Pattern
437
+
438
+ **Purpose:** Reusable stateful logic
439
+
440
+ ```typescript
441
+ export const useAuth = () => {
442
+ // State
443
+ const token = useCookie('token')
444
+
445
+ // Computed
446
+ const isAuthenticated = computed(() => !!token.value)
447
+
448
+ // Methods
449
+ const login = () => { /* ... */ }
450
+
451
+ return { token, isAuthenticated, login }
452
+ }
453
+ ```
454
+
455
+ ### 2. Provider Pattern
456
+
457
+ **Purpose:** Dependency injection
458
+
459
+ ```typescript
460
+ export const useRequestOptions = () => {
461
+ const config = useRuntimeConfig()
462
+
463
+ const auth = () => ({
464
+ baseURL: config.public.baseAPI,
465
+ headers: {
466
+ Authorization: `Bearer ${useAuth().token.value}`
467
+ }
468
+ })
469
+
470
+ return { auth, base, mock, file }
471
+ }
472
+ ```
473
+
474
+ ### 3. Slot Pattern
475
+
476
+ **Purpose:** Flexible component composition
477
+
478
+ ```vue
479
+ <StatusBox :status="status" :data="data">
480
+ <template #default="{ data }">
481
+ <!-- Custom rendering with data -->
482
+ </template>
483
+ </StatusBox>
484
+ ```
485
+
486
+ ### 4. Middleware Chain Pattern
487
+
488
+ **Purpose:** Sequential request processing
489
+
490
+ ```typescript
491
+ // Middleware executes in order
492
+ export default defineNuxtConfig({
493
+ router: {
494
+ middleware: ['common', 'auth', 'permissions']
495
+ }
496
+ })
497
+ ```
498
+
499
+ ---
500
+
501
+ ## 🔧 Configuration Management
502
+
503
+ ### App Config
504
+
505
+ ```typescript
506
+ // app/app.config.ts
507
+ export default defineAppConfig({
508
+ core: {
509
+ is_thai_year: false,
510
+ date_format: 'dd MMM yyyy',
511
+ color: '#335AFF',
512
+ limit_per_page: 10,
513
+ locale: 'en'
514
+ },
515
+ ui: {
516
+ // Nuxt UI customization
517
+ }
518
+ })
519
+ ```
520
+
521
+ ### Runtime Config
522
+
523
+ ```typescript
524
+ // Access in components
525
+ const config = useRuntimeConfig()
526
+ config.public.baseAPI
527
+ ```
528
+
529
+ ---
530
+
531
+ ## 📈 Scalability Considerations
532
+
533
+ ### 1. Module Federation
534
+ - Each feature can be a separate module
535
+ - Lazy load modules on demand
536
+ - Independent deployment possible
537
+
538
+ ### 2. Code Splitting
539
+ - Route-based splitting (automatic)
540
+ - Component-based splitting (manual)
541
+ - Vendor chunk optimization
542
+
543
+ ### 3. Caching Strategy
544
+ - User data cached for 1 minute
545
+ - Static assets cached indefinitely
546
+ - API responses cached per request
547
+
548
+ ---
549
+
550
+ ## 🔍 Debugging Guide
551
+
552
+ ### Common Issues
553
+
554
+ 1. **Auto-import not working**
555
+ - Check `nuxt.config.ts` imports configuration
556
+ - Restart dev server
557
+ - Check file location
558
+
559
+ 2. **Middleware not executing**
560
+ - Check middleware order
561
+ - Verify route meta configuration
562
+ - Check return values
563
+
564
+ 3. **Permission denied**
565
+ - Verify user access_level
566
+ - Check permission constants
567
+ - Review middleware logic
568
+
569
+ ### Debug Tools
570
+
571
+ ```typescript
572
+ // Enable verbose logging
573
+ const auth = useAuth()
574
+ console.log('User:', auth.me.value)
575
+ console.log('Permissions:', auth.me.value?.access_level)
576
+ console.log('Has PMO Admin:', auth.hasPermission(UserModule.PMO, Permission.ADMIN))
577
+ ```
578
+
579
+ ---
580
+
581
+ ## 📚 Further Reading
582
+
583
+ - [Nuxt Layers Documentation](https://nuxt.com/docs/guide/going-further/layers)
584
+ - [Nuxt UI Documentation](https://ui.nuxt.com)
585
+ - [Vue 3 Composition API](https://vuejs.org/guide/extras/composition-api-faq.html)
586
+ - [Pinia Documentation](https://pinia.vuejs.org)
587
+
588
+ ---
589
+
590
+ **Last Updated:** 2025-11-07
591
+ **Version:** 0.2.50
592
+
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.51](https://gitlab.finema.co/finema/finework/finework-frontend-layer/compare/0.2.50...0.2.51) (2025-11-11)
4
+
5
+ ### Bug Fixes
6
+
7
+ * update sidebar navigation and breadcrumb rootpath ([1cbdcf1](https://gitlab.finema.co/finema/finework/finework-frontend-layer/commit/1cbdcf135c35bff66c70a71831193255ea5d302b))
8
+
3
9
  ## [0.2.50](https://gitlab.finema.co/finema/finework/finework-frontend-layer/compare/0.2.49...0.2.50) (2025-11-07)
4
10
 
5
11
  ## [0.2.49](https://gitlab.finema.co/finema/finework/finework-frontend-layer/compare/0.2.48...0.2.49) (2025-11-07)