ConfX is a comprehensive feature flag and configuration management service designed to provide real-time updates, multi-environment support, version control, and a powerful rule engine for targeted configuration delivery.
To set up and run the ConfX server, follow these steps:
- Java Development Kit (JDK): Version 18 or higher.
- Gradle: Version 7.x or higher (the project includes a Gradle wrapper
./gradlew
). - PostgreSQL: A running instance of PostgreSQL.
-
Create a PostgreSQL database:
- Name:
confx
(or your preferred name, update properties accordingly)
- Name:
-
Create a PostgreSQL user (role):
- Username:
user
(or your preferred name) - Password:
password
(or your preferred strong password) - Grant this user necessary permissions on the
confx
database (e.g.,CREATE
,CONNECT
,TEMPORARY
, DML, DDL if Flyway is to create the schema).
Example SQL (run as a PostgreSQL superuser):
CREATE USER myuser WITH PASSWORD 'mypassword'; CREATE DATABASE confx OWNER myuser; -- If your DB user for the application won't own the schema but will operate within it: -- CREATE SCHEMA confx_schema AUTHORIZATION myuser; -- GRANT ALL PRIVILEGES ON SCHEMA confx_schema TO myuser;
- Username:
- Navigate to
src/main/resources/application.properties
. - Update the following datasource properties if your setup differs from the defaults:
spring.datasource.url=jdbc:postgresql://localhost:5432/confx spring.datasource.username=user spring.datasource.password=password
- Flyway properties are also present and will use the datasource properties by default. Ensure the
spring.flyway.schemas=confx_schema
andspring.jpa.properties.hibernate.default_schema=confx_schema
match your desired schema name. The Flyway scripts will create this schema if it doesn't exist (CREATE SCHEMA IF NOT EXISTS confx_schema;
inV1__...sql
).
- Build the project:
Open a terminal in the project's root directory and run:
./gradlew build
- Run the application:
After a successful build, run the application using:
Alternatively, you can run the generated JAR file:
./gradlew bootRun
java -jar build/libs/confx-0.0.1-SNAPSHOT.jar
Upon successful startup, Flyway will automatically apply database migrations, creating the necessary tables (projects
, environments
, config_items
, config_versions
, rules
, config_dependencies
) within the confx_schema
.
The server will typically start on http://localhost:8080
.
You can check the server status by accessing actuator endpoints (if enabled and exposed, default is management.endpoints.web.exposure.include=*
):
- Health:
http://localhost:8080/actuator/health
The server provides API endpoints under /api/v1/...
for managing projects, environments, configurations, and more. It also supports client SDK connections for real-time updates (details of which are beyond this server setup guide).
ConfX is a powerful, self-hosted solution for managing dynamic configurations and feature flags across multiple environments for various applications. It allows developers and product managers to control feature rollouts, A/B testing, and application settings without requiring new code deployments.
- Concept: A
Project
is the highest-level organizational unit in ConfX. It acts as a container for all related configurations and environments for a specific application, microservice, or a distinct part of a larger system. - Example: You might have a project named "WebApp-Frontend", another "OrderService-Backend", etc.
- Management: Projects can be created, updated, listed, and deleted via the REST API (
/api/v1/projects
). Each project has a unique name and an optional description.
- Concept: Within each
Project
, you can define multipleEnvironments
. An environment represents a specific deployment stage or context, such asdevelopment
,staging
,qa
, orproduction
. - Independence: Crucially, each environment holds its own independent set of configuration values and rules. This means a feature flag can be enabled in
staging
but disabled inproduction
, or an API endpoint URL can differ betweendevelopment
andproduction
. - Management: Environments are managed under a specific project (
/api/v1/projects/{projectId}/environments
). They have a name (unique within the project), an optional description, and a color tag for UI distinction.
- Concept: A
ConfigItem
is the blueprint or definition of a single piece of configuration or a feature flag. It defines:configKey
: A unique string identifier for the config within its project (e.g.,enableNewDashboard
,paymentGatewayTimeoutMs
).dataType
: The type of value this config holds (e.g.,BOOLEAN
,STRING
,INTEGER
,DOUBLE
,JSON
).- A description and optional notes.
- Purpose: It does not store the actual value for different environments; it only defines what the configuration is.
- Management: ConfigItems are defined per project (
/api/v1/projects/{projectId}/configs
).
- Concept: This is where the actual configuration values for each
ConfigItem
within a specificEnvironment
are stored and versioned. Every time you change a configuration's value (or its targeting rules) for a specific environment, a newConfigVersion
record is created. - Key Attributes of a
ConfigVersion
:- Link to
ConfigItem
andEnvironment
. value
: The default value of the config for this version in this environment (e.g., "true", "1000", "{"theme": "dark"}").versionNumber
: A sequential integer, incremented for each new version of this config in this environment.isActive
: A boolean flag. Only one version of a config item in a given environment can beisActive=true
at any time. This active version is what clients will evaluate against by default.changeDescription
: A "commit message" explaining why this version was created.rules
: A list of targeting rules associated with this specific version (see next section).
- Link to
- Audit Log & Rollback: The collection of
ConfigVersion
records for a config item in an environment forms its complete history (audit log). The system supports rolling back to any previous version by creating a new active version that copies the settings of the chosen older version. - Management: Config versions are managed via endpoints like
/api/v1/projects/{projectId}/environments/{environmentId}/configs/{configItemId}/versions
.
- Concept: ConfX features a powerful rule engine that allows for conditional targeting of configuration values. Rules are associated with a specific
ConfigVersion
. - Structure of a Rule:
priority
: An integer determining the order of evaluation (lower numbers evaluated first).conditionExpression
: A string expression (using Spring Expression Language - SpEL) that evaluates totrue
orfalse
based on anEvaluationContext
provided by the client SDK at evaluation time.valueToServe
: The specific value (as a string) to be returned if theconditionExpression
is true.
- EvaluationContext: This is a set of key-value attributes provided by the client SDK when requesting a config value (e.g.,
userId
,region
,email
, custom application attributes). Expressions likeattributes['region'] == 'US'
orattributes['userAge'] > 21
are evaluated against this context. - Evaluation Flow: When a config is evaluated for a given context:
- The active
ConfigVersion
for the item in the environment is retrieved. - Its associated rules are evaluated in order of
priority
. - If a rule's condition matches, its
valueToServe
is returned. - If no rules match, the default
value
from theConfigVersion
is returned.
- The active
- Supported Operators (via SpEL):
==
,!=
,>
,<
,>=
,<=
, logicalAND
(&&
),OR
(||
),NOT
(!
), and list operators likecontains()
(e.g.,attributes['segments'].contains('beta')
).
- Concept: ConfX allows defining dependencies between
ConfigItem
s within the same project. For example,ConfigB
(dependent) might only be truly active or take effect ifConfigA
(prerequisite) evaluates to a specific value. - Definition: A dependency specifies:
- The dependent
ConfigItem
. - The prerequisite
ConfigItem
. - The
prerequisiteExpectedValue
: The value the prerequisite config must evaluate to for the dependency to be met.
- The dependent
- Evaluation Impact: When evaluating a dependent config:
- All its prerequisites are evaluated first (recursively, using the same evaluation context).
- If any prerequisite does not evaluate to its
prerequisiteExpectedValue
, the dependent config is considered "off" (e.g., evaluates tofalse
if boolean, ornull
for other types), irrespective of its own rules or default value. - If all prerequisites are met, the dependent config proceeds with its normal rule and default value evaluation.
- Cyclic Dependency Handling:
- Prevention: When adding a new dependency, the system performs a check (using DFS) to prevent the creation of circular dependencies (e.g., A depends on B, and B depends on A).
- Evaluation Time Safety: During evaluation, a separate cycle detection mechanism (using an evaluation stack) is in place as a safeguard. If a cycle is detected during a recursive evaluation call, the config causing the cycle will evaluate to its "off" state to prevent infinite loops.
- Management: Dependencies are defined at the
ConfigItem
level, typically via endpoints like/api/v1/projects/{projectId}/dependencies/for/{configItemId}
.
- Concept: To ensure clients receive configuration changes almost instantaneously without constant polling, ConfX uses Server-Sent Events (SSE).
- Connection: Client SDKs establish an SSE connection to a specific stream endpoint on the server, typically scoped to a project and environment (e.g.,
/api/v1/stream/projects/{projectId}/environments/{environmentId}
). - Event Pushing: When a configuration is updated (i.e., a new
ConfigVersion
is published and becomes active), the server publishes an event.- The
ConfigUpdateEventListener
listens for these application events. - It then uses the
SseService
to push a message to all connected SSE clients subscribed to the relevant project and environment.
- The
- Payload: The SSE message typically includes:
type
: e.g.,CONFIG_VERSION_UPDATED
,CONFIG_ITEM_DELETED
, etc.payload
: ForCONFIG_VERSION_UPDATED
, this is the completeConfigVersionResponseDto
of the new active version (including its key, value, data type, and rules). For deletions, it contains identifiers of the deleted entity.
- Client Action: The client SDK receives this event, parses the payload, and updates its local in-memory cache with the new configuration data. This ensures that subsequent calls to evaluate that config key use the latest information.
- Purpose: To maintain the SSE connection integrity, especially through intermediaries like proxies or load balancers that might terminate idle connections, and to allow the server to detect disconnected clients.
- Mechanism: The
SseService
periodically sends SSE comments (e.g.,: ping
) as heartbeats to all active client connections. This generates network traffic without being interpreted as an actual data event by the client. - Client Handling: Standard
EventSource
implementations in browsers or custom SSE clients typically ignore comments. The SDK uses these heartbeats (or lack thereof on error) to manage connection state and attempt reconnections. - Server Cleanup: The
SseService
also uses timeouts and error handlers onSseEmitter
objects to clean up and remove emitters for clients that have disconnected or errored out.
- Concept: When an SDK instance initializes, it needs to fetch the current state of all active configurations for its designated project and environment.
- Endpoint: The server provides an endpoint (e.g.,
/api/v1/projects/{projectId}/environments/{environmentId}/all-active-configs
) that returns a list of allConfigVersionResponseDto
objects that are currently active for that environment. This payload includes the default value and all targeting rules for each config. - SDK Action: The SDK calls this endpoint upon startup, populates its in-memory cache, and then relies on SSE for subsequent delta updates.
This incremental approach, from basic organizational units to complex real-time evaluation and update mechanisms, forms the core of the ConfX service.