Describe the feature request
The polling endpoint GET /api/client/features computes its ETag using a revisionId that is scoped per-environment only and should be per project too:
// client-feature-toggle.controller.ts:296-304
async calculateMeta(query: IFeatureToggleQuery): Promise<IMeta> {
const revisionId =
await this.configurationRevisionService.getMaxRevisionId(
query.environment,
);
const queryHash = hashSum(query);
const etag = `"${queryHash}:${revisionId}:v1"`;
return { revisionId, etag, queryHash };
}
Background
ConfigurationRevisionService.getMaxRevisionId(environment) returns the maximum event ID across all projects for that environment. This means a feature change in project A invalidates the ETag for tokens scoped to project B, causing unnecessary cache busting and full payload re-fetches from Edge and SDKs.
In a multi-project instance with frequent changes, this produces a cascade of unnecessary 200 responses where 304s would suffice.
Solution suggestions
Make the revisionId used in ETag computation aware of the requesting token's project scope. When a token is scoped to specific projects, the ETag should only change when events occur in those projects (or in segments referenced by their features).
The delta/streaming system already implements this exact logic in visible-revision.ts:
EventStore.getDeltaRevisionState(environment) returns per-project revision maps (Map<string, number>)
getVisibleRevision(revisionState, projects, referencedSegmentIds) computes the max revision across only the relevant projects and segments
The same approach (or a similar one) could be applied to ConfigurationRevisionService.getMaxRevisionId() so the polling path benefits from project-scoped invalidation.
Describe the feature request
The polling endpoint
GET /api/client/featurescomputes its ETag using arevisionIdthat is scoped per-environment only and should be per project too:Background
ConfigurationRevisionService.getMaxRevisionId(environment)returns the maximum event ID across all projects for that environment. This means a feature change in project A invalidates the ETag for tokens scoped to project B, causing unnecessary cache busting and full payload re-fetches from Edge and SDKs.In a multi-project instance with frequent changes, this produces a cascade of unnecessary 200 responses where 304s would suffice.
Solution suggestions
Make the
revisionIdused in ETag computation aware of the requesting token's project scope. When a token is scoped to specific projects, the ETag should only change when events occur in those projects (or in segments referenced by their features).The delta/streaming system already implements this exact logic in
visible-revision.ts:EventStore.getDeltaRevisionState(environment)returns per-project revision maps (Map<string, number>)getVisibleRevision(revisionState, projects, referencedSegmentIds)computes the max revision across only the relevant projects and segmentsThe same approach (or a similar one) could be applied to
ConfigurationRevisionService.getMaxRevisionId()so the polling path benefits from project-scoped invalidation.