@flusys/ng-core 0.1.0-beta.1 → 0.1.0-beta.2

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.
Files changed (2) hide show
  1. package/README.md +552 -0
  2. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,552 @@
1
+ # @flusys/ng-core Package Guide
2
+
3
+ ## Overview
4
+
5
+ `@flusys/ng-core` is the foundation package that provides core functionality for all FLUSYS Angular libraries and applications. It contains configuration management, HTTP interceptors, base services, and type definitions.
6
+
7
+ **Key Principle:** ng-core has NO internal dependencies on other @flusys packages. All other packages depend on ng-core.
8
+
9
+ ## Package Information
10
+
11
+ - **Package:** `@flusys/ng-core`
12
+ - **Dependencies:** None (base package)
13
+ - **Dependents:** ng-shared, ng-layout, ng-auth, ng-iam, ng-storage, flusysng
14
+ - **Build Command:** `npm run build:ng-core`
15
+
16
+ ## Package Structure
17
+
18
+ ```
19
+ ng-core/
20
+ ├── components/
21
+ │ └── lib-app-config/
22
+ │ ├── lib-app-config.component.ts
23
+ │ ├── lib-app-config.component.html
24
+ │ └── lib-app-config.component.scss
25
+ ├── interceptors/
26
+ │ ├── api-loader.interceptor.ts
27
+ │ └── error-catching.interceptor.ts
28
+ ├── interfaces/
29
+ │ └── app-config.interface.ts
30
+ ├── services/
31
+ │ ├── api-loader.service.ts
32
+ │ └── base-api.service.ts
33
+ └── public-api.ts
34
+ ```
35
+
36
+ ## Public API Exports
37
+
38
+ ```typescript
39
+ // Components
40
+ export * from './components/lib-app-config/lib-app-config.component';
41
+
42
+ // Interceptors
43
+ export * from './interceptors/api-loader.interceptor';
44
+ export * from './interceptors/error-catching.interceptor';
45
+
46
+ // Interfaces
47
+ export * from './interfaces/app-config.interface';
48
+
49
+ // Services
50
+ export * from './services/api-loader.service';
51
+ export * from './services/base-api.service';
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Features
57
+
58
+ ### 1. APP_CONFIG (Configuration Management)
59
+
60
+ Centralized configuration system with dynamic service URLs and feature flags.
61
+
62
+ #### IAppConfig Interface
63
+
64
+ ```typescript
65
+ export type PermissionMode = 'rbac' | 'direct' | 'full';
66
+
67
+ export interface IServiceConfig {
68
+ baseUrl: string;
69
+ enabled: boolean;
70
+ }
71
+
72
+ export interface IAppConfig {
73
+ appName: string;
74
+ apiBaseUrl: string; // Default fallback URL
75
+ enableCompanyFeature: boolean; // Company/branch selection
76
+
77
+ services: {
78
+ auth: IServiceConfig;
79
+ iam: IServiceConfig;
80
+ storage: IServiceConfig;
81
+ [key: string]: IServiceConfig; // Extensible for custom services
82
+ };
83
+
84
+ multiTenant: {
85
+ enabled: boolean; // true = multi-tenant DB, false = single DB
86
+ tenantHeader: string; // Header name (e.g., 'x-tenant-id')
87
+ tenantId?: string; // Optional tenant ID value
88
+ };
89
+
90
+ permissionMode?: PermissionMode; // Defaults to 'full'
91
+ }
92
+ ```
93
+
94
+ #### APP_CONFIG Token
95
+
96
+ ```typescript
97
+ export const APP_CONFIG = new InjectionToken<IAppConfig>('APP_CONFIG');
98
+ ```
99
+
100
+ **Provider setup in app.config.ts:**
101
+
102
+ ```typescript
103
+ import { APP_CONFIG } from '@flusys/ng-core';
104
+ import { DEFAULT_APP_CONFIG } from './config/app.config';
105
+
106
+ export const appConfig: ApplicationConfig = {
107
+ providers: [
108
+ { provide: APP_CONFIG, useValue: DEFAULT_APP_CONFIG },
109
+ ]
110
+ };
111
+ ```
112
+
113
+ #### Environment Structure (Shared Base Pattern)
114
+
115
+ All common configuration is extracted to a shared base:
116
+
117
+ ```typescript
118
+ // projects/flusysng/src/environments/environment.base.ts
119
+ export const BASE_ENVIRONMENT = {
120
+ appName: 'FLUSYS',
121
+ multiTenant: { enabled: false, tenantHeader: 'x-tenant-id' },
122
+ storage: { apiPath: '/upload/file', maxFileSize: 10485760, allowedMimeTypes: [...] },
123
+ };
124
+
125
+ // projects/flusysng/src/environments/environment.ts (development)
126
+ import { BASE_ENVIRONMENT } from './environment.base';
127
+
128
+ export const environment = {
129
+ ...BASE_ENVIRONMENT,
130
+ production: false,
131
+ apiBaseUrl: 'http://localhost:2002',
132
+ services: {
133
+ auth: { baseUrl: 'http://localhost:2002/auth', enabled: true },
134
+ iam: { baseUrl: 'http://localhost:2002/iam', enabled: true },
135
+ storage: { baseUrl: 'http://localhost:2002/storage', enabled: true },
136
+ },
137
+ };
138
+ ```
139
+
140
+ #### Helper Functions
141
+
142
+ ```typescript
143
+ import {
144
+ getDatabaseMode,
145
+ isFeatureEnabled,
146
+ getServiceUrl,
147
+ isServiceEnabled,
148
+ isCompanyFeatureEnabled,
149
+ isStorageFeatureEnabled,
150
+ getPermissionMode,
151
+ } from '@flusys/ng-core';
152
+ ```
153
+
154
+ | Function | Signature | Description |
155
+ |----------|-----------|-------------|
156
+ | `getDatabaseMode` | `(config) → 'single' \| 'multi-tenant'` | Get database mode from `multiTenant.enabled` |
157
+ | `isFeatureEnabled` | `(config, feature: 'auth' \| 'iam' \| 'storage') → boolean` | Check if a service feature is enabled |
158
+ | `getServiceUrl` | `(config, serviceName) → string` | Get service URL or fallback to `apiBaseUrl` |
159
+ | `isServiceEnabled` | `(config, serviceName) → boolean` | Check if a service is enabled |
160
+ | `isCompanyFeatureEnabled` | `(config) → boolean` | Check `enableCompanyFeature` flag |
161
+ | `isStorageFeatureEnabled` | `(config) → boolean` | Check `services.storage.enabled` |
162
+ | `getPermissionMode` | `(config) → PermissionMode` | Get permission mode (defaults to `'full'`) |
163
+
164
+ #### Constants
165
+
166
+ ```typescript
167
+ export const DEFAULT_APP_NAME = 'FLUSYS';
168
+ ```
169
+
170
+ #### Configuration Modes
171
+
172
+ **Mode 1: Simple (No Company, No IAM)**
173
+ ```typescript
174
+ {
175
+ enableCompanyFeature: false,
176
+ multiTenant: { enabled: false, tenantHeader: 'x-tenant-id' },
177
+ services: {
178
+ auth: { baseUrl: '...', enabled: false },
179
+ iam: { baseUrl: '...', enabled: false },
180
+ storage: { baseUrl: '...', enabled: false },
181
+ }
182
+ }
183
+ ```
184
+
185
+ **Mode 2: Single DB + Multi-Company**
186
+ ```typescript
187
+ {
188
+ enableCompanyFeature: true,
189
+ multiTenant: { enabled: false, tenantHeader: 'x-tenant-id' },
190
+ services: {
191
+ auth: { baseUrl: 'http://localhost:2002/auth', enabled: true },
192
+ iam: { baseUrl: 'http://localhost:2002/iam', enabled: true },
193
+ storage: { baseUrl: 'http://localhost:2002/storage', enabled: true },
194
+ }
195
+ }
196
+ ```
197
+
198
+ **Mode 3: Multi-Tenant**
199
+ ```typescript
200
+ {
201
+ enableCompanyFeature: true,
202
+ multiTenant: { enabled: true, tenantHeader: 'x-tenant-id', tenantId: 'tenant-123' },
203
+ services: {
204
+ auth: { baseUrl: 'http://localhost:2002/auth', enabled: true },
205
+ iam: { baseUrl: 'http://localhost:2002/iam', enabled: true },
206
+ storage: { baseUrl: 'http://localhost:2002/storage', enabled: true },
207
+ }
208
+ }
209
+ ```
210
+
211
+ ---
212
+
213
+ ### 2. HTTP Interceptors
214
+
215
+ ng-core provides two functional interceptors. Both use the modern Angular functional interceptor pattern.
216
+
217
+ #### apiLoaderInterceptor
218
+
219
+ Tracks HTTP request loading state with tagged loaders. Uses a custom `x-loader-tag` header to group related requests.
220
+
221
+ **Behavior:**
222
+ 1. Reads `x-loader-tag` header from request (defaults to `'default'`)
223
+ 2. Increments loader count for that tag
224
+ 3. Removes `x-loader-tag` header before sending to backend
225
+ 4. Decrements loader count on request completion (success or error)
226
+
227
+ ```typescript
228
+ import { apiLoaderInterceptor } from '@flusys/ng-core';
229
+
230
+ // Tag a specific request
231
+ this.http.post('/api/users/get-all', filter, {
232
+ headers: new HttpHeaders({ 'x-loader-tag': 'users-list' })
233
+ });
234
+
235
+ // Check loading state for that tag
236
+ apiLoaderService.getLoader('users-list')(); // true while loading
237
+ ```
238
+
239
+ #### errorCatchingInterceptor
240
+
241
+ Displays user-friendly error toast messages for failed HTTP requests via PrimeNG `MessageService`.
242
+
243
+ **Behavior:**
244
+ - Skips 401 errors (handled by `tokenRefreshInterceptor` in ng-auth)
245
+ - Skips `/check-login` endpoint errors (expected to fail when not logged in)
246
+ - Extracts message from `error.error.message` (string or array), `error.message`, or fallback
247
+ - SSR-safe: only displays messages in browser (`isPlatformBrowser` check)
248
+
249
+ #### Interceptor Chain
250
+
251
+ ```typescript
252
+ import { errorCatchingInterceptor, apiLoaderInterceptor } from '@flusys/ng-core';
253
+ import { authInterceptor, tokenRefreshInterceptor } from '@flusys/ng-auth';
254
+
255
+ provideHttpClient(
256
+ withFetch(),
257
+ withInterceptors([
258
+ authInterceptor, // from @flusys/ng-auth (adds auth + tenant headers)
259
+ tokenRefreshInterceptor, // from @flusys/ng-auth (handles 401 + token refresh)
260
+ errorCatchingInterceptor, // from @flusys/ng-core (displays error toasts)
261
+ apiLoaderInterceptor, // from @flusys/ng-core (tracks loading state)
262
+ ])
263
+ )
264
+ ```
265
+
266
+ **Order matters:** Auth interceptors first, then error handling, then loader tracking.
267
+
268
+ ---
269
+
270
+ ### 3. Services
271
+
272
+ #### ApiLoaderService
273
+
274
+ Signal-based loading state management with tagged loaders. Provided at root level.
275
+
276
+ **Signals:**
277
+
278
+ | Signal | Type | Description |
279
+ |--------|------|-------------|
280
+ | `show` | `Signal<boolean>` | `true` if ANY loader tag has active requests |
281
+
282
+ **Methods:**
283
+
284
+ | Method | Parameters | Description |
285
+ |--------|-----------|-------------|
286
+ | `increase(name?)` | `name: string = 'default'` | Increment loader count for a tag |
287
+ | `decrease(name?)` | `name: string = 'default'` | Decrement loader count for a tag (min 0) |
288
+ | `getLoader(name)` | `name: string` | Get computed `Signal<boolean>` for a specific tag |
289
+
290
+ **Properties:**
291
+
292
+ | Property | Type | Description |
293
+ |----------|------|-------------|
294
+ | `DEFAULT_TAG` | `string` | Default tag name (`'default'`) |
295
+
296
+ **Usage:**
297
+
298
+ ```typescript
299
+ // Global loading state
300
+ @if (apiLoaderService.show()) {
301
+ <p-progressBar mode="indeterminate" />
302
+ }
303
+
304
+ // Tag-specific loading state
305
+ @if (apiLoaderService.getLoader('users-list')()) {
306
+ <p>Loading users...</p>
307
+ }
308
+ ```
309
+
310
+ #### BaseApiService
311
+
312
+ Abstract base class for API services. Provides automatic URL resolution from APP_CONFIG.
313
+
314
+ **Protected members:**
315
+
316
+ | Member | Type | Description |
317
+ |--------|------|-------------|
318
+ | `http` | `HttpClient` | Injected HTTP client |
319
+ | `appConfig` | `IAppConfig` | Injected app configuration |
320
+ | `baseUrl` | `string` | Resolved base URL for the service |
321
+
322
+ **Protected methods:**
323
+
324
+ | Method | Parameters | Returns | Description |
325
+ |--------|-----------|---------|-------------|
326
+ | `getUrl(endpoint)` | `endpoint: string` | `string` | Build full URL, removes leading slash to avoid double slashes |
327
+
328
+ **Usage:**
329
+
330
+ ```typescript
331
+ @Injectable({ providedIn: 'root' })
332
+ export class UserApiService extends BaseApiService {
333
+ constructor() {
334
+ super('auth'); // Resolves to services.auth.baseUrl
335
+ }
336
+
337
+ getAll(filter: any) {
338
+ return this.http.post(this.getUrl('user/get-all'), filter);
339
+ }
340
+
341
+ getById(id: string) {
342
+ return this.http.post(`${this.getUrl('user/get')}/${id}`, {});
343
+ }
344
+ }
345
+ ```
346
+
347
+ ---
348
+
349
+ ### 4. Components
350
+
351
+ #### LibAppConfigComponent
352
+
353
+ Root configuration component providing global UI elements. Include once at app root.
354
+
355
+ **Selector:** `lib-app-config`
356
+
357
+ **Provides:**
358
+ - Global loading progress bar (fixed top, 4px height, z-index 998)
359
+ - Toast notifications (PrimeNG Toast)
360
+ - Confirm dialogs (PrimeNG ConfirmDialog)
361
+
362
+ **Template:**
363
+ ```html
364
+ @if (apiLoaderService.show()) {
365
+ <p-progressBar mode="indeterminate" />
366
+ }
367
+ <p-toast />
368
+ <p-confirmdialog />
369
+ ```
370
+
371
+ **Usage:**
372
+ ```typescript
373
+ import { LibAppConfigComponent } from '@flusys/ng-core';
374
+
375
+ @Component({
376
+ selector: 'app-root',
377
+ standalone: true,
378
+ imports: [LibAppConfigComponent, RouterOutlet],
379
+ template: `
380
+ <lib-app-config />
381
+ <router-outlet />
382
+ `
383
+ })
384
+ export class AppComponent {}
385
+ ```
386
+
387
+ ---
388
+
389
+ ## Usage Examples
390
+
391
+ ### Basic App Setup
392
+
393
+ ```typescript
394
+ // app.config.ts
395
+ import { ApplicationConfig } from '@angular/core';
396
+ import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
397
+ import { APP_CONFIG, errorCatchingInterceptor, apiLoaderInterceptor } from '@flusys/ng-core';
398
+ import { authInterceptor, tokenRefreshInterceptor } from '@flusys/ng-auth';
399
+ import { DEFAULT_APP_CONFIG } from './config/app.config';
400
+
401
+ export const appConfig: ApplicationConfig = {
402
+ providers: [
403
+ provideHttpClient(
404
+ withFetch(),
405
+ withInterceptors([
406
+ authInterceptor,
407
+ tokenRefreshInterceptor,
408
+ errorCatchingInterceptor,
409
+ apiLoaderInterceptor,
410
+ ])
411
+ ),
412
+ { provide: APP_CONFIG, useValue: DEFAULT_APP_CONFIG },
413
+ ]
414
+ };
415
+ ```
416
+
417
+ ### Creating an API Service
418
+
419
+ ```typescript
420
+ import { Injectable } from '@angular/core';
421
+ import { BaseApiService } from '@flusys/ng-core';
422
+
423
+ @Injectable({ providedIn: 'root' })
424
+ export class AuthApiService extends BaseApiService {
425
+ constructor() {
426
+ super('auth'); // Resolves to services.auth.baseUrl
427
+ }
428
+
429
+ login(credentials: any) {
430
+ return this.http.post(this.getUrl('auth/login'), credentials);
431
+ }
432
+ }
433
+ ```
434
+
435
+ ### Using Tagged Loaders
436
+
437
+ ```typescript
438
+ import { HttpHeaders } from '@angular/common/http';
439
+ import { ApiLoaderService } from '@flusys/ng-core';
440
+
441
+ // In a service - tag requests
442
+ this.http.post('/api/users/get-all', filter, {
443
+ headers: new HttpHeaders({ 'x-loader-tag': 'users-list' })
444
+ });
445
+
446
+ // In a component - check specific loader
447
+ readonly usersLoading = this.apiLoaderService.getLoader('users-list');
448
+
449
+ // In template
450
+ @if (usersLoading()) {
451
+ <p-skeleton />
452
+ }
453
+ ```
454
+
455
+ ---
456
+
457
+ ## Best Practices
458
+
459
+ 1. **Always provide APP_CONFIG** at application root level
460
+ 2. **Match backend configuration mode** (`multiTenant.enabled` should align with FLUSYS_NEST setup)
461
+ 3. **Enable features based on backend availability** (`services.iam.enabled` only if IAM module is deployed)
462
+ 4. **Never import from other @flusys packages** in ng-core
463
+ 5. **Keep ng-core minimal** - only foundation functionality
464
+ 6. **Use `BaseApiService`** for all API services to avoid hardcoded URLs
465
+ 7. **Don't create custom error handling** - use `errorCatchingInterceptor`
466
+ 8. **Don't manually track loading** - use `apiLoaderInterceptor` with `x-loader-tag` headers
467
+
468
+ ## Common Issues
469
+
470
+ ### APP_CONFIG Not Found
471
+
472
+ **Problem:** `NullInjectorError: No provider for InjectionToken APP_CONFIG`
473
+
474
+ **Solution:** Provide APP_CONFIG in app.config.ts:
475
+ ```typescript
476
+ { provide: APP_CONFIG, useValue: DEFAULT_APP_CONFIG }
477
+ ```
478
+
479
+ ### Circular Dependency
480
+
481
+ **Problem:** Build fails with circular dependency error involving ng-core.
482
+
483
+ **Solution:** ng-core should NEVER import from other @flusys packages. Check imports and remove any references to ng-shared, ng-layout, or ng-auth.
484
+
485
+ ---
486
+
487
+ ## API Reference
488
+
489
+ ### Tokens
490
+
491
+ | Token | Type | Description |
492
+ |-------|------|-------------|
493
+ | `APP_CONFIG` | `InjectionToken<IAppConfig>` | Application configuration |
494
+
495
+ ### Interceptors
496
+
497
+ | Function | Description |
498
+ |----------|-------------|
499
+ | `apiLoaderInterceptor` | Loading state management with tagged loaders |
500
+ | `errorCatchingInterceptor` | Error toast display (skips 401 and check-login) |
501
+
502
+ ### Services
503
+
504
+ | Service | Description |
505
+ |---------|-------------|
506
+ | `ApiLoaderService` | Signal-based loading state with tagged loaders |
507
+ | `BaseApiService` | Abstract base class for API services with URL resolution |
508
+
509
+ ### Interfaces & Types
510
+
511
+ | Export | Description |
512
+ |--------|-------------|
513
+ | `IAppConfig` | App configuration interface |
514
+ | `IServiceConfig` | Service configuration (`baseUrl`, `enabled`) |
515
+ | `PermissionMode` | `'rbac' \| 'direct' \| 'full'` |
516
+
517
+ ### Helper Functions
518
+
519
+ | Function | Description |
520
+ |----------|-------------|
521
+ | `getDatabaseMode(config)` | Returns `'single'` or `'multi-tenant'` |
522
+ | `isFeatureEnabled(config, feature)` | Check service feature enabled (`'auth' \| 'iam' \| 'storage'`) |
523
+ | `getServiceUrl(config, serviceName)` | Get service URL with fallback |
524
+ | `isServiceEnabled(config, serviceName)` | Check if service is enabled |
525
+ | `isCompanyFeatureEnabled(config)` | Check company feature flag |
526
+ | `isStorageFeatureEnabled(config)` | Check storage service enabled |
527
+ | `getPermissionMode(config)` | Get permission mode (default `'full'`) |
528
+
529
+ ### Constants
530
+
531
+ | Constant | Value | Description |
532
+ |----------|-------|-------------|
533
+ | `DEFAULT_APP_NAME` | `'FLUSYS'` | Default application name |
534
+
535
+ ### Components
536
+
537
+ | Component | Selector | Description |
538
+ |-----------|----------|-------------|
539
+ | `LibAppConfigComponent` | `lib-app-config` | Global toast, confirm dialog, and loading bar |
540
+
541
+ ## See Also
542
+
543
+ - **[SHARED-GUIDE.md](./SHARED-GUIDE.md)** - API services, components, directives
544
+ - **[LAYOUT-GUIDE.md](./LAYOUT-GUIDE.md)** - Layout system
545
+ - **[Angular Patterns](../../.claude/docs/angular/)** - Framework patterns
546
+ - **[FLUSYS_NEST/docs/CORE-GUIDE.md](../../FLUSYS_NEST/docs/CORE-GUIDE.md)** - Backend core module
547
+
548
+ ---
549
+
550
+ **Last Updated:** 2026-02-07
551
+ **Package Version:** 1.0.0
552
+ **Angular Version:** 21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/ng-core",
3
- "version": "0.1.0-beta.1",
3
+ "version": "0.1.0-beta.2",
4
4
  "description": "Core utilities and services for FLUSYS Angular packages",
5
5
  "license": "MIT",
6
6
  "peerDependencies": {