feat: Feature flag for relational tables (#10599)

# Which Problems Are Solved

This PR introduces a new feature flag `EnableRelationalTables` that will
be used in following implementations to decide whether Zitadel should
use the relational model or the event sourcing one.

# TODO

  - [x] Implement flag at system level
- [x] Display the flag on console:
https://github.com/zitadel/zitadel/pull/10615

# How the Problems Are Solved

  - Implement loading the flag from config
- Add persistence of the flag through gRPC endpoint
(SetInstanceFeatures)
- Implement reading of the flag through gRPC endpoint
(GetInstanceFeatures)

# Additional Changes

Some minor refactoring to remove un-needed generics annotations

# Additional Context

- Closes #10574

---------

Co-authored-by: Silvan <[email protected]>
This commit is contained in:
Marco A.
2025-09-02 09:48:46 +00:00
committed by GitHub
co-authored by Silvan
parent e3dff2482e
commit 75a67be669
46 changed files with 669 additions and 91 deletions
+1
View File
@@ -19,6 +19,7 @@ type InstanceFeatures struct {
LoginV2 FeatureSource[*feature.LoginV2]
PermissionCheckV2 FeatureSource[bool]
ConsoleUseV2UserApi FeatureSource[bool]
EnableRelationalTables FeatureSource[bool]
}
func (q *Queries) GetInstanceFeatures(ctx context.Context, cascade bool) (_ *InstanceFeatures, err error) {
@@ -72,11 +72,13 @@ func (m *InstanceFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceLoginVersion,
feature_v2.InstancePermissionCheckV2,
feature_v2.InstanceConsoleUseV2UserApi,
feature_v2.InstanceEnableRelationalTables,
).
Builder().ResourceOwner(m.ResourceOwner)
}
func (m *InstanceFeaturesReadModel) reduceReset() {
m.instance.EnableRelationalTables = FeatureSource[bool]{}
if m.populateFromSystem() {
return
}
@@ -126,6 +128,8 @@ func reduceInstanceFeatureSet[T any](features *InstanceFeatures, event *feature_
features.PermissionCheckV2.set(level, event.Value)
case feature.KeyConsoleUseV2UserApi:
features.ConsoleUseV2UserApi.set(level, event.Value)
case feature.KeyEnableRelationalTables:
features.EnableRelationalTables.set(level, event.Value)
}
return nil
}
@@ -104,6 +104,10 @@ func (*instanceFeatureProjection) Reducers() []handler.AggregateReducer {
Event: instance.InstanceRemovedEventType,
Reduce: reduceInstanceRemovedHelper(InstanceDomainInstanceIDCol),
},
{
Event: feature_v2.InstanceEnableRelationalTables,
Reduce: reduceInstanceSetFeature[bool],
},
},
}}
}
+1
View File
@@ -28,6 +28,7 @@ type SystemFeatures struct {
EnableBackChannelLogout FeatureSource[bool]
LoginV2 FeatureSource[*feature.LoginV2]
PermissionCheckV2 FeatureSource[bool]
EnableRelationalTables FeatureSource[bool]
}
func (q *Queries) GetSystemFeatures(ctx context.Context) (_ *SystemFeatures, err error) {
+3
View File
@@ -63,6 +63,7 @@ func (m *SystemFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemEnableBackChannelLogout,
feature_v2.SystemLoginVersion,
feature_v2.SystemPermissionCheckV2,
feature_v2.SystemEnableRelationalTables,
).
Builder().ResourceOwner(m.ResourceOwner)
}
@@ -96,6 +97,8 @@ func reduceSystemFeatureSet[T any](features *SystemFeatures, event *feature_v2.S
features.LoginV2.set(level, event.Value)
case feature.KeyPermissionCheckV2:
features.PermissionCheckV2.set(level, event.Value)
case feature.KeyEnableRelationalTables:
features.EnableRelationalTables.set(level, event.Value)
}
return nil
}
+8
View File
@@ -53,6 +53,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
context.Background(), aggregate,
feature_v2.SystemEnableRelationalTables, false,
)),
),
),
want: &SystemFeatures{
@@ -67,6 +71,10 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
Level: feature.LevelSystem,
Value: false,
},
EnableRelationalTables: FeatureSource[bool]{
Level: feature.LevelSystem,
Value: false,
},
},
},
{