Skip to content

Commit 670d2d2

Browse files
feat(feature-flag): add declarative feature flag catalog and schema (#11345)
2 parents 353dc23 + 22c77a2 commit 670d2d2

5 files changed

Lines changed: 207 additions & 3 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
{
2+
"$schema": "thunderbird_mobile_featureflag.schema.json",
3+
"version": "2026-07-30.1",
4+
"flags": [
5+
{
6+
"key": "archive_marks_as_read",
7+
"default": true,
8+
"description": "Marks message as read when archived."
9+
},
10+
{
11+
"key": "disable_font_size_config",
12+
"default": true,
13+
"description": "Disables legacy font-size configuration UI."
14+
},
15+
{
16+
"key": "email_notification_default",
17+
"default": true,
18+
"description": "Default email-notification behaviour for new accounts."
19+
},
20+
{
21+
"key": "display_in_app_notifications",
22+
"default": false,
23+
"description": "Enables in-app notifications."
24+
},
25+
{
26+
"key": "use_notification_sender_for_system_notifications",
27+
"default": false,
28+
"description": "Uses NotificationSender for system notifications instead of the legacy controller."
29+
},
30+
{
31+
"key": "use_compose_for_message_list_items",
32+
"default": false,
33+
"description": "Renders the legacy message-list items using Jetpack Compose."
34+
},
35+
{
36+
"key": "message_view_action_export_eml",
37+
"default": false,
38+
"description": "Adds the 'Export EML' message action."
39+
},
40+
{
41+
"key": "enable_avatar_customization",
42+
"default": true,
43+
"description": "Enables avatar customization in account settings."
44+
},
45+
{
46+
"key": "use_new_message_reader_css_styles",
47+
"default": true,
48+
"description": "Uses new message-reader CSS styles.",
49+
"time_to_promote": "2026-12-31"
50+
},
51+
{
52+
"key": "enable_message_list_new_state",
53+
"default": false,
54+
"description": "Enables the new message-list state."
55+
},
56+
{
57+
"key": "use_compose_for_message_reader",
58+
"default": false,
59+
"description": "Renders the message reader using Jetpack Compose."
60+
},
61+
{
62+
"key": "thundermail_onboarding_enabled",
63+
"default": true,
64+
"description": "Enables Thundermail onboarding flow.",
65+
"time_to_promote": "2026-12-31"
66+
}
67+
],
68+
"overrides": {
69+
"thunderbird": {
70+
"debug": {
71+
"display_in_app_notifications": true,
72+
"use_notification_sender_for_system_notifications": true,
73+
"message_view_action_export_eml": true
74+
},
75+
"daily": {
76+
"display_in_app_notifications": true,
77+
"message_view_action_export_eml": true
78+
},
79+
"beta": {
80+
"display_in_app_notifications": true
81+
},
82+
"release": {}
83+
},
84+
"k9": {
85+
"debug": {
86+
"display_in_app_notifications": true,
87+
"use_notification_sender_for_system_notifications": true,
88+
"message_view_action_export_eml": true
89+
},
90+
"release": {}
91+
}
92+
}
93+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"$id": "https://www.thunderbird.net/mobile.featureflag.schema.json",
4+
"title": "Thunderbird Mobile Feature Flag Catalog",
5+
"description": "Single source of truth for feature flags in Thunderbird and K-9 Mail: the authored flag registry, the codegen input, and the offline defaults bundled with the app.",
6+
"type": "object",
7+
"additionalProperties": false,
8+
"required": [
9+
"version",
10+
"flags",
11+
"overrides"
12+
],
13+
"properties": {
14+
"$schema": {
15+
"type": "string",
16+
"description": "Optional self-reference so editors can resolve this schema (e.g. 'thunderbird_mobile_featureflag.schema.json')."
17+
},
18+
"version": {
19+
"type": "string",
20+
"description": "Catalog version; used for the offline 'needs update' / staleness fallback."
21+
},
22+
"flags": {
23+
"type": "array",
24+
"description": "The flag registry: identity, codegen target, and baseline value. One entry per flag.",
25+
"uniqueItems": true,
26+
"items": {
27+
"type": "object",
28+
"additionalProperties": false,
29+
"required": [
30+
"key",
31+
"default"
32+
],
33+
"properties": {
34+
"key": {
35+
"type": "string",
36+
"pattern": "^[a-z0-9_]+$"
37+
},
38+
"description": {
39+
"type": "string",
40+
"description": "The human description of the given feature flag. This will be displayed in the Secret Debug Settings"
41+
},
42+
"type": {
43+
"enum": [
44+
"boolean"
45+
],
46+
"default": "boolean",
47+
"description": "Boolean only for now; the online provider may serve richer types later. To support multivariate, widen this enum and let 'default' accept the non-boolean value (or a variant key)."
48+
},
49+
"default": {
50+
"type": "boolean",
51+
"description": "Baseline value used offline and whenever no per-variant override applies. Promoting a flag = set this true and drop its overrides."
52+
},
53+
"time_to_promote": {
54+
"type": "string",
55+
"format": "date",
56+
"description": "Target date to graduate or remove the flag (lifecycle hygiene)."
57+
}
58+
}
59+
}
60+
},
61+
"overrides": {
62+
"type": "object",
63+
"description": "Offline default snapshot. Per app, per build types, ONLY the flag keys whose value differs from the flag's 'default'. An absent/empty build type means every flag takes its 'default'. The bundled (offline) provider serves: flag.default MERGED WITH the matching app/build type override. (Keys here must exist in 'flags' — enforced by the codegen/validation tool.)",
64+
"additionalProperties": false,
65+
"properties": {
66+
"thunderbird": {
67+
"type": "object",
68+
"additionalProperties": false,
69+
"properties": {
70+
"debug": {
71+
"$ref": "#/definitions/overrideMap"
72+
},
73+
"daily": {
74+
"$ref": "#/definitions/overrideMap"
75+
},
76+
"beta": {
77+
"$ref": "#/definitions/overrideMap"
78+
},
79+
"release": {
80+
"$ref": "#/definitions/overrideMap"
81+
}
82+
}
83+
},
84+
"k9": {
85+
"type": "object",
86+
"additionalProperties": false,
87+
"properties": {
88+
"debug": {
89+
"$ref": "#/definitions/overrideMap"
90+
},
91+
"release": {
92+
"$ref": "#/definitions/overrideMap"
93+
}
94+
}
95+
}
96+
}
97+
}
98+
},
99+
"definitions": {
100+
"overrideMap": {
101+
"type": "object",
102+
"description": "flagKey -> boolean override (value differs from the flag's 'default').",
103+
"patternProperties": {
104+
"^[a-z0-9_]+$": {
105+
"type": "boolean"
106+
}
107+
},
108+
"additionalProperties": false
109+
}
110+
}
111+
}

docs/SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ generator, in this case, **mdbook**. It defines the structure and navigation of
6262
- [Technical Designs](engineering/technical-designs/README.md)
6363
- [Template](engineering/technical-designs/0000-technical-design-template.md)
6464
- [Proposed]()
65-
- [0002: Declarative Feature Flag Catalog](engineering/technical-designs/0002-feature-flag-declarative-catalog.md)
6665
- [Accepted]()
6766
- [0001 - Changelog System Replacement](engineering/technical-designs/0001-changelog-system-replacement.md)
67+
- [0002: Declarative Feature Flag Catalog](engineering/technical-designs/0002-feature-flag-declarative-catalog.md)
6868
- [Rejected]()
6969
- [Obsolete]()
7070
- [User Guide]()

docs/engineering/rfcs/0004-feature-flag-new-architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ The catalog is local-only in this phase. It is packaged with the app and cannot
4949

5050
```json
5151
{
52-
"$schema": "featureflag.schema.lean.json",
52+
"$schema": "thunderbird_mobile_featureflag.schema.json",
5353
"version": "2026-06-18.1",
5454
"flags": [
5555
{

docs/engineering/technical-designs/0002-feature-flag-declarative-catalog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
- Issue: [#11252](https://github.com/thunderbird/thunderbird-android/issues/11252)
44
- RFC: [RFC 0004: Add a Declarative Feature Flag Catalog](../rfcs/0004-feature-flag-new-architecture.md)
5-
- Status: **Proposed**
5+
- Status: **Accepted**
66

77
## Summary
88

0 commit comments

Comments
 (0)