Skip to main content
Synced from the repo — do not edit here

Canonical source: CLINIC_MODULARIZATION_GUIDE.md. This page is generated by docs/scripts/sync-handbook.mjs. Edit the source file in the repo; changes appear here on the next build.

Clinic Modularization Guide

This guide explains how to configure different features for different clinics in the Basis Health platform.

Overview

The clinic modularization system allows you to enable or disable specific features for individual clinics. This is achieved through a ClinicFeatureFlags model that controls which features are available for each clinic.

Implementation Details

1. Feature Flags Model

The ClinicFeatureFlags model includes the following flags:

  • chatEnabled: Controls whether the chat feature is available
  • marketplaceEnabled: Controls marketplace access
  • protocolsEnabled: Controls protocol features
  • terraIntegrationEnabled: Controls Terra health data integration
  • videoCallsEnabled: Controls video call functionality
  • wellnessAssessmentEnabled: Controls wellness assessment features
  • supplementsEnabled: Controls supplement recommendations

2. Files Modified

Dart/Flutter Files:

  • hybrid/basiscore/lib/src/models/clinic.dart - Added ClinicFeatureFlags model and integrated it into ClinicDetails
  • hybrid/basisflow/lib/routes/route_main.dart - Implemented chat visibility check based on feature flag

Python Backend Files:

  • basis-functions/functions/src/model_clinic.py - Added ClinicFeatureFlags model
  • basis-functions/functions/src/functions_clinic.py - Added feature flags support to UpdateClinicRequest

Protocol Buffer Files:

  • proto-models/models/mclinic.proto - Added ClinicFeatureFlags message definition

3. Example: Chat Feature Toggle

The chat floating action button in the main container now checks the chatEnabled flag:

floatingActionButton: serviceChat == null ? null : StreamBuilder<String?>(
stream: serviceClinic.stream,
initialData: serviceClinic.clinic,
builder: (context, clinicIdSnapshot) {
final clinicId = clinicIdSnapshot.data;
if (clinicId == null) return const SizedBox.shrink();

return StreamBuilder<ClinicDetails?>(
stream: serviceClinicStorage.watchClinicDetails(clinicId),
builder: (context, clinicSnapshot) {
// Check if chat is enabled for this clinic
final chatEnabled = clinicSnapshot.data?.featureFlags.chatEnabled ?? true;
if (!chatEnabled) return const SizedBox.shrink();

return FloatingActionButton(
onPressed: () => EnhancedChatDrawerContent.open(context),
child: const Icon(Icons.message)
);
}
);
}
),

How to Use

Updating Feature Flags

Use the provided test script to update feature flags for a clinic:

cd basis-functions/functions/test
python test_clinic_feature_flags.py

Remember to update the clinic_id in the script with your actual clinic ID.

Programmatically Updating Flags

from src.functions_clinic import UpdateClinicRequest, update_clinic
from src.model_clinic import ClinicFeatureFlags
from src.model import PermissionAuthorUser

# Update feature flags for a clinic
update_request = UpdateClinicRequest(
clinic_id="your-clinic-id",
feature_flags=ClinicFeatureFlags(
chatEnabled=False, # Disable chat
marketplaceEnabled=True,
protocolsEnabled=True,
terraIntegrationEnabled=True,
videoCallsEnabled=True,
wellnessAssessmentEnabled=True,
supplementsEnabled=True
)
)

by = PermissionAuthorUser(uid="admin-user-id")
updated_clinic = update_clinic(update_request, by=by)

Extending the System

Adding New Feature Flags

  1. Update the Dart Model (hybrid/basiscore/lib/src/models/clinic.dart):

    final bool myNewFeatureEnabled;
  2. Update the Python Model (basis-functions/functions/src/model_clinic.py):

    myNewFeatureEnabled: bool = Field(True, description='Whether my new feature is enabled')
  3. Update the Proto File (proto-models/models/mclinic.proto):

    bool myNewFeatureEnabled = 8;
  4. Implement Feature Check in your UI code:

    final myFeatureEnabled = clinic?.featureFlags.myNewFeatureEnabled ?? true;
    if (!myFeatureEnabled) return const SizedBox.shrink();

Hiding Navigation Menu Items

To hide navigation menu items based on feature flags, you can modify the navigation generation code. For example:

// In your navigation menu builder
if (clinic?.featureFlags.marketplaceEnabled ?? true) {
navigationItems.add(MarketplaceMenuItem());
}

if (clinic?.featureFlags.protocolsEnabled ?? true) {
navigationItems.add(ProtocolsMenuItem());
}

Settings Modularization

You can also conditionally show/hide settings based on feature flags:

// In your settings page
if (clinic?.featureFlags.terraIntegrationEnabled ?? true) {
settingsSections.add(TerraIntegrationSettings());
}

Best Practices

  1. Default to Enabled: When accessing feature flags, default to true if the flag is not set. This ensures backward compatibility.

  2. Granular Control: Create specific feature flags for each major feature rather than grouping multiple features under one flag.

  3. Permission Checks: Ensure that only authorized users (clinic admins) can update feature flags.

  4. Cache Considerations: The clinic details are watched via streams, so changes will be reflected in real-time. However, consider caching strategies for performance.

  5. Testing: Always test feature flag changes in a development environment before applying to production clinics.

Future Enhancements

  1. Feature Tiers: Implement different tiers (Basic, Pro, Enterprise) that automatically set feature flags.

  2. Feature Dependencies: Implement logic to handle feature dependencies (e.g., video calls might require chat to be enabled).

  3. UI for Flag Management: Create an admin interface for managing feature flags without code changes.

  4. Analytics: Track feature usage to make informed decisions about which features to enable/disable.

  5. A/B Testing: Use feature flags for A/B testing new features with specific clinics.