A full-stack feature flag management system with React frontend and Spring Boot + MySQL backend.
Developers can create, update, and manage feature flags, then evaluate them via an API that returns a boolean value using sticky deterministic bucketing.
- 🔑 User authentication (signup/login)
- 🏷️ CRUD operations for feature flags
- ⚙️ Configurable attributes: name, description, rollout percentage, allowed countries
- 🧮 Deterministic rollout evaluation (sticky bucketing)
- 🌍 Country-based targeting
- 🔐 API key authentication for external apps
- 📡 REST API returns
true/falseon feature evaluation - 📊 Success tracking & analytics (success ratio / lift between feature and control groups)
- Frontend: React
- Backend: Spring Boot
- Database: MySQL
- Java 17+
- Node.js 18+
- MySQL running locally or on cloud
cd backend
./mvnw spring-boot:run
⚠️ The frontend is bundled and served from the Spring Boot app. It does not need to be run seperately
cd frontend
npm install
npm start
Each user is issued an API Key after login.
Pass this key in the request header when evaluating a feature flag.
Endpoint:
GET /api/evaluate/{id}
Headers:
X-API-Key: your-api-key
Request example:
GET /api/evaluate/550e8400-e29b-41d4-a716-446655440000?userId=user123&userCountry=IN
Response:
true
To record when a user action is successful (used later for computing the success ratio / lift):
Endpoint:
POST /api/success/{id}
Headers:
X-API-Key: your-api-key
Query Parameters:
userId– ID of the user triggering the success
Request example:
POST /api/success/550e8400-e29b-41d4-a716-446655440000?userId=user123
Response:
200 OK
This increments the success count for the user’s assigned group (feature vs control). The frontend dashboard uses these counts to calculate the success ratio (lift) of the feature against the control group.
- The system hashes
userId + featureId + salt. - Hash is mapped into a bucket
0–99. - If bucket < rollout percentage → feature enabled.
- Country filters and whitelist rules override rollout logic.
This ensures the same user consistently receives the same result.