Skip to content

feat(config): implement multi-environment configuration management system#122

Merged
MPSxDev merged 11 commits into
PayStell:mainfrom
akintewe:feature/config-management-system
Aug 27, 2025
Merged

feat(config): implement multi-environment configuration management system#122
MPSxDev merged 11 commits into
PayStell:mainfrom
akintewe:feature/config-management-system

Conversation

@akintewe

@akintewe akintewe commented Jul 26, 2025

Copy link
Copy Markdown
Contributor

Pull Request Overview

📝 Summary

This PR implements a complete Multi-Environment Configuration Management System that centralizes all application configurations, provides dynamic feature flags, and enables secure configuration management across development, staging, and production environments. The system eliminates hardcoded configurations and provides a robust API for real-time configuration updates.

🔗 Related Issues

🔄 Changes Made

Core Features Implemented:

  • Centralized Configuration Management: All configurations are now stored in the database with environment-specific values
  • Feature Flags System: Dynamic feature toggles with targeting rules (user/merchant IDs, roles, percentage rollout)
  • Encrypted Configurations: Sensitive data is automatically encrypted using AES-256-CBC
  • Configuration Validation: Automatic validation of required configurations at startup
  • Hot-Reload API: Update configurations without server restart via REST API
  • Audit Logging: Complete tracking of all configuration changes
  • Environment-Specific Configs: Separate configurations for development, staging, and production

Technical Implementation:

  • Database Entities: Configuration and FeatureFlag entities with comprehensive metadata
  • ConfigurationService: Core service handling CRUD operations, encryption, caching, and validation
  • REST API: Full CRUD endpoints for configurations and feature flags (/api/config)
  • Express Middleware: Seamless integration with request context for easy configuration access
  • Initialization Script: Automated setup of default configurations across environments
  • Comprehensive Testing: Unit tests, integration tests, and manual verification scripts

Files Added/Modified:

  • 16 files changed, 4,323 insertions
  • New entities: Configuration.ts, FeatureFlag.ts
  • New services: ConfigurationService.ts
  • New controllers: ConfigurationController.ts
  • New routes: configurationRoutes.ts
  • New middleware: configurationMiddleware.ts
  • New scripts: initializeConfigurations.ts, testConfigurationSystem.ts
  • New tests: Unit and integration tests
  • New documentation: CONFIGURATION_SYSTEM.md

🖼️ Current Output

API Endpoints Available:

GET    /api/config                    # Get all configurations
GET    /api/config/:key              # Get specific configuration
POST   /api/config                   # Create/update configuration
DELETE /api/config/:key              # Delete configuration
GET    /api/config/category/:category # Get configs by category
POST   /api/config/reload            # Hot-reload configurations
POST   /api/config/validate          # Validate all configurations
GET    /api/config/stats             # Configuration statistics
POST   /api/config/export            # Export configurations
POST   /api/config/import            # Import configurations

GET    /api/config/feature-flags     # Get all feature flags
POST   /api/config/feature-flags     # Create/update feature flag
POST   /api/config/feature-flags/:name/evaluate # Evaluate feature flag

Configuration Categories Supported:

  • Database configurations
  • Authentication settings
  • Payment processing
  • Stellar network settings
  • Email configurations
  • Redis settings
  • Security parameters
  • Monitoring configurations
  • Feature flags
  • General application settings

🧪 Testing

Automated Tests:

  • Unit Tests: ConfigurationService.test.ts - 536 lines of comprehensive test coverage
  • Integration Tests: configurationIntegration.test.ts - 350 lines testing API endpoints
  • Manual Test Script: testConfigurationSystem.ts - 233 lines for manual verification

Test Coverage Includes:

  • ✅ Configuration CRUD operations
  • ✅ Encryption/decryption of sensitive data
  • ✅ Feature flag evaluation with targeting rules
  • ✅ Cache management and hot-reload
  • ✅ Validation and error handling
  • ✅ Audit logging of changes
  • ✅ Environment-specific configurations
  • ✅ API endpoint functionality

Manual Testing Commands:

# Initialize default configurations
npm run init-config

# Run automated tests
npm test

# Run manual verification
npm run test-config

💬 Comments

Key Benefits:

  1. Security: Sensitive configurations are automatically encrypted
  2. Flexibility: Dynamic feature flags enable A/B testing and gradual rollouts
  3. Reliability: Configuration validation prevents startup failures
  4. Maintainability: Centralized configuration management reduces deployment errors
  5. Observability: Complete audit trail of all configuration changes

Migration Notes:

  • Existing environment variables continue to work
  • New system is backward compatible
  • Default configurations are automatically populated on first run
  • No breaking changes to existing functionality

Next Steps:

  • Consider implementing configuration migration tools for existing deployments
  • Monitor configuration usage patterns in production
  • Consider adding configuration templates for common deployment scenarios

Security Considerations:

  • Encryption keys should be managed securely in production
  • Access to configuration API should be restricted to authorized users
  • Audit logs should be monitored for suspicious configuration changes

Ready for Review

This implementation provides a complete, production-ready configuration management system that addresses all requirements from issue #117 while maintaining backward compatibility and providing comprehensive testing coverage.

Summary by CodeRabbit

  • New Features

    • Introduced a robust multi-environment configuration management system with REST API endpoints for managing configurations and feature flags.
    • Added support for feature flags with targeting, percentage rollouts, and dynamic updates without server restarts.
    • Enabled encrypted storage for sensitive configurations and comprehensive audit logging.
    • Added middleware for easy configuration and feature flag access within requests.
    • Provided import/export, validation, and statistics endpoints for configurations and feature flags.
    • Integrated configuration service initialization into app startup and added related middleware and routes.
  • Documentation

    • Enhanced README and added detailed documentation for setup, usage, security, and troubleshooting of the configuration system.
  • Tests

    • Added extensive integration and unit tests for configuration and feature flag management.
  • Chores

    • Added scripts for initializing and testing the configuration system.
    • Updated package scripts to include configuration initialization and testing commands.

…stem with feature flags, encryption, validation, and API
@coderabbitai

coderabbitai Bot commented Jul 26, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This set of changes introduces a comprehensive Multi-Environment Configuration Management System to the PayStell backend. It adds new entities, services, middleware, REST API endpoints, initialization and test scripts, and extensive documentation. The system supports environment-specific configuration storage, validation, encryption, feature flags, dynamic updates, audit logging, and includes both integration and unit tests.

Changes

Cohort / File(s) Change Summary
Documentation: System Overview & Usage
README.md, docs/CONFIGURATION_SYSTEM.md
Adds detailed documentation describing the configuration management system, its features, architecture, API endpoints, usage, setup, best practices, and troubleshooting.
Entities: Configuration & Feature Flags
src/entities/Configuration.ts, src/entities/FeatureFlag.ts
Introduces new TypeORM entities for configurations and feature flags, including enums, schema definitions, validation, and indexing.
Service Layer
src/services/ConfigurationService.ts
Implements ConfigurationService for managing configurations and feature flags, including caching, encryption, validation, audit logging, and evaluation logic. Exports a singleton instance.
Middleware
src/middlewares/configurationMiddleware.ts, src/types/express.d.ts
Adds middleware for injecting configuration and feature flag access into requests, environment data, validation, and request-level caching. Extends Express types for request properties.
API Controller & Routes
src/controllers/ConfigurationController.ts, src/routes/configurationRoutes.ts
Implements a RESTful API controller and routes for CRUD operations on configurations and feature flags, reload, validation, import/export, and statistics, with validation and Swagger docs.
Integration & Unit Tests
src/tests/integration/configurationIntegration.test.ts, src/tests/services/ConfigurationService.test.ts
Adds comprehensive integration and unit tests covering all aspects of the configuration and feature flag system.
Initialization & Test Scripts
src/scripts/initializeConfigurations.ts, src/scripts/testConfigurationSystem.ts, package.json
Adds scripts to initialize default configurations/feature flags and to test the configuration system. Updates package.json scripts section accordingly.
App Integration
src/app.ts, src/config/db.ts, src/index.ts
Integrates configuration middleware and routes into the Express app, registers new entities with TypeORM, and ensures configuration service initialization at startup.
Permissions Update
src/entities/Permission.ts
Adds CONFIGURATION as a new resource to the PermissionResource enum.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ExpressApp
    participant ConfigMiddleware
    participant ConfigController
    participant ConfigService
    participant DB

    Client->>ExpressApp: HTTP Request (/api/config/...)
    ExpressApp->>ConfigMiddleware: Inject config & feature flag access
    ConfigMiddleware->>ConfigService: Fetch config/flag (cache/db)
    ConfigService->>DB: Query configurations/flags
    DB-->>ConfigService: Return data
    ConfigService-->>ConfigMiddleware: Return config/flag
    ConfigMiddleware-->>ExpressApp: Attach config/flag access to req
    ExpressApp->>ConfigController: Route handler
    ConfigController->>ConfigService: Perform CRUD/eval operation
    ConfigService->>DB: Read/write as needed
    ConfigService-->>ConfigController: Return result
    ConfigController-->>ExpressApp: Send response
    ExpressApp-->>Client: HTTP Response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
Centralized configuration management by environment, including database storage and environment files (#117)
Automatic validation of required configurations at startup (#117)
Feature flags system with dynamic toggle API and targeting (#117)
Encrypted configurations for sensitive data (#117)
REST API for configuration management (/api/config) (#117)
Hot-reload of configurations without server restart (#117)
Audit log of all configuration changes (#117)
Complete documentation of available configurations (#117)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Suggested reviewers

  • MPSxDev

Poem

A rabbit hopped through configs anew,
With flags and secrets, all secure and true.
Environments three—dev, stage, and prod—
Now managed with care, not left to odd.
Hot reloads and docs, a system so bright,
PayStell's configs now hop just right!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99b4812 and f27f19c.

📒 Files selected for processing (1)
  • src/app.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🧹 Nitpick comments (15)
src/app.ts (1)

159-160: Consider moving import to top of file.

While the functionality is correct, the route import is placed unusually late in the file. For better code organization and consistency with other route imports, consider moving this to the top with the other route imports around line 28.

+import configurationRoutes from "./routes/configurationRoutes";
 
 // Route imports
 import sessionRouter from "./routes/session.routes";
 // ... other imports

 // Later in the file, remove the late import:
-// Configuration routes
-import configurationRoutes from "./routes/configurationRoutes";
 app.use("/api/config", configurationRoutes);
src/tests/integration/configurationIntegration.test.ts (1)

276-301: Add more validation test scenarios.

The current validation test only covers empty required configurations. Consider testing:

  • Invalid values when allowedValues is specified
  • Expired configurations
  • Type mismatches
  • Invalid validation rules
it("should validate allowed values", async () => {
  await request(app)
    .post("/api/config")
    .set("Authorization", `Bearer ${authToken}`)
    .send({
      key: "LOG_LEVEL",
      value: "invalid_level",
      type: "string",
      category: "general",
      allowedValues: ["error", "warn", "info", "debug"],
    });

  const validateResponse = await request(app)
    .get("/api/config/validate")
    .set("Authorization", `Bearer ${authToken}`);

  expect(validateResponse.body.data.isValid).toBe(false);
  expect(validateResponse.body.data.errors).toContain(
    expect.stringContaining("LOG_LEVEL")
  );
});

it("should detect expired configurations", async () => {
  await request(app)
    .post("/api/config")
    .set("Authorization", `Bearer ${authToken}`)
    .send({
      key: "TEMP_CONFIG",
      value: "temp_value",
      type: "string",
      category: "general",
      expiresAt: new Date(Date.now() - 1000).toISOString(),
    });

  const validateResponse = await request(app)
    .get("/api/config/validate")
    .set("Authorization", `Bearer ${authToken}`);

  expect(validateResponse.body.data.warnings).toContain(
    expect.stringContaining("expired")
  );
});
src/scripts/testConfigurationSystem.ts (4)

108-117: Consider deterministic testing for percentage rollouts.

The percentage rollout evaluation for user3 might not be deterministic. With a 50% rollout, the same user should consistently get the same result based on a hash of their ID.

// Verify that the same user gets consistent results
const evaluation1 = await configurationService.evaluateFeatureFlag("test_targeted_flag", {
  userId: "user3",
});
const evaluation2 = await configurationService.evaluateFeatureFlag("test_targeted_flag", {
  userId: "user3",
});
logger.info(`✅ Percentage rollout consistency: ${evaluation1.isEnabled === evaluation2.isEnabled}`);

143-157: Enhance cache performance testing with more metrics.

The current cache test only measures total time. Consider adding more detailed metrics to better understand cache performance.

// Test cache performance with cold and warm cache
logger.info("\n📝 Test 7: Cache Management");

// Clear cache first
configurationService.clearCache();

// Cold cache test
const coldStart = Date.now();
await configurationService.getConfig("TEST_CONFIG");
const coldTime = Date.now() - coldStart;
logger.info(`✅ Cold cache retrieval: ${coldTime}ms`);

// Warm cache test
const warmStart = Date.now();
for (let i = 0; i < 10; i++) {
  await configurationService.getConfig("TEST_CONFIG");
}
const warmTime = Date.now() - warmStart;
logger.info(`✅ Warm cache retrieval (10 requests): ${warmTime}ms`);
logger.info(`✅ Average warm cache time: ${warmTime / 10}ms per request`);

// Clear cache
configurationService.clearCache();
logger.info("✅ Cache cleared successfully");

204-211: Improve error handling in cleanup section.

The cleanup errors are only logged as warnings. Consider collecting all cleanup errors and reporting them at the end.

const cleanupErrors = [];
for (const configKey of testConfigs) {
  try {
    await configurationService.deleteConfig(configKey, "test-script");
    logger.info(`✅ Deleted configuration: ${configKey}`);
  } catch (error) {
    cleanupErrors.push({ key: configKey, error });
    logger.warn(`⚠️  Could not delete ${configKey}: ${error}`);
  }
}

if (cleanupErrors.length > 0) {
  logger.error(`❌ Cleanup completed with ${cleanupErrors.length} errors`);
}

221-225: Consider making process.exit optional for better reusability.

The hardcoded process.exit() calls make this script difficult to use in test suites or as part of larger scripts.

async function testConfigurationSystem(options = { exitOnComplete: true }) {
  try {
    // ... existing test code ...
    
    logger.info("✅ Environment-specific configurations work correctly");
    
    if (options.exitOnComplete) {
      process.exit(0);
    }
    return { success: true };
  } catch (error) {
    logger.error("❌ Configuration System Test Failed:", error);
    if (options.exitOnComplete) {
      process.exit(1);
    }
    throw error;
  }
}
src/tests/services/ConfigurationService.test.ts (1)

213-220: Make encryption test less implementation-specific.

The test assumes encrypted values contain ":" which is implementation-specific. Test that the value is encrypted rather than the format.

 expect(mockConfigRepository.create).toHaveBeenCalledWith(
   expect.objectContaining({
     key: "SENSITIVE_CONFIG",
-    value: expect.stringContaining(":"), // Encrypted format
+    value: expect.not.stringMatching("secret_value"), // Value should be encrypted
     isEncrypted: true,
   })
 );
+
+// Additionally verify the value was actually encrypted
+const savedValue = mockConfigRepository.create.mock.calls[0][0].value;
+expect(savedValue).not.toBe("secret_value");
+expect(savedValue.length).toBeGreaterThan(0);
src/routes/configurationRoutes.ts (2)

15-28: Add type-based validation for configuration values.

The value field should be validated based on the specified type to catch type mismatches early.

const configurationValidation = [
  body("key").isString().isLength({ min: 1, max: 255 }).withMessage("Key is required and must be 1-255 characters"),
  body("value").notEmpty().withMessage("Value is required")
    .custom((value, { req }) => {
      const type = req.body.type || ConfigurationType.STRING;
      switch (type) {
        case ConfigurationType.NUMBER:
          return !isNaN(Number(value));
        case ConfigurationType.BOOLEAN:
          return ["true", "false", true, false].includes(value);
        case ConfigurationType.JSON:
          try {
            JSON.parse(typeof value === "string" ? value : JSON.stringify(value));
            return true;
          } catch {
            return false;
          }
        default:
          return true;
      }
    }).withMessage("Value must match the specified type"),
  // ... rest of validations
];

267-274: Consider adding soft delete option for configuration deletion.

Deleting configurations permanently could be risky. Consider adding a soft delete option to maintain audit history.

Add a query parameter for soft delete:

router.delete(
  "/:key",
  authMiddleware as RequestHandler,
  requirePermission(PermissionResource.CONFIGURATION, PermissionAction.DELETE),
  param("key").isString().withMessage("Key must be a string"),
  query("permanent").optional().isBoolean().withMessage("Permanent must be a boolean"),
  handleValidationErrors,
  configurationController.deleteConfiguration.bind(configurationController) as RequestHandler,
);

Update the OpenAPI documentation:

parameters:
  - in: query
    name: permanent
    schema:
      type: boolean
      default: false
    description: Permanently delete the configuration (default is soft delete)
docs/CONFIGURATION_SYSTEM.md (4)

64-66: Default boolean flags should be NOT NULL

is_encrypted, is_active, and is_required are BOOLEAN columns without NOT NULL.
Making them NOT NULL DEFAULT FALSE avoids NULL/FALSE ambiguity and simplifies ORM logic.


84-89: status duplicates is_enabled – remove or document difference

The feature_flags table stores both is_enabled and status. Unless status has semantics beyond enabled/disabled (e.g., “scheduled”), the double flag increases cognitive load and can drift.


126-131: Inconsistent casing in JSON payload keys

API section uses camelCase (isRequired, isEncrypted) while the DB schema and code sections use snake_case (is_required, is_encrypted). Unify the convention or document the mapping layer.


378-382: Prefer AEAD mode (AES-256-GCM) over CBC

AES-256-CBC provides confidentiality but no built-in integrity; misuse can lead to padding-oracle attacks. Modern best practice is an authenticated mode such as AES-256-GCM or XChaCha20-Poly1305.

src/entities/FeatureFlag.ts (1)

95-97: Consider using array type for tags

Storing tags as a comma-separated string limits querying capabilities. Consider using a JSONB array instead for better indexing and querying:

-  @Column({ type: "text", nullable: true })
+  @Column({ type: "jsonb", nullable: true })
   @IsOptional()
-  tags?: string; // Comma-separated tags
+  tags?: string[]; // Array of tags
src/services/ConfigurationService.ts (1)

340-354: Consider using a more efficient hashing algorithm

While MD5 is sufficient for distribution purposes, consider using a faster non-cryptographic hash like xxHash or CityHash for better performance in high-traffic scenarios:

-      const hash = crypto.createHash("md5").update(`${flagName}:${userId}`).digest("hex");
+      // Use a faster hash function for better performance
+      const hash = someNonCryptoHash(`${flagName}:${userId}`);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae6799f and f13dfdc.

📒 Files selected for processing (16)
  • README.md (2 hunks)
  • docs/CONFIGURATION_SYSTEM.md (1 hunks)
  • package.json (1 hunks)
  • src/app.ts (3 hunks)
  • src/config/db.ts (2 hunks)
  • src/controllers/ConfigurationController.ts (1 hunks)
  • src/entities/Configuration.ts (1 hunks)
  • src/entities/FeatureFlag.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/middlewares/configurationMiddleware.ts (1 hunks)
  • src/routes/configurationRoutes.ts (1 hunks)
  • src/scripts/initializeConfigurations.ts (1 hunks)
  • src/scripts/testConfigurationSystem.ts (1 hunks)
  • src/services/ConfigurationService.ts (1 hunks)
  • src/tests/integration/configurationIntegration.test.ts (1 hunks)
  • src/tests/services/ConfigurationService.test.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (10)
src/index.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (619-619)
src/app.ts (1)
src/middlewares/configurationMiddleware.ts (2)
  • configurationMiddleware (23-49)
  • environmentConfigMiddleware (123-153)
src/tests/integration/configurationIntegration.test.ts (2)
src/services/ConfigurationService.ts (1)
  • configurationService (619-619)
src/lib/services/referral-service.ts (1)
  • request (25-68)
src/scripts/initializeConfigurations.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (619-619)
src/scripts/testConfigurationSystem.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (619-619)
src/controllers/ConfigurationController.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (619-619)
src/services/ConfigurationService.ts (1)
src/services/AuditService.ts (1)
  • AuditService (34-170)
src/entities/Configuration.ts (1)
src/entities/FeatureFlag.ts (1)
  • Entity (26-107)
src/entities/FeatureFlag.ts (1)
src/entities/Configuration.ts (1)
  • Entity (39-119)
src/middlewares/configurationMiddleware.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (619-619)
🔇 Additional comments (36)
src/config/db.ts (1)

19-20: LGTM! Proper entity registration for configuration system.

The new Configuration and FeatureFlag entities are correctly imported and registered in the TypeORM DataSource. The import paths follow the established pattern and the entities are properly added to the entities array, enabling the ORM to manage these tables.

Also applies to: 50-51

src/index.ts (1)

4-4: Excellent initialization sequence.

The configuration service is properly initialized after the database connection and before the server starts listening. This ensures that all configurations and feature flags are loaded and validated before handling requests. The async/await pattern and error handling are correctly implemented.

Also applies to: 12-14

package.json (1)

16-18: Well-structured script additions.

The new configuration management scripts follow established naming conventions and use the same ts-node pattern as the existing init-rbac script. The trailing comma addition maintains consistent JSON formatting.

src/app.ts (1)

42-42: Proper middleware integration.

The configuration middleware is correctly placed after audit middleware and before route handlers. This ensures that configuration access and environment information are available to all routes while maintaining the audit trail.

Also applies to: 122-123

README.md (1)

16-20: Comprehensive documentation for the new configuration system.

The README updates effectively highlight the new multi-environment configuration management capabilities. The feature list clearly communicates the key benefits (dynamic updates, encryption, audit logging), and the configuration management section provides practical API endpoint documentation and setup instructions.

Also applies to: 72-96

src/tests/integration/configurationIntegration.test.ts (1)

215-274: Well-structured service integration tests.

The service integration tests properly verify the interaction between the API and the configuration service, including correct type conversion for different data types.

src/scripts/testConfigurationSystem.ts (1)

1-58: Well-structured test initialization and basic operations.

The script properly initializes the database and configuration service, with clear logging for test progress tracking.

src/tests/services/ConfigurationService.test.ts (3)

1-53: Well-structured mock setup for unit testing.

The mock setup properly isolates the ConfigurationService for unit testing with appropriate repository and service mocks.


290-465: Comprehensive feature flag testing coverage.

The feature flag tests thoroughly cover evaluation scenarios including disabled flags, targeting rules, and percentage rollouts.


467-536: Good coverage of validation and cache management scenarios.

The tests properly verify required configuration validation, expiration checking, and cache management operations.

src/routes/configurationRoutes.ts (2)

402-588: Well-designed feature flag routes with comprehensive evaluation support.

The feature flag routes properly handle different scopes and evaluation contexts with appropriate query parameters for userId, merchantId, and userRole.


677-684: Encrypted values are already masked in export endpoint

The exportConfigurations method replaces any encrypted configuration values with "[ENCRYPTED]" before exporting, so no plaintext encrypted data is exposed.

src/entities/Configuration.ts (1)

1-119: Well-structured entity with comprehensive configuration support.

The entity design is solid with proper indexing, validation, and support for various configuration types including encryption, validation rules, and metadata.

src/entities/FeatureFlag.ts (3)

1-10: Imports look good

All necessary TypeORM and validation decorators are properly imported. The shared Environment enum creates appropriate coupling between related entities.


12-24: Well-structured enums with clear string values

The enums use descriptive string values which improves database readability and debugging. The scope and status options comprehensively cover the feature flag use cases.


26-68: Entity structure and indexing are well-designed

The entity properly uses decorators, has appropriate indexes for performance and uniqueness constraints, and includes all necessary fields for a feature flag system.

src/controllers/ConfigurationController.ts (8)

1-9: Clean imports with proper separation of concerns

The controller properly delegates business logic to the service layer and imports only what's needed.


13-31: Excellent security practice masking encrypted values

The consistent masking of encrypted values in responses prevents accidental exposure of sensitive data.


60-70: Fix async function flow after validation error

After sending the validation error response, the function continues execution. Add proper return:

       if (!errors.isEmpty()) {
         res.status(400).json({
           success: false,
           message: "Validation failed",
           errors: errors.array(),
         });
         return;
       }

Actually, the return statement is already there on line 70, so this is correct.


135-142: Good validation of category parameter

The method properly validates that the category parameter is a valid enum value before proceeding.


215-259: Well-structured feature flag creation with proper date handling

The method correctly handles date string conversion and includes audit information.


264-282: Clean feature flag evaluation implementation

The method properly extracts context from query parameters and delegates to the service for evaluation logic.


287-315: Efficient statistics aggregation

The method efficiently computes statistics in a single pass using reduce, providing valuable insights into configuration usage.


355-409: Robust import implementation with good error handling

The import method properly:

  • Validates input format
  • Handles individual configuration errors without failing the entire import
  • Provides detailed feedback on import results
  • Respects the overwrite flag for existing configurations
src/services/ConfigurationService.ts (7)

1-25: Well-structured interfaces for type safety

The interfaces provide clear contracts for configuration values, validation results, and feature flag evaluations.


58-76: Robust initialization with proper validation

The initialization method ensures all required configurations are present at startup, preventing runtime failures.


81-121: Efficient caching strategy with proper decryption handling

The method implements a good caching pattern and transparently handles encrypted values.


126-215: Comprehensive configuration management with audit trail

The setConfig method properly handles:

  • Create vs update logic
  • Transparent encryption
  • Audit logging with old/new values
  • Cache invalidation

288-361: Well-implemented feature flag evaluation with comprehensive checks

The evaluation logic properly handles:

  • Flag existence and active status
  • Time-based scheduling
  • Targeting rules evaluation
  • Percentage-based rollouts with consistent hashing

506-542: Thorough validation of required configurations

The validation method comprehensively checks:

  • Presence of required values
  • Expiration dates
  • Allowed values constraints

618-619: Appropriate use of singleton pattern

The singleton instance ensures consistent configuration state across the application.

src/middlewares/configurationMiddleware.ts (5)

5-18: Clean TypeScript interface extension

Properly extends the Express Request interface to include configuration methods with appropriate type signatures.


20-49: Well-implemented configuration injection middleware

The middleware properly injects configuration access methods into the request object with appropriate error handling.


54-84: Useful validation middleware with clear error reporting

The middleware provides clear feedback about missing configurations, making debugging easier.


89-118: Excellent feature flag middleware with context awareness

The middleware properly extracts user context and provides clear feedback when features are disabled.


158-188: Smart request-scoped caching implementation

The middleware adds an efficient caching layer that prevents redundant configuration lookups within the same request lifecycle.

Comment thread docs/CONFIGURATION_SYSTEM.md
Comment on lines +69 to +77
@Column({ type: "jsonb", nullable: true })
@IsOptional()
targetingRules?: {
userIds?: string[];
merchantIds?: string[];
userRoles?: string[];
percentage?: number; // For percentage-based rollouts
conditions?: Record<string, unknown>;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add percentage validation in targetingRules

The percentage field in targetingRules should be validated to ensure it's between 0 and 100. Consider adding validation logic in the service layer or database constraints.

🤖 Prompt for AI Agents
In src/entities/FeatureFlag.ts around lines 69 to 77, the percentage field
inside targetingRules lacks validation to ensure its value is between 0 and 100.
Add validation logic either by using class-validator decorators like @Min(0) and
@Max(100) on the percentage property or implement a custom validation method in
the service layer that checks this range before saving or updating the entity.

Comment on lines +120 to +153
/**
* Middleware to inject environment-specific configurations
*/
export const environmentConfigMiddleware = async (
req: Request,
res: Response,
next: NextFunction
): Promise<void> => {
try {
// Inject environment-specific configurations
const environment = process.env.NODE_ENV || "development";

// Add environment info to request
req.environment = environment;

// Load common configurations
const commonConfigs = await Promise.all([
configurationService.getConfig("APP_NAME", "PayStell"),
configurationService.getConfig("APP_VERSION", "1.0.0"),
configurationService.getConfig("ENVIRONMENT", environment),
]);

req.appConfig = {
name: commonConfigs[0] as string,
version: commonConfigs[1] as string,
environment: commonConfigs[2] as string,
};

next();
} catch (error) {
logger.error("Environment config middleware error:", error);
next(error);
}
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add TypeScript declarations for injected properties

The middleware adds environment and appConfig to the request but these aren't declared in the TypeScript interface:

 declare global {
   namespace Express {
     interface Request {
       config?: {
         get: (key: string, defaultValue?: string) => Promise<string | number | boolean | Record<string, unknown> | null>;
         isFeatureEnabled: (flagName: string, context?: {
           userId?: string;
           merchantId?: string;
           userRole?: string;
         }) => Promise<boolean>;
       };
+      environment?: string;
+      appConfig?: {
+        name: string;
+        version: string;
+        environment: string;
+      };
     }
   }
 }
🤖 Prompt for AI Agents
In src/middlewares/configurationMiddleware.ts around lines 120 to 153, the
middleware adds environment and appConfig properties to the request object but
these are not declared in the TypeScript Request interface. To fix this, extend
the Express Request interface by declaring these properties in a separate type
declaration file or within the same file using module augmentation. Define
environment as a string and appConfig as an object with name, version, and
environment string properties to ensure proper typing and avoid TypeScript
errors.

Comment thread src/routes/configurationRoutes.ts
Comment thread src/scripts/initializeConfigurations.ts
Comment thread src/services/ConfigurationService.ts
Comment on lines +20 to +23
// Create a test user and get auth token
// This would normally be done through the auth system
authToken = "test-auth-token";
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Generate proper authentication tokens for tests instead of using hardcoded values.

The hardcoded auth token "test-auth-token" bypasses actual authentication testing. Consider generating real JWT tokens or mocking the auth middleware properly to ensure authentication is correctly tested.

-    // Create a test user and get auth token
-    // This would normally be done through the auth system
-    authToken = "test-auth-token";
+    // Create a test user and generate a proper auth token
+    const testUser = await createTestUser();
+    authToken = await generateAuthToken(testUser);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Create a test user and get auth token
// This would normally be done through the auth system
authToken = "test-auth-token";
});
// Create a test user and generate a proper auth token
const testUser = await createTestUser();
authToken = await generateAuthToken(testUser);
🤖 Prompt for AI Agents
In src/tests/integration/configurationIntegration.test.ts around lines 20 to 23,
replace the hardcoded auth token "test-auth-token" with a properly generated
authentication token. Implement code to generate a valid JWT token using the
same secret and payload structure as the real authentication system, or mock the
authentication middleware to simulate real authentication behavior. This ensures
the tests validate authentication logic correctly instead of bypassing it.

Comment on lines +38 to +155
describe("Configuration API Endpoints", () => {
it("should create and retrieve a configuration", async () => {
// Create configuration
const createResponse = await request(app)
.post("/api/config")
.set("Authorization", `Bearer ${authToken}`)
.send({
key: "TEST_CONFIG",
value: "test_value",
type: "string",
category: "general",
description: "Test configuration",
isRequired: false,
});

expect(createResponse.status).toBe(201);
expect(createResponse.body.success).toBe(true);

// Retrieve configuration
const getResponse = await request(app)
.get("/api/config/TEST_CONFIG")
.set("Authorization", `Bearer ${authToken}`);

expect(getResponse.status).toBe(200);
expect(getResponse.body.data.value).toBe("test_value");
});

it("should handle encrypted configurations", async () => {
// Create encrypted configuration
const createResponse = await request(app)
.post("/api/config")
.set("Authorization", `Bearer ${authToken}`)
.send({
key: "ENCRYPTED_CONFIG",
value: "secret_value",
type: "string",
category: "security",
description: "Encrypted configuration",
isEncrypted: true,
isRequired: false,
});

expect(createResponse.status).toBe(201);

// Retrieve configuration (should show as encrypted)
const getResponse = await request(app)
.get("/api/config")
.set("Authorization", `Bearer ${authToken}`);

expect(getResponse.status).toBe(200);
const encryptedConfig = getResponse.body.data.find(
(config: any) => config.key === "ENCRYPTED_CONFIG"
);
expect(encryptedConfig.value).toBe("[ENCRYPTED]");
});

it("should get configurations by category", async () => {
// Create configurations in different categories
await request(app)
.post("/api/config")
.set("Authorization", `Bearer ${authToken}`)
.send({
key: "PAYMENT_CONFIG",
value: "100",
type: "number",
category: "payment",
description: "Payment configuration",
});

await request(app)
.post("/api/config")
.set("Authorization", `Bearer ${authToken}`)
.send({
key: "SECURITY_CONFIG",
value: "true",
type: "boolean",
category: "security",
description: "Security configuration",
});

// Get configurations by category
const response = await request(app)
.get("/api/config/category/payment")
.set("Authorization", `Bearer ${authToken}`);

expect(response.status).toBe(200);
expect(response.body.data.length).toBe(1);
expect(response.body.data[0].key).toBe("PAYMENT_CONFIG");
});

it("should delete configuration", async () => {
// Create configuration
await request(app)
.post("/api/config")
.set("Authorization", `Bearer ${authToken}`)
.send({
key: "TO_DELETE",
value: "delete_me",
type: "string",
category: "general",
});

// Delete configuration
const deleteResponse = await request(app)
.delete("/api/config/TO_DELETE")
.set("Authorization", `Bearer ${authToken}`);

expect(deleteResponse.status).toBe(200);
expect(deleteResponse.body.success).toBe(true);

// Verify it's deleted
const getResponse = await request(app)
.get("/api/config/TO_DELETE")
.set("Authorization", `Bearer ${authToken}`);

expect(getResponse.status).toBe(404);
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add missing test scenarios for comprehensive coverage.

The configuration API tests are missing several important scenarios:

  • Updating existing configurations
  • Type validation (e.g., passing string when number is expected)
  • Required field validation
  • Unauthorized access attempts (403 scenarios)
  • Invalid data handling (400 scenarios)
  • Environment-specific configuration handling

Consider adding these test cases:

it("should update existing configuration", async () => {
  // Create initial configuration
  await request(app)
    .post("/api/config")
    .set("Authorization", `Bearer ${authToken}`)
    .send({
      key: "UPDATE_TEST",
      value: "initial_value",
      type: "string",
      category: "general",
    });

  // Update configuration
  const updateResponse = await request(app)
    .post("/api/config")
    .set("Authorization", `Bearer ${authToken}`)
    .send({
      key: "UPDATE_TEST",
      value: "updated_value",
      type: "string",
      category: "general",
    });

  expect(updateResponse.status).toBe(200);
  expect(updateResponse.body.data.value).toBe("updated_value");
});

it("should return 403 for unauthorized access", async () => {
  const response = await request(app)
    .get("/api/config")
    .set("Authorization", "Bearer invalid-token");

  expect(response.status).toBe(403);
});

it("should validate configuration types", async () => {
  const response = await request(app)
    .post("/api/config")
    .set("Authorization", `Bearer ${authToken}`)
    .send({
      key: "TYPE_TEST",
      value: "not-a-number",
      type: "number",
      category: "general",
    });

  expect(response.status).toBe(400);
});
🤖 Prompt for AI Agents
In src/tests/integration/configurationIntegration.test.ts between lines 38 and
155, the existing tests lack coverage for updating configurations, type
validation, required field validation, unauthorized access, invalid data
handling, and environment-specific configurations. Add new test cases to cover
these scenarios: a test to update an existing configuration and verify the
update succeeds with status 200; a test to check that unauthorized requests
return a 403 status; and a test to validate that sending incorrect types (e.g.,
string instead of number) returns a 400 error. Implement these tests following
the existing test structure and use appropriate assertions for status codes and
response bodies.

Comment on lines +157 to +213
describe("Feature Flag API Endpoints", () => {
it("should create and evaluate feature flag", async () => {
// Create feature flag
const createResponse = await request(app)
.post("/api/config/feature-flags")
.set("Authorization", `Bearer ${authToken}`)
.send({
name: "test_feature",
description: "Test feature flag",
isEnabled: true,
scope: "global",
});

expect(createResponse.status).toBe(201);
expect(createResponse.body.success).toBe(true);

// Evaluate feature flag
const evaluateResponse = await request(app)
.get("/api/config/feature-flags/test_feature/evaluate")
.set("Authorization", `Bearer ${authToken}`);

expect(evaluateResponse.status).toBe(200);
expect(evaluateResponse.body.data.isEnabled).toBe(true);
});

it("should handle targeted feature flags", async () => {
// Create targeted feature flag
await request(app)
.post("/api/config/feature-flags")
.set("Authorization", `Bearer ${authToken}`)
.send({
name: "targeted_feature",
description: "Targeted feature flag",
isEnabled: true,
scope: "user",
targetingRules: {
userIds: ["user1", "user2"],
},
});

// Evaluate with matching user
const matchResponse = await request(app)
.get("/api/config/feature-flags/targeted_feature/evaluate?userId=user1")
.set("Authorization", `Bearer ${authToken}`);

expect(matchResponse.status).toBe(200);
expect(matchResponse.body.data.isEnabled).toBe(true);

// Evaluate with non-matching user
const noMatchResponse = await request(app)
.get("/api/config/feature-flags/targeted_feature/evaluate?userId=user3")
.set("Authorization", `Bearer ${authToken}`);

expect(noMatchResponse.status).toBe(200);
expect(noMatchResponse.body.data.isEnabled).toBe(false);
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Expand feature flag tests to cover all targeting scenarios.

The current tests only cover user-based targeting. Add tests for:

  • Merchant-based targeting
  • Role-based targeting
  • Percentage rollouts
  • Scheduled feature flags (start/end dates)
it("should handle percentage-based rollouts", async () => {
  await request(app)
    .post("/api/config/feature-flags")
    .set("Authorization", `Bearer ${authToken}`)
    .send({
      name: "percentage_feature",
      description: "Percentage rollout feature",
      isEnabled: true,
      scope: "user",
      targetingRules: {
        percentage: 50,
      },
    });

  // Test multiple evaluations to verify percentage distribution
  const results = [];
  for (let i = 0; i < 100; i++) {
    const response = await request(app)
      .get(`/api/config/feature-flags/percentage_feature/evaluate?userId=user${i}`)
      .set("Authorization", `Bearer ${authToken}`);
    results.push(response.body.data.isEnabled);
  }

  const enabledCount = results.filter(r => r).length;
  expect(enabledCount).toBeGreaterThan(30);
  expect(enabledCount).toBeLessThan(70);
});

it("should handle role-based targeting", async () => {
  await request(app)
    .post("/api/config/feature-flags")
    .set("Authorization", `Bearer ${authToken}`)
    .send({
      name: "role_feature",
      description: "Role-based feature",
      isEnabled: true,
      scope: "user",
      targetingRules: {
        roles: ["admin", "super_admin"],
      },
    });

  const adminResponse = await request(app)
    .get("/api/config/feature-flags/role_feature/evaluate?userRole=admin")
    .set("Authorization", `Bearer ${authToken}`);
  expect(adminResponse.body.data.isEnabled).toBe(true);

  const userResponse = await request(app)
    .get("/api/config/feature-flags/role_feature/evaluate?userRole=user")
    .set("Authorization", `Bearer ${authToken}`);
  expect(userResponse.body.data.isEnabled).toBe(false);
});
🤖 Prompt for AI Agents
In src/tests/integration/configurationIntegration.test.ts between lines 157 and
213, the feature flag tests currently only cover user-based targeting. Expand
these tests by adding new test cases for merchant-based targeting, role-based
targeting, percentage rollouts, and scheduled feature flags with start and end
dates. For percentage rollouts, simulate multiple evaluations to verify the
distribution falls within expected bounds. For role-based targeting, test with
roles that should and should not enable the feature. Similarly, add tests for
merchant targeting and scheduled flags to fully cover all targeting scenarios.

Comment thread src/tests/services/ConfigurationService.test.ts
- Rename 'key' column to 'configKey' to avoid SQL reserved word conflicts
- Remove hardcoded passwords, use environment variables instead
- Improve encryption key derivation using scryptSync
- Add proper TypeScript type declarations for Express Request
- Add percentage validation (0-100) in targeting rules
- Add CONFIGURATION permission resource
- Fix user ID type conversions (number → string)
- Enhance test coverage with missing scenarios
- Add production confirmation for bulk imports
- Fix mock decryption in unit tests

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (4)
src/tests/integration/configurationIntegration.test.ts (1)

20-23: Generate proper authentication tokens for tests instead of using hardcoded values.

The hardcoded auth token "test-auth-token" bypasses actual authentication testing. Consider generating real JWT tokens or mocking the auth middleware properly to ensure authentication is correctly tested.

src/middlewares/configurationMiddleware.ts (1)

5-18: Add TypeScript declarations for injected properties

The middleware adds environment and appConfig properties to the request object but these aren't declared in the TypeScript interface, which will cause TypeScript errors when accessing these properties.

src/services/ConfigurationService.ts (1)

47-53: Security concern: Remove hardcoded default encryption key

Using a hardcoded default encryption key is a critical security vulnerability. The application should fail to start if the encryption key is not properly configured.

src/routes/configurationRoutes.ts (1)

747-754: Import validation safety checks are already implemented.

The suggested safety confirmations for bulk configuration import have already been implemented in the importValidation schema (lines 43-53). The validation includes array checking, boolean validation for overwrite, and production confirmation with today's date.

🧹 Nitpick comments (4)
src/entities/Configuration.ts (1)

91-110: Consider using JSON column type for better database support.

The entity stores JSON data in text columns (validationRules, allowedValues, metadata). While this works, consider using TypeORM's json column type for databases that support it (PostgreSQL, MySQL 5.7+). This provides better type safety and performance:

-  @Column({ type: "text", nullable: true })
+  @Column({ type: "json", nullable: true })
   @IsOptional()
-  validationRules?: string; // JSON string for validation rules
+  validationRules?: Record<string, any>;
PR_DESCRIPTION.md (1)

42-58: Add language specification to the code block.

The code block showing API endpoints should specify the language for proper syntax highlighting:

-```
+```bash
 GET    /api/config                    # Get all configurations
docs/CONFIGURATION_SYSTEM.md (1)

370-382: Enhance encryption key security guidance

While the documentation mentions storing the encryption key in an environment variable, it should emphasize that this key must be securely managed and never committed to version control.

Consider adding a security warning:

 ### 3. Environment Variables
 Ensure these environment variables are set:
 ```bash
 NODE_ENV=development
-CONFIG_ENCRYPTION_KEY=your-encryption-key
+CONFIG_ENCRYPTION_KEY=your-encryption-key  # CRITICAL: Use a strong, randomly generated key. Never commit to version control!

+⚠️ Security Warning: The CONFIG_ENCRYPTION_KEY must be:
+- At least 32 characters long
+- Randomly generated (use a tool like openssl rand -hex 32)
+- Stored securely (e.g., in a secrets management system)
+- Different for each environment
+- Rotated periodically


</blockquote></details>
<details>
<summary>src/middlewares/configurationMiddleware.ts (1)</summary><blockquote>

`162-192`: **Document middleware dependency and ordering requirement**

The `configCacheMiddleware` assumes that `req.config` already exists, which means it must run after `configurationMiddleware`. This dependency should be documented to prevent middleware ordering issues.

Add a comment to clarify the dependency:

```diff
 /**
  * Middleware to cache configuration values for the duration of the request
+ * 
+ * Note: This middleware must be applied AFTER configurationMiddleware
+ * as it depends on req.config being available.
  */
 export const configCacheMiddleware = async (
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f13dfdc and 5f595c5.

📒 Files selected for processing (14)
  • PR_DESCRIPTION.md (1 hunks)
  • docs/CONFIGURATION_SYSTEM.md (1 hunks)
  • src/controllers/ConfigurationController.ts (1 hunks)
  • src/entities/Configuration.ts (1 hunks)
  • src/entities/FeatureFlag.ts (1 hunks)
  • src/entities/Permission.ts (1 hunks)
  • src/middlewares/configurationMiddleware.ts (1 hunks)
  • src/routes/configurationRoutes.ts (1 hunks)
  • src/scripts/initializeConfigurations.ts (1 hunks)
  • src/scripts/testConfigurationSystem.ts (1 hunks)
  • src/services/ConfigurationService.ts (1 hunks)
  • src/tests/integration/configurationIntegration.test.ts (1 hunks)
  • src/tests/services/ConfigurationService.test.ts (1 hunks)
  • src/types/express.d.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/entities/Permission.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/tests/services/ConfigurationService.test.ts
  • src/scripts/testConfigurationSystem.ts
  • src/entities/FeatureFlag.ts
  • src/scripts/initializeConfigurations.ts
🧰 Additional context used
🧬 Code Graph Analysis (5)
src/tests/integration/configurationIntegration.test.ts (2)
src/services/ConfigurationService.ts (1)
  • configurationService (637-637)
src/lib/services/referral-service.ts (1)
  • request (25-68)
src/middlewares/configurationMiddleware.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (637-637)
src/routes/configurationRoutes.ts (3)
src/controllers/ConfigurationController.ts (1)
  • ConfigurationController (9-419)
src/middlewares/permissionMiddleware.ts (1)
  • requirePermission (18-64)
src/middlewares/validationErrorHandler.ts (1)
  • handleValidationErrors (5-42)
src/controllers/ConfigurationController.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (637-637)
src/services/ConfigurationService.ts (1)
src/services/AuditService.ts (1)
  • AuditService (34-170)
🪛 markdownlint-cli2 (0.17.2)
PR_DESCRIPTION.md

11-11: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


20-20: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


28-28: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


41-41: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


42-42: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


59-59: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


73-73: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


78-78: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


88-88: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


102-102: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


109-109: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


115-115: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


120-120: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

🔇 Additional comments (5)
src/tests/integration/configurationIntegration.test.ts (2)

350-397: Great job implementing the previously requested test scenarios!

The additional test cases for updating configurations, unauthorized access (403), and type validation (400) properly address the testing gaps identified in the previous review. The implementation correctly validates the expected status codes and response behaviors.


399-450: Excellent implementation of the additional feature flag test scenarios!

The tests for percentage-based rollouts and role-based targeting comprehensively cover the previously missing scenarios. The percentage distribution validation (30-70% range for 50% rollout) and role-based access checks are well-implemented.

src/types/express.d.ts (1)

26-39: Well-designed TypeScript interface extension for configuration access.

The addition of config, environment, and appConfig properties to the Express Request interface is clean and follows best practices. The async methods with proper typing and optional parameters provide a flexible API for configuration access throughout the application.

docs/CONFIGURATION_SYSTEM.md (1)

55-75: Configuration schema looks good!

The SQL schema properly uses config_key instead of reserved keywords, includes appropriate indexes with the unique constraint, and covers all necessary fields for a robust configuration management system.

src/routes/configurationRoutes.ts (1)

1-756: Well-structured configuration routes implementation.

The routes module is comprehensively implemented with proper authentication, authorization, validation, and documentation. The code follows consistent patterns and includes all necessary security measures.

Consider these optional enhancements for future iterations:

  • Add rate limiting middleware to mutation endpoints (POST, DELETE) to prevent abuse
  • Set request size limits for the import endpoint to prevent memory exhaustion
  • Consider dependency injection for the ConfigurationController to improve testability

Comment thread src/controllers/ConfigurationController.ts Outdated
Comment thread src/services/ConfigurationService.ts
Comment thread src/services/ConfigurationService.ts
- Improve encryption security with proper salt derivation using SHA-256
- Fix inconsistent percentage rollout calculations (standardize to 0-99 range)
- Add getConfigDetails method for secure configuration retrieval
- Mask encrypted values in single configuration endpoint for consistency
- Ensure all percentage calculations use same range and logic

@respp respp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work @akintewe , you’ve implemented a very complete and well-structured system. Just a few minor adjustments are needed before it can be merged: standardize the percentage rollout calculation in both methods, and remove the PR_DESCRIPTION.md file from the repository, as it shouldn’t be included in the merge. The rest of the code is well-executed and fully meets the issue requirements. As a final suggestion, I recommend revisiting your commit messages—it's best to use more descriptive names that reflect the actual changes made, since when reviewing the commit history, what matters is not why coderabbit suggested the change, but what was actually modified or fixed.

…escription file

- Standardize percentage calculation in evaluateTargetingRules to use 'anonymous' fallback like evaluateFeatureFlag
- Ensure consistent variable naming (userPercentage) across both methods
- Remove PR_DESCRIPTION.md from repository as requested by maintainer
- Both methods now use identical 0-99 range and < comparison logic
@akintewe akintewe requested a review from respp August 2, 2025 11:59
@akintewe

akintewe commented Aug 2, 2025

Copy link
Copy Markdown
Contributor Author

Excellent work @akintewe , you’ve implemented a very complete and well-structured system. Just a few minor adjustments are needed before it can be merged: standardize the percentage rollout calculation in both methods, and remove the PR_DESCRIPTION.md file from the repository, as it shouldn’t be included in the merge. The rest of the code is well-executed and fully meets the issue requirements. As a final suggestion, I recommend revisiting your commit messages—it's best to use more descriptive names that reflect the actual changes made, since when reviewing the commit history, what matters is not why coderabbit suggested the change, but what was actually modified or fixed.

Thank you so much for the feedback, i will make the fix.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
src/services/ConfigurationService.ts (1)

47-53: Security concern: Hardcoded default encryption key

Using a hardcoded default encryption key is a security risk. The application should fail to start if the encryption key is not properly configured.

-    this.encryptionKey = process.env.CONFIG_ENCRYPTION_KEY || "default-encryption-key";
+    if (!process.env.CONFIG_ENCRYPTION_KEY) {
+      throw new Error("CONFIG_ENCRYPTION_KEY environment variable is required");
+    }
+    this.encryptionKey = process.env.CONFIG_ENCRYPTION_KEY;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 849e3df and cba85fe.

📒 Files selected for processing (1)
  • src/services/ConfigurationService.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/services/ConfigurationService.ts (1)
src/services/AuditService.ts (1)
  • AuditService (34-170)
🔇 Additional comments (2)
src/services/ConfigurationService.ts (2)

579-588: Good implementation of secure key derivation

The encryption implementation properly uses a deterministic salt with key derivation, addressing the previous security concern.


565-566: Incorrect handling of ENCRYPTED configuration type

The ENCRYPTED type case is calling decryptValue, but this seems incorrect. The type indicates the value should remain encrypted, not be decrypted during parsing.

       case ConfigurationType.ENCRYPTED:
-        return this.decryptValue(value);
+        // ENCRYPTED type should return the encrypted value as-is
+        return value;

Likely an incorrect or invalid review comment.

Comment thread src/services/ConfigurationService.ts Outdated
Comment thread src/services/ConfigurationService.ts Outdated
Comment thread src/services/ConfigurationService.ts Outdated
Comment thread src/services/ConfigurationService.ts Outdated
…n service

- Add safeJsonParse method with error handling to prevent crashes from malformed JSON
- Replace all JSON.parse calls with safeJsonParse for validationRules, allowedValues, and metadata
- Fix hash calculation inconsistency in evaluateTargetingRules to use 'targeting:userId' prefix
- Ensure consistent percentage rollout behavior across all evaluation methods
- Add proper error logging for JSON parsing failures with fallback defaults

@MPSxDev MPSxDev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your work, please resolve the issues with these files. @akintewe configurationMiddleware.ts, ConfigurationService.ts ConfigurationService.test.ts

image image image

- Remove unused import statements in controllers, tests, and type definitions
- Replace 'any' types with proper TypeScript types for better type safety
- Fix Repository import missing in ConfigurationService.test.ts
- Remove namespace declaration from configurationMiddleware (moved to express.d.ts)
- Ensure all tests use proper typing with Partial<Repository<T>> instead of any
- Maintain backward compatibility while improving code quality

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/tests/integration/configurationIntegration.test.ts (1)

20-23: Generate proper authentication tokens for tests instead of using hardcoded values.

The hardcoded auth token "test-auth-token" bypasses actual authentication testing. Consider generating real JWT tokens or mocking the auth middleware properly to ensure authentication is correctly tested.

src/services/ConfigurationService.ts (1)

46-52: Security concern: Hardcoded default encryption key

Using a hardcoded default encryption key is a security risk. The application should fail to start if the encryption key is not properly configured.

-    this.encryptionKey = process.env.CONFIG_ENCRYPTION_KEY || "default-encryption-key";
+    if (!process.env.CONFIG_ENCRYPTION_KEY) {
+      throw new Error("CONFIG_ENCRYPTION_KEY environment variable is required");
+    }
+    this.encryptionKey = process.env.CONFIG_ENCRYPTION_KEY;
🧹 Nitpick comments (2)
src/tests/integration/configurationIntegration.test.ts (1)

157-213: Add test coverage for merchant-based targeting and scheduled feature flags.

While the new tests for percentage rollouts and role-based targeting are good additions, the test suite is still missing coverage for:

  • Merchant-based targeting
  • Scheduled feature flags with start/end dates

Add these test cases to ensure complete coverage:

+    it("should handle merchant-based targeting", async () => {
+      await request(app)
+        .post("/api/config/feature-flags")
+        .set("Authorization", `Bearer ${authToken}`)
+        .send({
+          name: "merchant_feature",
+          description: "Merchant-based feature",
+          isEnabled: true,
+          scope: "merchant",
+          targetingRules: {
+            merchantIds: ["merchant1", "merchant2"],
+          },
+        });
+
+      const matchResponse = await request(app)
+        .get("/api/config/feature-flags/merchant_feature/evaluate?merchantId=merchant1")
+        .set("Authorization", `Bearer ${authToken}`);
+      expect(matchResponse.body.data.isEnabled).toBe(true);
+
+      const noMatchResponse = await request(app)
+        .get("/api/config/feature-flags/merchant_feature/evaluate?merchantId=merchant3")
+        .set("Authorization", `Bearer ${authToken}`);
+      expect(noMatchResponse.body.data.isEnabled).toBe(false);
+    });
+
+    it("should handle scheduled feature flags", async () => {
+      const now = new Date();
+      const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); // Tomorrow
+      const pastDate = new Date(now.getTime() - 24 * 60 * 60 * 1000); // Yesterday
+
+      await request(app)
+        .post("/api/config/feature-flags")
+        .set("Authorization", `Bearer ${authToken}`)
+        .send({
+          name: "scheduled_feature",
+          description: "Scheduled feature",
+          isEnabled: true,
+          scope: "global",
+          scheduledStartDate: futureDate.toISOString(),
+        });
+
+      const notStartedResponse = await request(app)
+        .get("/api/config/feature-flags/scheduled_feature/evaluate")
+        .set("Authorization", `Bearer ${authToken}`);
+      expect(notStartedResponse.body.data.isEnabled).toBe(false);
+      expect(notStartedResponse.body.data.reason).toContain("not yet scheduled");
+
+      // Test expired flag
+      await request(app)
+        .post("/api/config/feature-flags")
+        .set("Authorization", `Bearer ${authToken}`)
+        .send({
+          name: "expired_feature",
+          description: "Expired feature",
+          isEnabled: true,
+          scope: "global",
+          scheduledEndDate: pastDate.toISOString(),
+        });
+
+      const expiredResponse = await request(app)
+        .get("/api/config/feature-flags/expired_feature/evaluate")
+        .set("Authorization", `Bearer ${authToken}`);
+      expect(expiredResponse.body.data.isEnabled).toBe(false);
+      expect(expiredResponse.body.data.reason).toContain("expired");
+    });

Also applies to: 399-450

src/controllers/ConfigurationController.ts (1)

403-406: Avoid logging full error objects that may contain sensitive information.

The error logging at line 404 logs the entire error object, which might contain sensitive configuration values or system information.

Log only the error message instead of the full error object:

-          logger.error(`Failed to import configuration ${config.key}:`, error);
+          logger.error(`Failed to import configuration ${config.key}: ${error instanceof Error ? error.message : 'Unknown error'}`);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37e6aeb and a29d384.

📒 Files selected for processing (6)
  • src/controllers/ConfigurationController.ts (1 hunks)
  • src/middlewares/configurationMiddleware.ts (1 hunks)
  • src/services/ConfigurationService.ts (1 hunks)
  • src/tests/integration/configurationIntegration.test.ts (1 hunks)
  • src/tests/services/ConfigurationService.test.ts (1 hunks)
  • src/types/express.d.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/tests/services/ConfigurationService.test.ts
  • src/types/express.d.ts
  • src/middlewares/configurationMiddleware.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/tests/integration/configurationIntegration.test.ts (2)
src/services/ConfigurationService.ts (1)
  • configurationService (665-665)
src/lib/services/referral-service.ts (1)
  • request (25-68)
src/controllers/ConfigurationController.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (665-665)

Comment thread src/services/ConfigurationService.ts Outdated
Comment thread src/services/ConfigurationService.ts
- Add error handling to JSON parsing in parseValue method for ConfigurationType.JSON
- Fix hash calculation consistency by passing flagName to evaluateTargetingRules
- Ensure percentage rollout uses same hash format across all evaluation methods
- Add proper TypeScript types for safeJsonParse method with generic constraints
- Fix import path for Wallet entity in database configuration
- Resolve type assertion issues in AuditService for Express request extensions
- Maintain backward compatibility while improving error handling and type safety

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a29d384 and 1406aca.

📒 Files selected for processing (3)
  • src/config/db.ts (2 hunks)
  • src/services/AuditService.ts (2 hunks)
  • src/services/ConfigurationService.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/config/db.ts
  • src/services/ConfigurationService.ts
🔇 Additional comments (2)
src/services/AuditService.ts (2)

4-5: LGTM! Proper import and type organization.

The Express Request import is necessary for the type casting improvements, and the comment correctly indicates that request interface extensions are handled in the dedicated type definition file.


161-167: Excellent type safety improvements.

The type casting approach with optional chaining provides robust access to extended request properties while maintaining type safety. Converting the user ID to string is appropriate for the audit context requirements.

Comment thread src/services/AuditService.ts Outdated
- Replace deprecated req.connection.remoteAddress with req.socket.remoteAddress
- Add support for proxy headers (x-forwarded-for, x-real-ip)
- Implement proper fallback chain for reliable IP detection in various deployment scenarios
- Handle comma-separated IPs in x-forwarded-for header by extracting first IP
- Maintain backward compatibility while improving production reliability
@akintewe akintewe requested a review from MPSxDev August 3, 2025 10:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
src/controllers/ConfigurationController.ts (1)

43-69: LGTM: Security issue resolved.

The method now properly uses getConfigDetails and masks encrypted values, addressing the security concern raised in previous reviews. The implementation is consistent with other methods.

src/tests/integration/configurationIntegration.test.ts (1)

20-23: Generate proper authentication tokens for tests instead of using hardcoded values.

The hardcoded auth token bypasses actual authentication testing and should be replaced with proper JWT token generation or auth middleware mocking.

src/scripts/initializeConfigurations.ts (3)

42-49: LGTM: Security issue resolved with environment variables.

The sensitive configurations now properly load from environment variables, addressing the security concerns from previous reviews. This prevents hardcoded secrets from being exposed in version control.


196-211: Handle required sensitive configurations consistently.

SMTP credentials are marked as required but have empty values, which will fail validation. Consider making them optional for initial setup or providing environment-based defaults.


399-465: Don't initialize all environments by default - this is dangerous for production.

The script initializes configurations for all environments including production, which could accidentally overwrite production settings. Consider targeting only the intended environment.

🧹 Nitpick comments (2)
src/controllers/ConfigurationController.ts (2)

74-130: Consider using appropriate HTTP status codes for create vs update operations.

The method always returns 201 (Created) even when updating existing configurations. Consider differentiating between creates and updates for better REST semantics.

-      res.status(201).json({
+      const existingConfig = await configurationService.getConfig(key);
+      const statusCode = existingConfig === null ? 201 : 200;
+      
+      res.status(statusCode).json({
         success: true,
-        message: "Configuration updated successfully",
+        message: existingConfig === null ? "Configuration created successfully" : "Configuration updated successfully",
         data: {
           ...config,
           value: isEncrypted ? "[ENCRYPTED]" : config.value,
         },
       });

273-330: Consider using appropriate HTTP status codes for create vs update operations.

Similar to setConfiguration, this method always returns 201 even for updates. Consider differentiating between creates and updates for better REST semantics.

-      res.status(201).json({
+      const existingFlag = await configurationService.getFeatureFlag(name);
+      const statusCode = existingFlag ? 200 : 201;
+      
+      res.status(statusCode).json({
         success: true,
-        message: "Feature flag updated successfully",
+        message: existingFlag ? "Feature flag updated successfully" : "Feature flag created successfully",
         data: flag,
       });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b5595b and ee2b296.

📒 Files selected for processing (13)
  • src/app.ts (3 hunks)
  • src/controllers/ConfigurationController.ts (1 hunks)
  • src/entities/Configuration.ts (1 hunks)
  • src/entities/FeatureFlag.ts (1 hunks)
  • src/middlewares/configurationMiddleware.ts (1 hunks)
  • src/routes/configurationRoutes.ts (1 hunks)
  • src/scripts/initializeConfigurations.ts (1 hunks)
  • src/scripts/testConfigurationSystem.ts (1 hunks)
  • src/services/AuditService.ts (2 hunks)
  • src/services/ConfigurationService.ts (1 hunks)
  • src/tests/integration/configurationIntegration.test.ts (1 hunks)
  • src/tests/services/ConfigurationService.test.ts (1 hunks)
  • src/types/express.d.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/app.ts
  • src/scripts/testConfigurationSystem.ts
  • src/services/AuditService.ts
  • src/middlewares/configurationMiddleware.ts
  • src/tests/services/ConfigurationService.test.ts
  • src/types/express.d.ts
  • src/routes/configurationRoutes.ts
  • src/entities/Configuration.ts
  • src/entities/FeatureFlag.ts
  • src/services/ConfigurationService.ts
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/scripts/initializeConfigurations.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (780-780)
src/tests/integration/configurationIntegration.test.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (780-780)
src/controllers/ConfigurationController.ts (1)
src/services/ConfigurationService.ts (1)
  • configurationService (780-780)
🔇 Additional comments (13)
src/controllers/ConfigurationController.ts (10)

16-38: LGTM: Proper security handling for encrypted configurations.

The method correctly masks encrypted values before returning them to the client, maintaining security while providing useful metadata. The response structure is consistent and includes a helpful count field.


135-152: LGTM: Clean delete implementation with audit support.

The method properly handles the delete operation and includes user identification for audit trails.


157-191: LGTM: Proper input validation and security handling.

The method correctly validates the category parameter against allowed values and maintains consistent security practices by masking encrypted values.


196-211: LGTM: Supports hot-reload functionality.

The method provides the hot-reload capability mentioned in the PR objectives, allowing configuration updates without server restarts.


216-245: LGTM: Comprehensive configuration validation.

The method properly validates required configurations and provides detailed feedback about missing or empty values, which aligns with the startup validation requirements mentioned in the PR objectives.


252-268: LGTM: Consistent implementation pattern.

The method follows the same response structure pattern as configuration methods, maintaining API consistency.


335-360: LGTM: Proper feature flag evaluation with context.

The method correctly passes evaluation context (userId, merchantId, userRole) to the service, enabling targeted feature flag functionality as described in the PR objectives.


365-405: LGTM: Comprehensive statistics for monitoring.

The method provides valuable insights into the configuration system, supporting the observability goals mentioned in the PR objectives. The aggregation logic is correct and efficient.


410-447: LGTM: Secure configuration export functionality.

The method properly masks encrypted values in exports and sets appropriate headers for file download. The export format includes useful metadata like timestamp and environment.


452-512: LGTM: Robust batch import with proper error handling.

The method handles batch imports gracefully, continuing processing even when individual configurations fail. The statistics tracking (imported, skipped, errors) provides valuable feedback about the import operation.

src/tests/integration/configurationIntegration.test.ts (3)

38-156: LGTM: Comprehensive basic configuration API testing.

The test cases cover essential CRUD operations, security handling for encrypted configurations, category filtering, and deletion. The assertions are appropriate and verify both status codes and response data.


158-214: LGTM: Basic feature flag testing with targeted rules.

The tests cover basic feature flag functionality and user-targeted rules. The additional advanced targeting tests at the end of the file (percentage rollouts, role-based targeting) provide comprehensive coverage.


367-470: LGTM: Advanced test scenarios address previous feedback.

These test cases successfully address the missing scenarios from previous reviews, including configuration updates, unauthorized access handling, type validation, and advanced feature flag targeting (percentage rollouts, role-based targeting). The test coverage is now comprehensive.

respp
respp previously approved these changes Aug 4, 2025

@respp respp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @akintewe !

@respp respp removed the request for review from MPSxDev August 4, 2025 01:06
@akintewe akintewe requested review from MPSxDev and respp August 4, 2025 08:53
@akintewe akintewe requested a review from respp August 9, 2025 08:23
@akintewe

Copy link
Copy Markdown
Contributor Author

@respp please any response on my pr?

@MPSxDev MPSxDev merged commit f63dd29 into PayStell:main Aug 27, 2025
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi-Environment Configuration Management System

3 participants