1- App ``provides `` for Inter-App Data
2- ####################################
1+ App ``provides `` for Inter-App Configuration
2+ ############################################
33
44Status
55======
@@ -11,15 +11,15 @@ Context
1111=======
1212
1313frontend-base applications currently communicate through two structured
14- mechanisms: ``routes `` and ``slots ``. Both are defined in the `` App `` interface
15- and consumed directly by frontend-base's runtime.
14+ mechanisms: ``routes ``, `` slots ``, and ``providers ``. All are defined in the
15+ `` App `` interface and consumed directly by frontend-base's runtime.
1616
17- As the platform evolves, however, situations arise where apps need to share data
18- with each other that frontend-base itself has no reason to understand. A
19- concrete example is the course navigation bar introduced in the header app.
20- The header needs to know two things from other apps:
17+ As the platform evolves, however, situations arise where apps need to share
18+ configuration data with each other that frontend-base itself has no reason to
19+ understand. A concrete example is the course navigation bar introduced in the
20+ header app. The header needs to know two things from other apps:
2121
22- 1. Which apps want the course navigation bar to appear (currently a hardcoded
22+ 1. Which apps want the course navigation bar to appear (previously a hardcoded
2323 list of roles in ``constants.ts ``).
2424
25252. Which URL patterns each app handles client-side, so the navigation bar can
@@ -36,8 +36,8 @@ runtime needs to interpret them directly. It builds a router from ``routes``
3636and renders widgets from ``slots ``. Any new field that frontend-base itself
3737must consume deserves the same treatment: a dedicated, typed field.
3838
39- But for data that flows between apps - where frontend-base is just the conduit -
40- a generic mechanism is more appropriate.
39+ But for generic configuration between apps - where frontend-base is just the
40+ conduit - a generic mechanism is more appropriate.
4141
4242
4343Decision
@@ -55,25 +55,23 @@ Add an optional ``provides`` field to the ``App`` interface::
5555 provides?: Record<string, unknown>,
5656 }
5757
58- ``provides `` is a flat key-value map where each key is an identifier agreed
59- upon by the providing and consuming apps, and the value is whatever the
60- consumer expects. frontend-base stores this data and exposes it through a
61- runtime function, but does not interpret it. Any namespaced identifier can
62- serve as a key.
58+ ``provides `` is a flat key-value map where each key is a namespaced identifier
59+ agreed upon by the providing and consuming apps, and the value takes whatever
60+ shape the consuming app expects. The runtime stores this data and exposes it
61+ through a runtime function, but does not interpret it.
6362
6463A runtime helper would look something like::
6564
66- // Returns all `provides` entries matching the given key .
67- function getProvidedData(key : string): unknown[]
65+ // Returns all `provides` entries matching the given identifier .
66+ function getProvides(id : string): unknown[]
6867
6968
7069Guidelines
7170==========
7271
73- 1. ``provides `` is for inter-app data that frontend-base does not need to
74- interpret. If frontend-base's runtime must consume the data to function
75- (as it does with routes and slots), a dedicated typed field on ``App `` is
76- the right choice.
72+ 1. ``provides `` is for inter-app configuration that the runtime does not need
73+ to interpret. If it must consume the data to function (as it does with
74+ routes and slots), a dedicated typed field on ``App `` is the right choice.
7775
78762. Keys in ``provides `` should be their own namespaced identifiers, not
7977 duplicates of existing app, slot, or widget IDs. This allows different
@@ -84,8 +82,8 @@ Guidelines
8482 consuming apps. It is not enforced by frontend-base. Consuming apps should
8583 validate or type-guard the data they receive.
8684
87- 4. ``provides `` should not be used as a back door to modify frontend-base 's
88- behavior. It is not a configuration mechanism for the runtime.
85+ 4. ``provides `` should not be used as a back door to modify the runtime 's
86+ behavior. It is not a configuration mechanism for the runtime itself .
8987
9088
9189Consequences
@@ -107,28 +105,29 @@ Course navigation bar example
107105As a concrete illustration, the Instructor Dashboard app could declare::
108106
109107 const config: App = {
110- appId: 'org.openedx.frontend.app.instructor ',
108+ appId: 'org.openedx.frontend.app.instructorDashboard ',
111109 provides: {
112- 'org.openedx.frontend.provides.courseNavigationRoles.v1': {
113- courseNavigationRoles: [ 'org.openedx.frontend.role.instructor'] ,
114- } ,
110+ 'org.openedx.frontend.provides.courseNavigationRoles.v1': [
111+ 'org.openedx.frontend.role.instructorDashboard' ,
112+ ] ,
115113 },
116114 routes: [...],
117115 slots: [...],
118116 };
119117
120118The header's course navigation bar widget collects ``provides `` entries keyed
121- to its provides identifier from all registered apps. From the provided roles
122- it determines both when to render the navigation bar (by checking
123- ``getActiveRoles() ``) and which tab URLs can be navigated client-side (by
124- resolving roles to route paths via ``getUrlByRouteRole() ``).
119+ to the course navigation roles identifier from all registered apps. It expects
120+ the provided values to be role identifiers, from which it determines both when
121+ to render the navigation bar (by checking ``getActiveRoles() ``) and which tab
122+ URLs can be navigated client-side (by resolving roles to route paths via
123+ ``getUrlByRouteRole() ``).
125124
126125
127126Rejected alternatives
128127=====================
129128
130- Slot operations
131- ---------------
129+ Widget operations
130+ -----------------
132131
133132Each app could register its own widget into the course navigation bar slot
134133with an ``active `` condition on its role. The ``OPTIONS `` operation can even
@@ -157,3 +156,15 @@ with no standard way to discover them. Providers are the right tool when data
157156changes over time and consumers need to re-render. The course navigation roles
158157are fixed at registration time and never change, making ``provides `` a more
159158natural fit.
159+
160+ Reusing ``App.config ``
161+ ----------------------
162+
163+ The existing ``App.config `` field has the same type (``Record<string, unknown> ``)
164+ and could theoretically hold provided data. However, ``config `` is per-app: it
165+ is retrieved by ``appId `` via ``getAppConfig() `` and is meant to hold settings
166+ *for * that app. ``provides `` has a cross-app access pattern:
167+ ``getProvides() `` collects entries from all apps that declared data under a
168+ given identifier. Merging the two would require scanning every app's config
169+ for a specific key, blurring the distinction between settings an app consumes
170+ and data it exposes for others.
0 commit comments