@bluealba/platform-cli 1.0.1 → 1.1.0

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 (52) hide show
  1. package/dist/index.js +278 -15
  2. package/docs/404.mdx +5 -0
  3. package/docs/architecture/api-explorer.mdx +478 -0
  4. package/docs/architecture/architecture-diagrams.mdx +12 -0
  5. package/docs/architecture/authentication-system.mdx +903 -0
  6. package/docs/architecture/authorization-system.mdx +886 -0
  7. package/docs/architecture/bootstrap.mdx +1442 -0
  8. package/docs/architecture/gateway-architecture.mdx +845 -0
  9. package/docs/architecture/multi-tenancy.mdx +1150 -0
  10. package/docs/architecture/overview.mdx +776 -0
  11. package/docs/architecture/scheduler.mdx +818 -0
  12. package/docs/architecture/shell.mdx +885 -0
  13. package/docs/architecture/ui-extension-points.mdx +781 -0
  14. package/docs/architecture/user-states.mdx +794 -0
  15. package/docs/development/overview.mdx +21 -0
  16. package/docs/development/workflow.mdx +914 -0
  17. package/docs/getting-started/core-concepts.mdx +892 -0
  18. package/docs/getting-started/installation.mdx +780 -0
  19. package/docs/getting-started/overview.mdx +83 -0
  20. package/docs/getting-started/quick-start.mdx +940 -0
  21. package/docs/guides/adding-documentation-sites.mdx +1367 -0
  22. package/docs/guides/creating-services.mdx +1736 -0
  23. package/docs/guides/creating-ui-modules.mdx +1860 -0
  24. package/docs/guides/identity-providers.mdx +1007 -0
  25. package/docs/guides/mermaid-diagrams.mdx +212 -0
  26. package/docs/guides/using-feature-flags.mdx +1059 -0
  27. package/docs/guides/working-with-rooms.mdx +566 -0
  28. package/docs/index.mdx +57 -0
  29. package/docs/platform-cli/commands.mdx +604 -0
  30. package/docs/platform-cli/overview.mdx +195 -0
  31. package/package.json +5 -2
  32. package/skills/ba-platform/platform-cli.skill.md +26 -0
  33. package/skills/ba-platform/platform.skill.md +35 -0
  34. package/templates/application-monorepo-template/gitignore +95 -0
  35. package/templates/bootstrap-service-template/Dockerfile.development +1 -1
  36. package/templates/bootstrap-service-template/gitignore +57 -0
  37. package/templates/bootstrap-service-template/package.json +1 -1
  38. package/templates/bootstrap-service-template/src/main.ts +6 -16
  39. package/templates/customization-ui-module-template/Dockerfile.development +1 -1
  40. package/templates/customization-ui-module-template/gitignore +73 -0
  41. package/templates/nestjs-service-module-template/Dockerfile.development +1 -1
  42. package/templates/nestjs-service-module-template/gitignore +56 -0
  43. package/templates/platform-init-template/{{platformName}}-core/gitignore +97 -0
  44. package/templates/platform-init-template/{{platformName}}-core/local/.env.example +1 -1
  45. package/templates/platform-init-template/{{platformName}}-core/local/platform-docker-compose.yml +1 -1
  46. package/templates/platform-init-template/{{platformName}}-core/local/{{platformName}}-core-docker-compose.yml +0 -1
  47. package/templates/react-ui-module-template/Dockerfile +1 -1
  48. package/templates/react-ui-module-template/Dockerfile.development +1 -3
  49. package/templates/react-ui-module-template/caddy/Caddyfile +1 -1
  50. package/templates/react-ui-module-template/gitignore +72 -0
  51. package/templates/react-ui-module-template/Dockerfile_nginx +0 -11
  52. package/templates/react-ui-module-template/nginx/default.conf +0 -23
@@ -0,0 +1,1059 @@
1
+ ---
2
+ title: Using Feature Flags
3
+ description: Complete guide to implementing feature flags in the Blue Alba Platform for controlled feature rollouts, A/B testing, and dynamic configuration
4
+ ---
5
+
6
+ import { Card, CardGrid, Aside, Tabs, TabItem } from '@astrojs/starlight/components';
7
+ import MermaidDiagram from '~/components/MermaidDiagram.astro';
8
+
9
+ Feature flags (also called feature toggles) are a powerful technique that allows you to control feature availability dynamically without deploying new code. The Blue Alba Platform provides a comprehensive feature flags system backed by PostgreSQL with composable conditions and typed values.
10
+
11
+ ## Overview
12
+
13
+ The platform's feature flags system enables teams to:
14
+
15
+ - **Toggle features dynamically** - Enable/disable features without redeployment
16
+ - **Target specific users/tenants** - Release features to specific audiences
17
+ - **Return typed values** - Flags can return any value type, not just booleans
18
+ - **Reduce deployment risk** - Deploy code with features disabled, enable when ready
19
+ - **Organize by application** - Associate flags with the application that owns them
20
+
21
+ ### Key Benefits
22
+
23
+ <CardGrid stagger>
24
+ <Card title="Progressive Rollouts" icon="rocket">
25
+ Release features gradually to control risk. Use percentage-based rollout with consistent hashing to ensure users always see the same variant.
26
+ </Card>
27
+
28
+ <Card title="Instant Rollback" icon="setting">
29
+ Disable problematic features instantly without rolling back deployments or redeploying code.
30
+ </Card>
31
+
32
+ <Card title="Tenant Isolation" icon="lock">
33
+ Enable features for specific tenants while keeping them disabled for others.
34
+ </Card>
35
+
36
+ <Card title="Application Ownership" icon="document">
37
+ Associate each flag with the application that owns it, making it easier to manage and filter flags across a large platform.
38
+ </Card>
39
+ </CardGrid>
40
+
41
+ ---
42
+
43
+ ## Architecture
44
+
45
+ The feature flags system is a direct database-backed implementation with no provider abstraction layer. The service composes three focused collaborators — `ConditionEvaluatorService`, `RolloutService`, and `FeatureFlagsDatabaseService` — all wired together in the gateway.
46
+
47
+ <MermaidDiagram
48
+ title="Feature Flags Architecture"
49
+ code={`graph TB
50
+ subgraph Client["Client Applications"]
51
+ UI[React UI<br/>useFeatureFlag]
52
+ end
53
+
54
+ subgraph Gateway["Gateway Service"]
55
+ API[Feature Flags<br/>Controller]
56
+ Core[Feature Flags<br/>Service]
57
+ Cond[Condition<br/>Evaluator]
58
+ Rollout[Rollout<br/>Service]
59
+ DB2[Database<br/>Service]
60
+ end
61
+
62
+ subgraph Backend["Backend Services"]
63
+ SVC[NestJS Service<br/>FeatureFlagsClientService<br/>@FeatureFlags decorator]
64
+ end
65
+
66
+ subgraph Storage["Storage"]
67
+ DB[(PostgreSQL<br/>Database)]
68
+ end
69
+
70
+ UI -->|HTTP| API
71
+ API --> Core
72
+ Core --> Cond
73
+ Core --> Rollout
74
+ Core --> DB2
75
+ DB2 -->|Direct| DB
76
+ Gateway -->|x-forwarded-feature-flags| SVC
77
+
78
+ classDef client fill:#87CEEB,color:#333
79
+ classDef gateway fill:#90EE90,color:#333
80
+ classDef storage fill:#FFD700,color:#333
81
+ classDef backend fill:#DDA0DD,color:#333
82
+
83
+ class UI client
84
+ class API,Core,Cond,Rollout,DB2 gateway
85
+ class SVC backend
86
+ class DB storage`}
87
+ />
88
+
89
+ ### Architecture Components
90
+
91
+ - **Client SDKs**: React hooks library (`useFeatureFlag`, `FeatureFlagGuard`) for consuming feature flags in UI applications
92
+ - **Backend SDKs**: NestJS utilities (`FeatureFlagsClientService`, `@FeatureFlags` decorator) from `@bluealba/pae-service-nestjs-sdk` for consuming feature flags in backend services via the `x-forwarded-feature-flags` header
93
+ - **Gateway API**: REST endpoints for evaluating and managing feature flags
94
+ - **Feature Flags Service**: Orchestrates evaluation logic by composing the three collaborators below
95
+ - **Condition Evaluator**: Evaluates leaf and composite conditions against the request context
96
+ - **Rollout Service**: Applies consistent hash-based percentage rollout gating
97
+ - **Database Service**: Direct PostgreSQL access for reading and writing flag configurations
98
+
99
+ This architecture provides:
100
+ - **Consistency**: Same API across frontend and backend
101
+ - **Performance**: Bulk evaluation support
102
+ - **Self-Contained**: Requires no external services
103
+
104
+ ---
105
+
106
+ ## Core Concepts
107
+
108
+ ### Feature Flags
109
+
110
+ A feature flag is a configuration entry that controls the value returned for a feature in a given context. Each flag has:
111
+
112
+ - **name**: Unique identifier for the flag (e.g., `new-dashboard`)
113
+ - **description**: Human-readable explanation of what the flag controls
114
+ - **visible**: Boolean master switch; when `false` the flag is inactive and evaluation returns `null` (not `defaultValue`). The simulate endpoint returns `defaultValue` with reason `FLAG_INACTIVE` for easier debugging.
115
+ - **defaultValue**: The value returned when no `valueRule` matches the current context
116
+ - **valueRules**: Ordered array of rules evaluated in sequence; the first matching rule's value is returned
117
+ - **application**: The platform application this flag belongs to (optional but strongly recommended)
118
+
119
+ ### Application Association
120
+
121
+ Each feature flag can be associated with a specific platform application. This association:
122
+
123
+ - **Identifies ownership** - Makes it clear which application or team is responsible for a flag
124
+ - **Enables filtering** - The Admin UI allows filtering the flags list by application, which is essential when the platform hosts many flags across multiple applications
125
+ - **Supports bootstrap** - When declaring flags in bootstrap configuration, you can reference an application by name and the platform resolves the association automatically
126
+
127
+ <Aside type="tip">
128
+ Although the `application` field is optional at the API level, assigning every feature flag to an application is strongly recommended. As the number of flags grows across the platform, the application association becomes the primary way to organize and locate flags in the Admin UI.
129
+ </Aside>
130
+
131
+ An application is identified by its **internal name** (e.g., `pae-features`) when used in bootstrap or API calls, while the Admin UI presents its **display name** (e.g., `Features`) for readability.
132
+
133
+ ```typescript
134
+ interface Application {
135
+ id: number;
136
+ name: string; // Internal application name, used in API/bootstrap
137
+ displayName: string; // Human-readable name, shown in Admin UI
138
+ }
139
+ ```
140
+
141
+ ### Feature Flag Context
142
+
143
+ When evaluating feature flags, the system uses a flat context interface to make targeting decisions. The context contains information about the current user, tenant, and any additional properties your application needs.
144
+
145
+ ```typescript
146
+ interface FeatureFlagContext {
147
+ username?: string; // Current username
148
+ tenant?: string; // Current tenant identifier
149
+ [key: string]: string | number | boolean | undefined; // Additional custom attributes
150
+ }
151
+ ```
152
+
153
+ <Aside type="note">
154
+ The context interface is intentionally flat. Unlike the legacy model there is no nested `properties` bag — custom attributes are placed directly on the context object. The special attribute name `user` in a condition maps to `context.username`.
155
+ </Aside>
156
+
157
+ ### Value Rules
158
+
159
+ Value rules are the targeting rules that determine what value a flag returns for a given context.
160
+
161
+ **Value Rule Structure:**
162
+
163
+ ```typescript
164
+ interface ValueRule {
165
+ name?: string; // Optional human-readable identifier (improves log messages)
166
+ condition: LeafCondition | CompositeCondition; // Targeting condition
167
+ value: any; // Value to return when condition matches
168
+ rollout?: RolloutConfig; // Optional percentage-based rollout
169
+ }
170
+ ```
171
+
172
+ **How Value Rules Work:**
173
+
174
+ - Rules are evaluated **in insertion order (by database `id`)** against the current context
175
+ - The **first rule whose condition matches** wins; its `value` is returned immediately
176
+ - If **no rule matches**, the flag's `defaultValue` is returned
177
+ - If the flag's `visible` field is `false`, evaluation is skipped entirely and `null` is returned (not `defaultValue`)
178
+
179
+ ### Conditions
180
+
181
+ Conditions are the building blocks of value rule targeting. There are two kinds: leaf conditions and composite conditions. They can be nested arbitrarily deep.
182
+
183
+ #### Leaf Conditions
184
+
185
+ A leaf condition compares a single context attribute against a value or set of values.
186
+
187
+ ```typescript
188
+ interface LeafCondition {
189
+ attribute: string; // Context attribute to inspect (e.g., 'tenant', 'role')
190
+ operator: 'eq' | 'neq' | 'in' | 'nin'; // Comparison operator
191
+ value: string | number | boolean | Array<string | number | boolean>;
192
+ }
193
+ ```
194
+
195
+ **Operators:**
196
+
197
+ | Operator | Description | Example Use Case |
198
+ |----------|-------------|------------------|
199
+ | `eq` | Attribute equals value | Target a single tenant |
200
+ | `neq` | Attribute does not equal value | Exclude a specific user |
201
+ | `in` | Attribute is in the list | Target a set of tenants or roles |
202
+ | `nin` | Attribute is NOT in the list | Exclude a set of users |
203
+
204
+ <Aside type="note">
205
+ The attribute name `user` is a reserved alias that maps to `context.username`. For all other attributes, the name must match a key on the `FeatureFlagContext` object.
206
+ </Aside>
207
+
208
+ **Example Leaf Condition:**
209
+
210
+ ```typescript
211
+ {
212
+ attribute: 'tenant',
213
+ operator: 'in',
214
+ value: ['premium-tenant-1', 'premium-tenant-2']
215
+ }
216
+ ```
217
+
218
+ #### Composite Conditions
219
+
220
+ Composite conditions combine multiple conditions using a logical operator. They are recursive — each entry in `rules` can itself be a leaf or another composite condition.
221
+
222
+ ```typescript
223
+ interface CompositeCondition {
224
+ operator: 'AND' | 'OR';
225
+ rules: Array<LeafCondition | CompositeCondition>;
226
+ }
227
+ ```
228
+
229
+ **Example Composite Condition:**
230
+
231
+ ```typescript
232
+ {
233
+ operator: 'AND',
234
+ rules: [
235
+ {
236
+ attribute: 'tenant',
237
+ operator: 'in',
238
+ value: ['premium-tenant-1', 'premium-tenant-2']
239
+ },
240
+ {
241
+ attribute: 'user',
242
+ operator: 'neq',
243
+ value: 'test-user@example.com'
244
+ }
245
+ ]
246
+ }
247
+ ```
248
+
249
+ This matches users in a premium tenant, excluding the test user.
250
+
251
+ ### Percentage-Based Rollout
252
+
253
+ Value rules support an optional `rollout` configuration that restricts the rule to a percentage of the target population.
254
+
255
+ ```typescript
256
+ interface RolloutConfig {
257
+ percentage: number; // 0–100 (inclusive)
258
+ attribute: string; // Context attribute used as the hashing key
259
+ }
260
+ ```
261
+
262
+ When `rollout` is present, the rule is only applied if the SHA-256 hash of `flagName:attributeValue` falls within the given percentage bucket. This ensures:
263
+
264
+ - **Consistency**: The same user always falls into the same bucket for the same flag
265
+ - **Stability**: Adding or removing other rules does not change which bucket a user belongs to
266
+
267
+ **Example — Roll out to 20% of users:**
268
+
269
+ ```typescript
270
+ {
271
+ condition: {
272
+ attribute: 'tenant',
273
+ operator: 'eq',
274
+ value: 'acme-corp'
275
+ },
276
+ value: true,
277
+ rollout: {
278
+ percentage: 20,
279
+ attribute: 'username'
280
+ }
281
+ }
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Implementation Details
287
+
288
+ The feature flags implementation is built directly into the gateway service. All flag configurations are stored in the gateway's PostgreSQL database and the service directly composes `FeatureFlagsDatabaseService`, `ConditionEvaluatorService`, and `RolloutService` to handle evaluation.
289
+
290
+ ### Capabilities
291
+
292
+ - **Database-Backed Storage**: All flags stored in PostgreSQL
293
+ - **Zero External Dependencies**: No external services required
294
+ - **Typed Values**: Flags can return any value type, not just booleans
295
+ - **Composable Conditions**: Leaf and composite conditions with arbitrary nesting
296
+ - **Ordered Value Rules**: First-match-wins evaluation order (by insertion order)
297
+ - **Percentage Rollouts**: Consistent hash-based rollout with configurable attribute
298
+ - **Application Association**: Flags can be linked to a specific platform application
299
+
300
+ ### Example Feature Flag Structure
301
+
302
+ Here is a complete example of a feature flag with value rules and an application association:
303
+
304
+ ```json
305
+ {
306
+ "name": "advanced-analytics-dashboard",
307
+ "description": "Enable advanced analytics dashboard for specific tenants",
308
+ "visible": true,
309
+ "defaultValue": false,
310
+ "application": {
311
+ "id": 3,
312
+ "name": "pae-analytics",
313
+ "displayName": "Analytics"
314
+ },
315
+ "valueRules": [
316
+ {
317
+ "name": "premium-tenants-no-test",
318
+ "condition": {
319
+ "operator": "AND",
320
+ "rules": [
321
+ {
322
+ "attribute": "tenant",
323
+ "operator": "in",
324
+ "value": ["premium-tenant-1", "premium-tenant-2"]
325
+ },
326
+ {
327
+ "attribute": "user",
328
+ "operator": "neq",
329
+ "value": "test-user@example.com"
330
+ }
331
+ ]
332
+ },
333
+ "value": true
334
+ }
335
+ ]
336
+ }
337
+ ```
338
+
339
+ **Result**: This flag returns `true` for users in `premium-tenant-1` or `premium-tenant-2`, excluding `test-user@example.com`. All other evaluations return the `defaultValue` of `false`. It is owned by the `pae-analytics` application.
340
+
341
+ ---
342
+
343
+ ## Managing Feature Flags in the Admin UI
344
+
345
+ The Platform Admin application (`pae-admin-ui`) provides a dedicated Feature Flags page where you can create, edit, and delete flags, as well as filter them by application.
346
+
347
+ ### Filtering by Application
348
+
349
+ The Feature Flags page includes an **Application selector** in the top bar. Selecting an application filters the table to show only flags that belong to that application. The default value shows flags for all applications.
350
+
351
+ This is the primary way to work with flags when a platform has many applications — each team selects their application to see only the flags they own.
352
+
353
+ ### Creating a Feature Flag
354
+
355
+ To create a new feature flag from the Admin UI:
356
+
357
+ 1. Navigate to **Feature Flags** in the Admin application.
358
+ 2. Click **Add Feature Flag**.
359
+ 3. Fill in the required fields in the dialog:
360
+
361
+ | Field | Required | Description |
362
+ |-------|----------|-------------|
363
+ | **Name** | Yes | Unique identifier. Kebab-case, no spaces (e.g., `new-checkout-flow`). Cannot be changed after creation. |
364
+ | **Application** | Yes | The platform application this flag belongs to. |
365
+ | **Description** | No | Human-readable explanation of what the flag controls. |
366
+ | **Visible** | Yes | Master switch. When off, evaluation always returns the default value. Defaults to `true`. |
367
+ | **Default Value** | No | Value returned when no value rule matches. |
368
+ | **Value Rules** | No | Ordered targeting rules; the first matching rule's value is returned. |
369
+
370
+ 4. Click **Create** to save the flag.
371
+
372
+ <Aside type="note">
373
+ The **Application** field is required in the Admin UI form. This ensures every flag created through the UI is properly organized and discoverable.
374
+ </Aside>
375
+
376
+ ### Editing a Feature Flag
377
+
378
+ To edit an existing flag:
379
+
380
+ 1. Locate the flag in the table (use the Application selector or the search input to narrow down results).
381
+ 2. Click the actions menu (three-dot icon) on the flag row.
382
+ 3. Select **Edit**.
383
+ 4. Update any field except **Name** (the name is immutable after creation).
384
+ 5. Click **Save Changes**.
385
+
386
+ <Aside type="caution">
387
+ When you save an edit that includes changes to value rules, **all existing value rules are replaced** by the new set. This is an atomic replacement, not a merge. If you clear all value rules, the flag will always return its `defaultValue`.
388
+ </Aside>
389
+
390
+ ### Searching and Filtering
391
+
392
+ The Feature Flags table provides two ways to narrow down results:
393
+
394
+ - **Application selector** (top bar): Filters flags by their associated application. Selecting "All Applications" shows every flag regardless of association.
395
+ - **Search input** (above the table): Filters flags whose name or description match the search term.
396
+
397
+ Both filters are applied simultaneously, so you can select an application and then search within it.
398
+
399
+ ---
400
+
401
+ ## Declaring Feature Flags via Bootstrap
402
+
403
+ The bootstrap mechanism allows applications to declare their required feature flags as code, ensuring they are created (or updated) automatically when the platform initializes. This is the recommended way to manage flags for an application — it makes the flag definitions version-controlled and reproducible.
404
+
405
+ For the full reference on configuring `feature-flags.json`, including examples and upsert semantics, see the [Bootstrap Architecture documentation](/_/docs/architecture/bootstrap/#feature-flags-definition).
406
+
407
+ ### Direct API Usage
408
+
409
+ You can also manage flags directly via the gateway REST API (internal endpoint secured at the network level under `/_/`).
410
+
411
+ <Tabs>
412
+ <TabItem label="Create flag">
413
+ ```bash
414
+ POST /_/feature-flags
415
+ Content-Type: application/json
416
+
417
+ {
418
+ "name": "new-checkout-flow",
419
+ "description": "Enable the redesigned checkout experience",
420
+ "visible": true,
421
+ "defaultValue": false,
422
+ "applicationId": 5,
423
+ "valueRules": [
424
+ {
425
+ "name": "premium-tenants",
426
+ "condition": {
427
+ "attribute": "tenant",
428
+ "operator": "in",
429
+ "value": ["premium-tenant-1", "premium-tenant-2"]
430
+ },
431
+ "value": true
432
+ }
433
+ ]
434
+ }
435
+ ```
436
+
437
+ `valueRules` is optional. If omitted, the flag is created with no rules and every evaluation returns `defaultValue`.
438
+ </TabItem>
439
+ <TabItem label="Update flag with value rules">
440
+ ```bash
441
+ PATCH /_/feature-flags/new-checkout-flow
442
+ Content-Type: application/json
443
+
444
+ {
445
+ "visible": true,
446
+ "defaultValue": false,
447
+ "valueRules": [
448
+ {
449
+ "name": "premium-tenants",
450
+ "condition": {
451
+ "attribute": "tenant",
452
+ "operator": "in",
453
+ "value": ["premium-tenant-1", "premium-tenant-2"]
454
+ },
455
+ "value": true
456
+ },
457
+ {
458
+ "name": "admin-internal-50pct",
459
+ "condition": {
460
+ "operator": "AND",
461
+ "rules": [
462
+ { "attribute": "role", "operator": "eq", "value": "admin" },
463
+ { "attribute": "tenant", "operator": "eq", "value": "internal" }
464
+ ]
465
+ },
466
+ "value": true,
467
+ "rollout": {
468
+ "percentage": 50,
469
+ "attribute": "username"
470
+ }
471
+ }
472
+ ]
473
+ }
474
+ ```
475
+ </TabItem>
476
+ <TabItem label="Get all flags">
477
+ ```bash
478
+ GET /_/feature-flags/all
479
+ ```
480
+
481
+ Each flag in the response includes `visible`, `defaultValue`, `valueRules`, and an optional `application` object:
482
+
483
+ ```json
484
+ [
485
+ {
486
+ "id": 12,
487
+ "name": "new-checkout-flow",
488
+ "description": "Enable the redesigned checkout experience",
489
+ "visible": true,
490
+ "defaultValue": false,
491
+ "application": {
492
+ "id": 5,
493
+ "name": "pae-commerce",
494
+ "displayName": "Commerce"
495
+ },
496
+ "valueRules": [],
497
+ "createdAt": "2026-01-10T09:00:00Z",
498
+ "updatedAt": "2026-01-10T09:00:00Z"
499
+ }
500
+ ]
501
+ ```
502
+ </TabItem>
503
+ <TabItem label="Evaluate a flag">
504
+ ```bash
505
+ POST /_/feature-flags/evaluate/new-checkout-flow
506
+ ```
507
+
508
+ This endpoint takes **no request body**. The evaluation context (username, tenant, role) is derived from the authenticated user associated with the request. To test arbitrary contexts without being tied to an authenticated user, use the simulate endpoint instead.
509
+
510
+ Response:
511
+
512
+ ```json
513
+ {
514
+ "flagName": "new-checkout-flow",
515
+ "value": true,
516
+ "evaluatedAt": "2026-01-10T09:00:00Z"
517
+ }
518
+ ```
519
+ </TabItem>
520
+ <TabItem label="Get flag details">
521
+ ```bash
522
+ GET /_/feature-flags/new-checkout-flow
523
+ ```
524
+
525
+ Returns full details of a single flag including all value rules and application association.
526
+
527
+ Response:
528
+
529
+ ```json
530
+ {
531
+ "id": 12,
532
+ "name": "new-checkout-flow",
533
+ "description": "Enable the redesigned checkout experience",
534
+ "visible": true,
535
+ "defaultValue": false,
536
+ "application": {
537
+ "id": 5,
538
+ "name": "pae-commerce",
539
+ "displayName": "Commerce"
540
+ },
541
+ "valueRules": [
542
+ {
543
+ "id": 1,
544
+ "name": "premium-tenants",
545
+ "condition": {
546
+ "attribute": "tenant",
547
+ "operator": "in",
548
+ "value": ["premium-tenant-1", "premium-tenant-2"]
549
+ },
550
+ "value": true,
551
+ "rollout": null,
552
+ "createdAt": "2026-01-10T09:00:00Z",
553
+ "updatedAt": "2026-01-10T09:00:00Z"
554
+ }
555
+ ],
556
+ "createdAt": "2026-01-10T09:00:00Z",
557
+ "updatedAt": "2026-01-10T09:00:00Z",
558
+ "createdBy": "admin",
559
+ "updatedBy": "admin"
560
+ }
561
+ ```
562
+ </TabItem>
563
+ <TabItem label="Simulate evaluation">
564
+ ```bash
565
+ POST /_/feature-flags/simulate/new-checkout-flow
566
+ Content-Type: application/json
567
+
568
+ {
569
+ "context": {
570
+ "username": "alice@example.com",
571
+ "tenant": "premium-tenant-1",
572
+ "role": "user"
573
+ }
574
+ }
575
+ ```
576
+
577
+ The context is supplied directly in the request body and is **not** derived from the authenticated user. This makes the endpoint safe for arbitrary testing during development.
578
+
579
+ Response (rule matched):
580
+
581
+ ```json
582
+ {
583
+ "flagName": "new-checkout-flow",
584
+ "active": true,
585
+ "value": true,
586
+ "reason": "RULE_MATCHED",
587
+ "matchedRule": {
588
+ "name": "premium-tenants",
589
+ "condition": {
590
+ "attribute": "tenant",
591
+ "operator": "in",
592
+ "value": ["premium-tenant-1", "premium-tenant-2"]
593
+ },
594
+ "value": true,
595
+ "rollout": null
596
+ },
597
+ "evaluatedAt": "2026-01-10T09:00:00Z",
598
+ "context": {
599
+ "username": "alice@example.com",
600
+ "tenant": "premium-tenant-1",
601
+ "role": "user"
602
+ }
603
+ }
604
+ ```
605
+ </TabItem>
606
+ <TabItem label="Bulk evaluate">
607
+ ```bash
608
+ POST /_/feature-flags/evaluate
609
+ Content-Type: application/json
610
+
611
+ {
612
+ "flagNames": ["new-checkout-flow", "beta-reporting", "new-dashboard-ui"],
613
+ "customProperties": {
614
+ "experimentGroup": "b"
615
+ }
616
+ }
617
+ ```
618
+
619
+ Evaluates multiple flags in a single request. `flagNames` is required; `customProperties` is an optional map of additional context attributes to merge into the evaluation context.
620
+
621
+ Response:
622
+
623
+ ```json
624
+ {
625
+ "flags": {
626
+ "new-checkout-flow": true,
627
+ "beta-reporting": false,
628
+ "new-dashboard-ui": null
629
+ },
630
+ "evaluatedAt": "2026-01-10T09:00:00Z"
631
+ }
632
+ ```
633
+ </TabItem>
634
+ <TabItem label="Delete flag">
635
+ ```bash
636
+ DELETE /_/feature-flags/new-checkout-flow
637
+ ```
638
+
639
+ Deletes the feature flag and all its associated value rules. This operation is permanent.
640
+
641
+ Response:
642
+
643
+ ```json
644
+ {
645
+ "name": "new-checkout-flow",
646
+ "deletedAt": "2026-01-10T09:00:00Z",
647
+ "message": "Feature flag \"new-checkout-flow\" has been permanently deleted"
648
+ }
649
+ ```
650
+ </TabItem>
651
+ </Tabs>
652
+
653
+ ---
654
+
655
+ ## Simulating Feature Flag Evaluation
656
+
657
+ The simulate endpoint (`POST /_/feature-flags/simulate/:flagName`) is a development and debugging tool that lets you test how a flag evaluates for any arbitrary context without being tied to the authenticated user.
658
+
659
+ ### Evaluate vs Simulate
660
+
661
+ | Aspect | `POST /evaluate/:flagName` | `POST /simulate/:flagName` |
662
+ |--------|---------------------------|---------------------------|
663
+ | **Context source** | Authenticated user (derived server-side) | Request body `{ context: {...} }` |
664
+ | **Error on missing flag** | Returns `null` | Returns `FLAG_NOT_FOUND` reason |
665
+ | **Response detail** | Value only | Value + reason + matched rule + echoed context |
666
+ | **Non-visible flag** | Returns `null` | Returns `defaultValue` with `FLAG_INACTIVE` reason |
667
+ | **Intended use** | Production evaluation | Development / rule debugging |
668
+
669
+ ### SimulationReason Values
670
+
671
+ | Reason | When returned |
672
+ |--------|---------------|
673
+ | `FLAG_NOT_FOUND` | No flag with the given name exists in the database |
674
+ | `FLAG_INACTIVE` | The flag exists but `visible` is `false` |
675
+ | `RULE_MATCHED` | A value rule's condition matched the provided context |
676
+ | `DEFAULT_VALUE` | The flag is visible but no rule matched; `defaultValue` is returned |
677
+
678
+ ### Example — Rule Matched
679
+
680
+ ```bash
681
+ POST /_/feature-flags/simulate/beta-reporting
682
+ Content-Type: application/json
683
+
684
+ {
685
+ "context": {
686
+ "username": "beta-user-1@example.com",
687
+ "tenant": "acme-corp"
688
+ }
689
+ }
690
+ ```
691
+
692
+ ```json
693
+ {
694
+ "flagName": "beta-reporting",
695
+ "active": true,
696
+ "value": true,
697
+ "reason": "RULE_MATCHED",
698
+ "matchedRule": {
699
+ "name": "beta-user-access",
700
+ "condition": {
701
+ "attribute": "user",
702
+ "operator": "in",
703
+ "value": ["beta-user-1@example.com", "beta-user-2@example.com"]
704
+ },
705
+ "value": true,
706
+ "rollout": null
707
+ },
708
+ "evaluatedAt": "2026-01-10T09:00:00Z",
709
+ "context": {
710
+ "username": "beta-user-1@example.com",
711
+ "tenant": "acme-corp"
712
+ }
713
+ }
714
+ ```
715
+
716
+ ### Example — No Rule Matched (Default Value Returned)
717
+
718
+ ```bash
719
+ POST /_/feature-flags/simulate/beta-reporting
720
+ Content-Type: application/json
721
+
722
+ {
723
+ "context": {
724
+ "username": "regular-user@example.com",
725
+ "tenant": "acme-corp"
726
+ }
727
+ }
728
+ ```
729
+
730
+ ```json
731
+ {
732
+ "flagName": "beta-reporting",
733
+ "active": true,
734
+ "value": false,
735
+ "reason": "DEFAULT_VALUE",
736
+ "matchedRule": null,
737
+ "evaluatedAt": "2026-01-10T09:00:00Z",
738
+ "context": {
739
+ "username": "regular-user@example.com",
740
+ "tenant": "acme-corp"
741
+ }
742
+ }
743
+ ```
744
+
745
+ <Aside type="tip">
746
+ Use the simulate endpoint during development to verify your targeting rules before deploying. You can test any combination of context attributes without needing to log in as different users, making it straightforward to confirm that conditions like `in`, `AND`, or percentage rollouts work as intended.
747
+ </Aside>
748
+
749
+ ---
750
+
751
+ ## Usage in React Applications
752
+
753
+ The platform provides React hooks and components for easy feature flag integration in UI applications.
754
+
755
+ ### Setup
756
+
757
+ **1. Install the SDK:**
758
+
759
+ The SDK is included in the `pae-ui-react-core` package.
760
+
761
+ ### Reading Flag Values with useFeatureFlag
762
+
763
+ The `useFeatureFlag` hook returns the evaluated value of a flag for the current user context. Because flags can now return any type, the hook returns `any`.
764
+
765
+ ```typescript
766
+ import { useFeatureFlag } from '@bluealba/pae-ui-react-core';
767
+
768
+ function MyComponent() {
769
+ const isNewDashboardEnabled = useFeatureFlag('new-dashboard');
770
+
771
+ return (
772
+ <div>
773
+ {isNewDashboardEnabled ? (
774
+ <NewDashboard />
775
+ ) : (
776
+ <LegacyDashboard />
777
+ )}
778
+ </div>
779
+ );
780
+ }
781
+ ```
782
+
783
+ **Hook Signature:**
784
+
785
+ ```typescript
786
+ function useFeatureFlag(flagName: string): any
787
+ ```
788
+
789
+ **Parameters:**
790
+ - `flagName`: Name of the feature flag to evaluate
791
+
792
+ **Returns:**
793
+ - `any`: The evaluated flag value. For boolean flags this will be `true` or `false`; for typed flags it will be whatever value the matching rule specifies. Returns `undefined` when the flag is not present in the bootstrapped flags map.
794
+
795
+ **Example with a string-valued flag:**
796
+
797
+ ```typescript
798
+ function ThemeSelector() {
799
+ const theme = useFeatureFlag('ui-theme'); // returns 'light', 'dark', 'system', or undefined
800
+
801
+ return <AppShell theme={theme ?? 'light'} />;
802
+ }
803
+ ```
804
+
805
+ ### Conditional Rendering with FeatureFlagGuard
806
+
807
+ `FeatureFlagGuard` renders its children only when the evaluated flag value is strictly `true`. It is designed for boolean flags used as on/off guards.
808
+
809
+ ```typescript
810
+ import { FeatureFlagGuard } from '@bluealba/pae-ui-react-core';
811
+
812
+ function MyComponent() {
813
+ return (
814
+ <div>
815
+ <h1>My App</h1>
816
+
817
+ <FeatureFlagGuard flag="beta-features" fallback={<ComingSoon />}>
818
+ <BetaFeatures />
819
+ </FeatureFlagGuard>
820
+
821
+ <FeatureFlagGuard flag="premium-analytics">
822
+ <PremiumAnalytics />
823
+ </FeatureFlagGuard>
824
+ </div>
825
+ );
826
+ }
827
+ ```
828
+
829
+ **Component Props:**
830
+
831
+ | Prop | Type | Required | Description |
832
+ |------|------|----------|-------------|
833
+ | `flag` | string | Yes | Name of the feature flag |
834
+ | `fallback` | ReactNode | No | Content to show when flag value is not `true` |
835
+ | `children` | ReactNode | Yes | Content to show when flag value is strictly `true` |
836
+ | `invert` | boolean | No | When `true`, shows children when the flag is disabled and `fallback` when enabled. Defaults to `false`. |
837
+
838
+ <Aside type="note">
839
+ `FeatureFlagGuard` uses a strict equality check (`=== true`). If your flag returns a truthy non-boolean value (e.g., a non-empty string), the children will not render. Use `useFeatureFlag` directly and write your own condition for non-boolean flags.
840
+ </Aside>
841
+
842
+ ---
843
+
844
+ ## Usage in NestJS Backend Services
845
+
846
+ The gateway evaluates all feature flags for the current user before forwarding any proxied request to a microservice, and injects the results as the `x-forwarded-feature-flags` header (base64-encoded JSON). The `@bluealba/pae-service-nestjs-sdk` package exposes utilities to read those flags — no additional HTTP calls required.
847
+
848
+ ### Setup
849
+
850
+ Add `FeatureFlagsClientModule` to the `imports` array of the NestJS module where you need flag access:
851
+
852
+ ```typescript
853
+ import { FeatureFlagsClientModule } from '@bluealba/pae-service-nestjs-sdk';
854
+ import { Module } from '@nestjs/common';
855
+ import { AcmeController } from './acme.controller';
856
+ import { AcmeService } from './acme.service';
857
+
858
+ @Module({
859
+ imports: [FeatureFlagsClientModule],
860
+ controllers: [AcmeController],
861
+ providers: [AcmeService],
862
+ })
863
+ export class AcmeModule {}
864
+ ```
865
+
866
+ ### Option 1 — Injectable Service
867
+
868
+ Inject `FeatureFlagsClientService` into any provider that has access to the request object:
869
+
870
+ ```typescript
871
+ import { Injectable } from '@nestjs/common';
872
+ import { FeatureFlagsClientService } from '@bluealba/pae-service-nestjs-sdk';
873
+ import { FastifyRequest } from 'fastify';
874
+
875
+ @Injectable()
876
+ export class AcmeService {
877
+ constructor(private readonly featureFlags: FeatureFlagsClientService) {}
878
+
879
+ async getItems(req: FastifyRequest) {
880
+ const isNewUI = this.featureFlags.get<boolean>(req, 'new-ui') ?? false;
881
+ const pageSize = this.featureFlags.get<number>(req, 'items-page-size') ?? 20;
882
+ // ...
883
+ }
884
+ }
885
+ ```
886
+
887
+ **API:**
888
+
889
+ | Method | Signature | Description |
890
+ |--------|-----------|-------------|
891
+ | `getAll` | `getAll(req): Record<string, any>` | Returns all evaluated flags for the request |
892
+ | `get` | `get<T>(req, flagName): T \| undefined` | Returns the value of a specific flag, or `undefined` if not present |
893
+
894
+ ### Option 2 — Parameter Decorator in Controllers
895
+
896
+ Use `@FeatureFlags()` to bind flag values directly to controller method parameters:
897
+
898
+ ```typescript
899
+ import { Controller, Get } from '@nestjs/common';
900
+ import { FeatureFlags } from '@bluealba/pae-service-nestjs-sdk';
901
+
902
+ @Controller('acme')
903
+ export class AcmeController {
904
+ @Get()
905
+ async getItems(@FeatureFlags('new-ui') isNewUI: boolean) {
906
+ // isNewUI is the evaluated value of the 'new-ui' flag for this user
907
+ }
908
+
909
+ @Get('debug')
910
+ async debugFlags(@FeatureFlags() flags: Record<string, any>) {
911
+ return { flags };
912
+ }
913
+ }
914
+ ```
915
+
916
+ | Usage | Resolves to |
917
+ |-------|-------------|
918
+ | `@FeatureFlags()` | `Record<string, any>` — all evaluated flags |
919
+ | `@FeatureFlags('flag-name')` | `T \| undefined` — value of the named flag |
920
+
921
+ <Aside type="caution">
922
+ Do not use feature flags as security gates. Flags are forwarded from the gateway at request time but are not re-validated by the microservice. Use the platform's authorization system (roles and operations) for access control.
923
+ </Aside>
924
+
925
+ ---
926
+
927
+ ## Best Practices
928
+
929
+ ### When to Use Feature Flags
930
+
931
+ <CardGrid stagger>
932
+ <Card title="New Features" icon="rocket">
933
+ Use release flags for new features to control rollout and enable quick rollback if issues arise.
934
+ </Card>
935
+
936
+ <Card title="Kill Switches" icon="warning">
937
+ Use kill-switch flags for critical systems that may need instant disabling. Set `visible: false` to immediately short-circuit evaluation.
938
+ </Card>
939
+
940
+ <Card title="Permissions" icon="lock">
941
+ Use permission flags to control feature access based on user role or tenant.
942
+ </Card>
943
+ </CardGrid>
944
+
945
+ **When NOT to use feature flags:**
946
+ - For every small code change (flag sprawl)
947
+ - As a replacement for configuration management
948
+ - For security-sensitive features that should be removed entirely
949
+ - When the code complexity becomes unmanageable
950
+
951
+ ### Always Associate Flags with an Application
952
+
953
+ Every feature flag should be linked to the application that owns it, using `applicationId` (via API) or `applicationName` (via bootstrap). This practice:
954
+
955
+ - Keeps the Feature Flags page navigable as the platform scales
956
+ - Makes it immediately clear which team is responsible for a flag
957
+ - Enables accurate filtering in the Admin UI
958
+
959
+ ### Order Value Rules from Most Specific to Least Specific
960
+
961
+ Because evaluation stops at the first matching rule, place the most targeted rules at the top of the `valueRules` array. A broad catch-all rule at the end acts as a secondary default.
962
+
963
+ ```typescript
964
+ // Good — specific rules first, broad rule last
965
+ valueRules: [
966
+ {
967
+ name: 'admin-preview',
968
+ condition: { attribute: 'user', operator: 'eq', value: 'admin@example.com' },
969
+ value: 'admin-preview' // Exact user gets a special value
970
+ },
971
+ {
972
+ name: 'beta-access',
973
+ condition: { attribute: 'role', operator: 'eq', value: 'beta' },
974
+ value: true // Beta role gets the feature
975
+ }
976
+ // No further rules — all other users fall through to defaultValue
977
+ ]
978
+ ```
979
+
980
+ ### Use the visible Field as a Master Switch
981
+
982
+ Set `visible: false` to immediately deactivate a flag without deleting it or clearing its value rules. This is the safest way to perform an emergency rollback — re-enabling a flag is a single field update.
983
+
984
+ ### Naming Conventions
985
+
986
+ Use consistent, descriptive names for your feature flags:
987
+
988
+ **Recommended Formats:**
989
+
990
+ ```
991
+ # Feature releases
992
+ new-[feature-name]
993
+ enable-[feature-name]
994
+ [feature-name]-v2
995
+
996
+ # Examples
997
+ new-dashboard-ui
998
+ enable-advanced-search
999
+ checkout-flow-v2
1000
+
1001
+ # Experiments
1002
+ [feature]-[experiment-name]
1003
+ ab-test-[feature]
1004
+
1005
+ # Examples
1006
+ checkout-express-flow
1007
+ ab-test-pricing-page
1008
+
1009
+ # Kill switches
1010
+ [system]-enabled
1011
+ [integration]-active
1012
+
1013
+ # Examples
1014
+ payment-processing-enabled
1015
+ analytics-tracking-active
1016
+ ```
1017
+
1018
+ **Best Practices:**
1019
+ - Use kebab-case (lowercase with hyphens)
1020
+ - Be descriptive but concise
1021
+ - Include feature area in the name
1022
+ - Avoid generic names like `feature1` or `test`
1023
+
1024
+ ---
1025
+
1026
+ ## Summary
1027
+
1028
+ The Blue Alba Platform's feature flags system provides a powerful, flexible way to control feature availability in your applications. Key takeaways:
1029
+
1030
+ <CardGrid stagger>
1031
+ <Card title="Rules-Based Evaluation" icon="approve-check">
1032
+ Flags use an ordered `valueRules` array. The first matching rule wins; `defaultValue` is the fallback.
1033
+ </Card>
1034
+
1035
+ <Card title="Composable Conditions" icon="magnifier">
1036
+ Combine leaf conditions (`eq`, `neq`, `in`, `nin`) with `AND`/`OR` composites to express any targeting logic.
1037
+ </Card>
1038
+
1039
+ <Card title="Self-Contained" icon="rocket">
1040
+ Requires only PostgreSQL — no external services needed.
1041
+ </Card>
1042
+
1043
+ <Card title="Application-Scoped" icon="document">
1044
+ Associate flags with applications to keep large flag sets organized and filterable.
1045
+ </Card>
1046
+ </CardGrid>
1047
+
1048
+ <Aside type="tip">
1049
+ Keep in mind that you can manage the feature flags in the platform admin application. Use the Application selector at the top of the Feature Flags page to filter flags by the application that owns them.
1050
+ </Aside>
1051
+
1052
+ **Next Steps:**
1053
+ 1. Create your first feature flag and assign it to an application
1054
+ 2. Declare flags in your application's bootstrap configuration using `applicationName` and `valueRules`
1055
+ 3. Integrate the React SDK using `useFeatureFlag` or `FeatureFlagGuard`
1056
+ 4. In NestJS microservices, import `FeatureFlagsClientModule` and use `FeatureFlagsClientService` or `@FeatureFlags()`
1057
+ 5. Start using feature flags to control rollouts safely
1058
+
1059
+ For questions or issues, reach out to the platform team.