@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.
- package/README.md +552 -0
- 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
|