MATIH Platform is in active MVP development. Documentation reflects current implementation status.
8. Platform Services
Feature Flags

Feature Flags

The Feature Flag system in the Config Service provides a complete feature management platform. The FeatureFlagController at /api/v1/feature-flags supports flag creation, evaluation with user targeting, percentage-based rollouts, allowed-user lists, batch evaluation, and tag-based organization.


FeatureFlagController

@RestController
@RequestMapping("/api/v1/feature-flags")
@Tag(name = "Feature Flags", description = "Feature flag management endpoints")
public class FeatureFlagController {
    private final FeatureFlagService flagService;
    private final ConfigMapper configMapper;
}

Create a Feature Flag

Endpoint: POST /api/v1/feature-flags

curl -X POST http://localhost:8888/api/v1/feature-flags \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d '{
    "tenantId": "550e8400-e29b-41d4-a716-446655440000",
    "flagKey": "ai.streaming-responses",
    "displayName": "AI Streaming Responses",
    "description": "Enable WebSocket streaming for AI conversation responses",
    "flagType": "BOOLEAN",
    "enabled": false,
    "defaultValue": "false",
    "rolloutPercentage": 0,
    "tags": ["ai", "experimental", "performance"]
  }'

Response (201 Created):

{
  "id": "880e8400-e29b-41d4-a716-446655440000",
  "tenantId": "550e8400-e29b-41d4-a716-446655440000",
  "flagKey": "ai.streaming-responses",
  "displayName": "AI Streaming Responses",
  "description": "Enable WebSocket streaming for AI conversation responses",
  "flagType": "BOOLEAN",
  "enabled": false,
  "defaultValue": "false",
  "rolloutPercentage": 0,
  "allowedUsers": [],
  "rules": [],
  "tags": ["ai", "experimental", "performance"],
  "createdAt": "2026-02-12T10:00:00Z",
  "updatedAt": "2026-02-12T10:00:00Z"
}

Check if Flag is Enabled

Simple boolean check without user context.

Endpoint: GET /api/v1/feature-flags/tenant/{tenantId}/key/{flagKey}/enabled

curl http://localhost:8888/api/v1/feature-flags/tenant/550e8400-e29b-41d4-a716-446655440000/key/ai.streaming-responses/enabled \
  -H "Authorization: Bearer ${TOKEN}"

Response:

{
  "enabled": true
}

Evaluate Flag for a User

Evaluate a feature flag in the context of a specific user. The evaluation considers the flag's enabled state, rollout percentage, allowed-user list, and targeting rules.

Endpoint: GET /api/v1/feature-flags/tenant/{tenantId}/key/{flagKey}/evaluate

curl "http://localhost:8888/api/v1/feature-flags/tenant/550e8400-e29b-41d4-a716-446655440000/key/ai.streaming-responses/evaluate?userId=user-001" \
  -H "Authorization: Bearer ${TOKEN}"

Response:

{
  "flagKey": "ai.streaming-responses",
  "enabled": true,
  "reason": "ROLLOUT_PERCENTAGE",
  "value": "true"
}

Evaluation Reasons

ReasonDescription
FLAG_DISABLEDFlag is globally disabled
ALLOWED_USERUser is in the explicit allowed-user list
TARGETING_RULEA targeting rule matched the user context
ROLLOUT_PERCENTAGEUser fell within the rollout percentage
DEFAULT_VALUENo rules matched; returning default

Batch Evaluate Multiple Flags

Evaluate multiple flags for a single user in one request. This is the recommended approach for frontend applications that need to check many flags at once.

Endpoint: POST /api/v1/feature-flags/tenant/{tenantId}/evaluate-batch

curl -X POST "http://localhost:8888/api/v1/feature-flags/tenant/550e8400-e29b-41d4-a716-446655440000/evaluate-batch?userId=user-001" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d '["ai.streaming-responses", "bi.new-chart-types", "ml.auto-feature-selection"]'

Response:

{
  "ai.streaming-responses": {
    "flagKey": "ai.streaming-responses",
    "enabled": true,
    "reason": "ALLOWED_USER",
    "value": "true"
  },
  "bi.new-chart-types": {
    "flagKey": "bi.new-chart-types",
    "enabled": false,
    "reason": "FLAG_DISABLED",
    "value": "false"
  },
  "ml.auto-feature-selection": {
    "flagKey": "ml.auto-feature-selection",
    "enabled": true,
    "reason": "ROLLOUT_PERCENTAGE",
    "value": "true"
  }
}

List Feature Flags

All flags for a tenant (paginated)

Endpoint: GET /api/v1/feature-flags/tenant/{tenantId}

curl "http://localhost:8888/api/v1/feature-flags/tenant/550e8400-e29b-41d4-a716-446655440000?page=0&size=20" \
  -H "Authorization: Bearer ${TOKEN}"

Enabled flags only

Endpoint: GET /api/v1/feature-flags/tenant/{tenantId}/enabled

Flags by tag

Endpoint: GET /api/v1/feature-flags/tenant/{tenantId}/tag/{tag}

curl http://localhost:8888/api/v1/feature-flags/tenant/550e8400-e29b-41d4-a716-446655440000/tag/experimental \
  -H "Authorization: Bearer ${TOKEN}"

Global flags

Endpoint: GET /api/v1/feature-flags/global


Enable / Disable a Flag

Toggle a flag on or off. This is the simplest way to control feature access.

Enable:

curl -X POST http://localhost:8888/api/v1/feature-flags/880e8400-e29b-41d4-a716-446655440000/enable \
  -H "Authorization: Bearer ${TOKEN}"

Disable:

curl -X POST http://localhost:8888/api/v1/feature-flags/880e8400-e29b-41d4-a716-446655440000/disable \
  -H "Authorization: Bearer ${TOKEN}"

Update Rollout Percentage

Gradually roll out a flag to a percentage of users. The percentage is applied deterministically using a hash of the user ID, so the same user always gets the same result.

Endpoint: PUT /api/v1/feature-flags/{id}/rollout

curl -X PUT "http://localhost:8888/api/v1/feature-flags/880e8400-e29b-41d4-a716-446655440000/rollout?percentage=25" \
  -H "Authorization: Bearer ${TOKEN}"

Recommended Rollout Strategy

Start at 5%

Enable the flag for internal users and 5% of the user base.

Monitor metrics

Watch error rates, latency, and user feedback for 24 hours.

Increase to 25%

If metrics are healthy, increase to 25%.

Increase to 50%

Continue monitoring for another 24 hours, then increase to 50%.

Full rollout

After successful 50% rollout, set to 100%.


Manage Allowed Users

Add or remove specific users from the flag's allowed list. Users on the allowed list always see the flag as enabled, regardless of rollout percentage.

Add users

Endpoint: POST /api/v1/feature-flags/{id}/users

curl -X POST http://localhost:8888/api/v1/feature-flags/880e8400-e29b-41d4-a716-446655440000/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d '["user-001", "user-002", "user-003"]'

Remove users

Endpoint: DELETE /api/v1/feature-flags/{id}/users

curl -X DELETE http://localhost:8888/api/v1/feature-flags/880e8400-e29b-41d4-a716-446655440000/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d '["user-003"]'

Update a Feature Flag

Endpoint: PUT /api/v1/feature-flags/{id}

curl -X PUT http://localhost:8888/api/v1/feature-flags/880e8400-e29b-41d4-a716-446655440000 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d '{
    "displayName": "AI Streaming Responses (v2)",
    "description": "Updated streaming implementation with chunked transfer",
    "rolloutPercentage": 50,
    "tags": ["ai", "stable", "performance"]
  }'

Delete a Feature Flag

Endpoint: DELETE /api/v1/feature-flags/{id}

curl -X DELETE http://localhost:8888/api/v1/feature-flags/880e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer ${TOKEN}"

Response: 204 No Content

⚠️

Deleting a feature flag immediately removes it from all evaluation paths. Any service checking this flag will receive the default value. Consider disabling the flag first and monitoring for issues before deleting.


Flag Evaluation Flow

The internal evaluation logic follows this decision tree:

Is flag.enabled == false?
  YES -> return DEFAULT_VALUE

Is userId in flag.allowedUsers?
  YES -> return ALLOWED_USER (enabled)

Do any targeting rules match?
  YES -> return TARGETING_RULE (rule value)

Is rolloutPercentage > 0?
  hash(flagKey + userId) % 100 < rolloutPercentage?
    YES -> return ROLLOUT_PERCENTAGE (enabled)
    NO  -> return DEFAULT_VALUE

return DEFAULT_VALUE

Error Codes

HTTP StatusError CodeDescription
400INVALID_FLAG_TYPEInvalid flag type specified
404FLAG_NOT_FOUNDFeature flag does not exist
409FLAG_KEY_EXISTSDuplicate flag key for tenant
422INVALID_PERCENTAGERollout percentage must be 0-100