backstage / backstage

Backstage is an open framework for building developer portals
https://backstage.io/
Apache License 2.0
26.73k stars 5.52k forks source link

[RFC] Backstage notification API (frontend) #10652

Closed timbonicus closed 1 month ago

timbonicus commented 2 years ago

Status: Open for comments

Need

The need for a notification API is described and discussed at length in #639, so I won’t cover it here except to say that there are many types of notifications that could be useful in Backstage:

These all have slightly different requirements. Some may be a simple string message, others may want to display a custom component. Some may be applicable to every Backstage user, others may only apply to certain teams or individuals. A goal of the notification API is to be flexible enough for all of these use cases.

Proposal

Note: This proposal was prototyped in the mob/notapi branch.

A notification API should have both a frontend and backend — the backend accepts and stores notifications from other backends, and the frontend receives and displays notifications in appropriate places. As suggested in #639, this RFC focuses only on the frontend as a starting point, and leaves the backend parts to a future RFC author.

Notification API

We propose to adapt the AlertApi that already exists into a NotificationApi that supports richer payloads. The AlertApi has two methods — post to add alerts, and an Observable to which you can subscribe to watch alerts. The NotificationApi is exactly the same, with a more flexible payload.

export type NotificationApi = {
  post(notification: Notification): void;
  notification$(): Observable<Notification>;
};

The Notification type uses the Kubernetes object format, same as the software catalog, to provide a standard envelope with flexibility for extension.

export type Notification = {
  kind: string;
  metadata: {
    title: string;
    message: string;
    uuid: string;
    timestamp: Date;
    [key: string]: any;
  };
  spec?: {
    // Catalog entity that triggered the notification, if applicable
    originatingEntityRef?: EntityRef;
    // Target User/Group entity refs if the notification is not global.
    targetEntityRefs?: Array<EntityRef>;
    icon?:  string | JSX.Element; // System icon or custom
    actions?: Array<
      | { title: string; url: string; }
      | { title: string; callback: Function; }
    >;
  }
};

The metadata fields are a minimum structure for standard display of notifications, such as on a notification page for a given user.

The uuid can be used as a reference for future read receipts, or client-side operations like de-duplication - if the same notification is fired multiple times with different payload values (e.g. a progress percentage).

The targetEntityRefs field, for frontend purposes, is only informational so that a user knows why they received a notification. The frontend will not use this for filtering notifications, since notifications should only be delivered to the frontend when appropriate for the logged-in user. A notification backend would use this field for filtering based on the identity token.

The actions can be links, or callback functions (such as Retrigger build) that invoke a process.

Similar to catalog entities, this base envelope can be extended to provide additional fields:

export type AlertNotification = Notification & {
  kind: ‘alert’;
  metadata: {
    severity: ‘info’ | ‘error’ | ‘warning’ | ‘success’;
  }
}

// Certain kinds of notification may offer more flexible display
export type HomepageNotification = Notification & {
  kind: ‘home’;
  spec: {
    element?: JSX.Element;
  }
}

Notification channels

To allow frontend plugins to push notifications, we propose an addition to the createPlugin parameters such that plugins can provide channels of notifications. This is a temporary solution, giving frontend plugins flexibility on how to load notifications, until a notification-backend is in place.

export type PluginNotificationChannel = {
  name: string;
  initialize(notificationApi: NotificationApi): void;
};
export type PluginConfig = {
  id: string;
  apis?: Iterable<AnyApiFactory>;
  routes?: Routes;
  externalRoutes?: ExternalRoutes;
  featureFlags?: PluginFeatureFlagConfig[];
+  notificationChannels?: PluginNotificationChannel[];
};

These notification channels have an initialize method, called once on page load (by AppManager), that receives the notificationApi. The channel can decide how to load and post notifications (e.g. poll with setInterval, stream from an endpoint). Notification channels have a name so that the same channel is not registered twice, such as when different plugins want to include notifications from the same source.

Since these notification channels are loaded by the app frontend, notifications can only be received while the user is actively within Backstage. Plugin authors could work around this by storing a timestamp of the last check in browser storage, and fetching all messages since that time from a backend.

NotificationContext

As a poor-man’s stand-in for a notification-backend, we propose introducing a React Context to store notifications received from the NotificationApi since page load, and allow acknowledging notifications since a given timestamp.

Since Backstage is a single-page app, this context persists within a single browser session and makes notifications behave slightly as one might expect if a backend existed. I can receive notifications, go to a notification page to view them, later receive new notifications, and return to the notification page to see both new and old (but still within the same browser session) notifications.

This context could later be adapted as a central utility to call an actual notification-backend for similar operations.

Notification display

Many different components can subscribe to the NotificationApi. We propose that the Backstage app layer provide a few components out of the box that watch for certain kinds of notification.

System-wide banner

The existing AlertDisplay component will switch to the NotificationApi instead of AlertApi, and respond only to notifications where kind === 'alert'.

system-banner

Sidebar notification section

A notification area will be introduced into the sidebar and mobile layout. This will show a dot when any notifications applicable to the current user have arrived since the notifications page was last visited. Clicking on this goes to the notifications page.

notification-sidebar

User notifications page

A page to show a list of notifications applicable to the current user. For this frontend proposal, this would only show notifications that arrived since Backstage was loaded in the current browser session, unless the plugin author has worked around this limitation as mentioned earlier.

This will make use of the NotificationContext in the short term, to allow returning to the page and seeing previously-delivered notifications from the same session. With the later addition of a notification-backend, this can show notifications from beyond this browser session, and those that arrived while the user was away from Backstage.

notification-page

Further considerations

Notifications within Backstage are only one possible route for notifications to be delivered from an eventual notification-backend; such a backend should support modules to route notifications via email, Slack, Discord, etc (similar to AlertManager/Prometheus).

References

These sources helped think about the structure and behavior of notifications:

szubster commented 2 years ago

It's fascinating that we had internal discussion at Box about similar system, with very similar goals (targeting notifications to users, entities, etc.). Did not start any work yet, we planned it for future quarters. Super exciting.

marcus-crane commented 2 years ago

Exciting :)

griffinz123 commented 2 years ago

It will be a great add on to backstage. We are thinking to implement some of the devops processes in backstage utilizing the software catalog and notifications would be really helpful.

Rugvip commented 2 years ago

Nice, this is indeed gonna be a great addition! 👍

Couple of questions/comments:

  1. Could you elaborate a bit more on the role of the NotificationContext and why you suggest to split it from the main NotificationApi? Would it make sense to simply merge the context methods/data into the NotificationApi? As a slight tweak to that, another idea would be to introduce a pair of APIs instead, with a second NotificationReceiptsApi or something of that sort? A pretty big downside of keeping this state in a NotificationContext is that we don't make that information or actions available for other APIs to use.
  2. Did you consider any other options to notification channels? I'm a bit hesitant towards the API as it introduces a plugin initialization function, and with the suggested channel name deduplication there's a bit of a risk of confusion around which implementation actually gets picked. Main concern is the initialization function, I feel that in itself is a big new addition that we probably should add by itself if needed, rather than wrapped up in the channels object.
  3. Wondering a bit about kind as well, the only ones I see mentioned are 'alert' and 'home'. What kind should a plugin use when they want to publish a notification that a build is complete? A potential tweak to the spec here could be to make the kind optional, with the default notification display surface handling all notifications that don't have a kind set. Then you'd expect other custom display surfaces for notifications with explicit kinds. Not sure if that's the best solution though, want to discuss it a bit :grin:
timbonicus commented 2 years ago

Thanks for the comments @Rugvip! ❤️

  1. The NotificationContext is a band-aid for not having a notification-backend and I expect it to be removed once the backend is place. The acknowledge / receipts method on the context should be a backend call eventually, probably just added to the NotificationApi as you say.

    This could be on the API now, if the API implementation stored it locally and the context retrieved it to filter messages. I hesitated to add it there since the signature will probably be different when sending receipts to a real notification-backend (e.g. sending receipts for particular notification uuids instead of just a last-read timestamp).

  2. The channel name deduplication was put in for a real-world example we have where two plugins use the same channel (defined in a third, separate package). Backstage apps may have one or both of the plugins installed, so they needed to be able to add the channel naively but not inadvertently set up a duplicate channel. Alternatively, if a plugin had a way to check if a channel was already added then it could just skip registering it again.

    It could totally make sense to decouple plugin initialization from channels, and just have access to register channels as part of the initialization. 🤔 Not sure offhand what that would look like, definitely open to ideas!

  3. We're thinking of kind as meaningful to where the notification should be shown. alert is a system-wide overlay, home is a home-screen banner. For a build failure, maybe it would be user? Maybe some more thought needed here using practical examples. Having it optional seems odd to me wrt the k8s object format (though, one might argue, we've departed already by not including apiVersion).

Rugvip commented 2 years ago

np!

  1. Even with a notification-backend in the picture you'd anyway most likely want to abstract the read receipts behind some API right? Figuring that if we're gonna do read receipts from the beginning we might as well strive to form an API that supports an eventual future notification-backend without or with minimal change. I don't thing formulating it as a slightly more verbose API should be a problem tbh, doing receipts per uuid as you say.

    Would totally be backed by some storage within the API implementation itself. Could just be in-memory or we could go a bit more fancy with local storage for or some other form of sync between windows.

  2. Do you think a deliberate installation of plugin channels in the app would be an alright model? Potentially an extension that wraps the channel that you can render near the top of the tree? With that model we get the visibility, explicitness, and don't have to invent anything new, but ofc it's a bit more work to install. That may be a good thing too as it makes it possible to pick and choose the channels that you want to use.

  3. Hmm, perhaps something more towards that end than kind in that case? I'm thinking something like target or such. I don't find the k8s object model to be too important to stick to in this case really?

    Then again I do think it is good idea to have some indirection between the notifications and the display of them. I do think kind could work pretty well, but perhaps oriented a bit more towards what the notification contains, rather than where it should be displayed?

    In the end I'm feeling a bit more exploration and discussion here could be good, especially pinpointing the kind of use-cases we're looking to support and how much flexibility we want to have. I'm not feeling that it's obvious how to pick what kind of notification you should be sending as a plugin author right now, and having that decision be easy I think is important to the DX of the API.

On completely separate note, something to potentially add to the metadata/spec could be the plugin that the notification originated from. That'd also likely be a powerful tool if one wants to do some manual filtering/mapping in places.

jhaals commented 2 years ago

First of all great work with this RFC, it's a very exciting feature!

As a start I agree with Patrik that it's a good idea implement the API with a notifications backend in mind from the start and rather "cheat" with the frontend implementation to reduce the risk of missing details early on.

Have you given any thought to time sensitive notifications? I'm thinking of the example with Semla in the kitchen. One would be very sad coming back from vacation a week later and finding out that there's no more Semlor.

Similarly having a notification for a group of individuals. I guess you would want to have some deadline to when the notification is no longer valid for members members visiting backstage.

timbonicus commented 2 years ago

To @jhaals point, we had a discussion to think through what this would look like ideally in the end. There will likely be a general backend event stream, similar to the more narrowly-scoped #8219, and frontend plugins may subscribe handlers to one or more channels of that event stream. These handlers can do any number of things, including triggering notifications based on the events. Therefore the notification API should be more of a "notification display API" and perhaps not be concerned with the backend payload that would instead be delivered through the event stream.

This tracks with a realization that, except for very simple alerts, there will need to be some frontend "hydration" of events to make them useful as notifications in the interface. For example, the icon or actions shown above are not things you'd be storing in a database — these need frontend knowledge of system icons, and routes to even formulate links.

For @Rugvip's (2) above, we like the explicitness of an app integrator being able to choose the channels / notifications that are shown in the interface, but disliked having another plugin installation step. There may also be other initialization that plugins want to do besides initializing notification channels. We're tentatively proposing a very experimental, use-at-your-own-risk, synchronous initialize addition to the createPlugin arguments that would allow a frontend plugin access to all APIs. This would replace the proposal for a notificationChannels option:

export type PluginConfig<Routes, ExternalRoutes> = {
  id: string;
  apis?: Iterable<AnyApiFactory>;
  routes?: Routes;
+  dangerouslyInitializeAndVoidWarranty: (apiHolder: ApiHolder) => void;
  externalRoutes?: ExternalRoutes;
  featureFlags?: PluginFeatureFlagConfig[];
-  notificationChannels?: PluginNotificationChannel[];
};

This would allow plugins to fire a one-time notification, set up a setInterval call, or eventually add event handlers. Later there may be a way for app integrators to supply options to plugins to control this initialization behavior, so that explicitness can still be supported (e.g. opting-out of certain notifications/channels).

The idea of an API being more display-oriented means that we can likely drop some of the Notification fields above and have a slimmer type focused on the where and what of how to display notifications. Perhaps this always includes a JSX.Element for more powerful custom rendering (with some default components available), and callbacks for UI-related actions like dismissing a notification.

We think the expiration of notifications that @jhaals touched on would likely be done in the event backend, some events might have an expiration timestamp or TTL. Relatedly, when loading an eventual event stream in the frontend do I receive all relevant events that happened since I last logged in? Should I be alerted of a build failure that happened a week ago? What if it was fixed and built successfully since then? There may be a notion of canceling or clearing events, or perhaps the expiration of past events is updated when more relevant current events arrive.

We'll do some experimentation with these ideas on the branch and report back.

marcus-crane commented 2 years ago

Unrelated to this RFC but I always enjoy the detailed discussions and considerations that come from both the Backstage maintainers and community contributors 🙂 I feel like I learn a lot just following along these sorts of future proposals

evankanderson commented 2 years ago

Sorry to swing by, but someone on the VMware side brought this to my attention, and the Notification object looks similar to, but not compatible with the CloudEvents spec:

export type Notification = {
  kind: string;
  metadata: {
    title: string;
    message: string;
    uuid: string;
    timestamp: Date;
    [key: string]: any;
  };
  spec?: {
    // Catalog entity that triggered the notification, if applicable
    originatingEntityRef?: EntityRef;
    // Target User/Group entity refs if the notification is not global.
    targetEntityRefs?: Array<EntityRef>;
    icon?:  string | JSX.Element; // System icon or custom
    actions?: Array<
      | { title: string; url: string; }
      | { title: string; callback: Function; }
    >;
  }
};
Notification field CloudEvents field
kind type
metadata.title custom attribute
metadata.message put in (json) event payload
metadata.uuid id
metadata.timestamp time
metadata.key + value custom attribute -- would limit this to string : string maps
spec.originatingEntityRef source or subject (EntityRef serialized as a URL or string, see below)
other spec attributes put in (json) event payload
spec.targetEntityRefs --> put this outside the Event payload in event routing information

The advantage of being able to serialize to a CloudEvents-compatible format is that it can simplify sharing and routing the events outside of Backstage as an extension mechanism, for example to a workflow or serverless platform. If you do end up exposing these CloudEvents outside of a Backstage instance, I'd suggest using the source attribute to point back to the Backstage instance that emitted the event; this allows easy disambiguation if you have a "test" and "production" version of Backstage, for example. The subject attribute could then contain a serialized EntityRef which was valid within the scope of that Backstage instance.

timbonicus commented 2 years ago

Thanks @evankanderson, this is great to point out. CloudEvents were mentioned in the original issue, I'll take a closer look at this spec.

We're re-evaluating the Notification type based on some experimentation and conversations. Specifically, splitting into Event which captures the original event and Notification which might be generated based on an event, and has more UI and display-focused things (like targetEntityRefs as you point out, the event itself shouldn't care who listens to it).

timbonicus commented 2 years ago

Recapping some thinking here as an update.

We believe Backstage will eventually have an event/message bus available to backends, where things like catalog updates, build failures, audit logs of activity, etc. will be broadcast. These events will carry some of the fields in the original proposal above, such as originatingEntityRef. The type sensibly has similarities with CloudEvents, as @evankanderson mentions:

type Event = {
  uuid: string;
  timestamp: number;
  plugin: string; // or source
  type: string; // similar to permissions, perhaps e.g. catalog.entity.updated
  originatingEntityRef?: string;
  data?: Record<string, any>;
};

Backend plugins should have access to this event bus; not only to fire their own events, but also to listen and respond to the events of other plugins. Notifications in the Backstage UI are only one possible response to these events — a search index might be updated, or an external system called, or notifications might be sent through different channels than the frontend (Slack, email).

The event itself should not dictate whether or which notifications might be generated, it should only serve as a record that something happened. There may be many different notification systems which respond to events in ways beyond the imagination of the event author.

There should be a layer that consumes this event bus with the intent of creating notifications when appropriate. Since the event bus contains events from plugins that may be entirely internal to an adopting company, there is no generic way to know which events should trigger notifications. It's also likely that different companies will want different notification defaults. It seems desirable then, that whatever layer exists is extendable and customizable. This layer might be configured with a set of event handlers from other plugins, similar to how to the catalog is configured with processors. Also similar to catalog processors, there may be a set of sensible defaults provided that can be overridden or added to.

Beyond that, we believe Backstage users themselves will eventually want to customize notifications — silence certain types of notifications, or notifications pertaining to certain catalog entities or teams. They may also subscribe to notifications that are not enabled by default. For the sanity of plugin authors, one should not need to worry about this level of customization when writing an event handler.

I believe this points to a notification-backend, which takes event handlers (or more pointedly, event-to-notification-generators), runs events from the bus through all the handlers, and stores the resulting notifications. This backend would also provide API routes to the frontend which load relevant notifications, and filter them based on user preferences. The notifications stored in the backend would have their own type:

type Notification = {
  uuid: string;
  timestamp: number;
  plugin: string; // the plugin or event-handler-module that generated the notification, not the plugin from the original event
  title: string;
  message: string;
  targetEntityRefs?: string[];
  data?: Record<string, any>;
};

These notifications are not specific to the Backstage frontend, and are suitable to be delivered through many potential notification channels. Similarly, the notification-backend APIs are general-purpose for any notification consumer, and not tailored specifically for the frontend.

Another responsibility of the notification-backend is to receive and store read-receipts, either from the frontend or another notification consumer. Read receipts store a combination of notification uuid, userEntityRef, and read timestamp. These serve to filter notifications returned by the API (unless querying for all notifications specifically).

The challenge mentioned above of frontend hydration still exists. The initialize method for frontend plugins probably still makes sense, perhaps the NotificationApi in the frontend has a registerHandler or similar that can be called to provide hydration for notifications delivered from the backend. The returned type could extend Notification to provide the frontend-specific fields from the original type:

type UINotification = Notification &
| {
    icon?:  string | JSX.Element; // System icon or custom
    actions?: Array<
      | { title: string; url: string; }
      | { title: string; callback: Function; }
    >;
  }
| {
    element?: JSX.Element;
  };

An alternative approach could be to mimic the outlet pattern to provide components that respond to certain notification types for just the user notification page:

<Route path="/user/notifications" element={<NotificationsPage />}>
  <NotificationExtensions>
    <GithubActionsBuildNotification type="github.actions.build" />
  </NotificationExtensions>
</Route>

This could become a bit unwieldy for the app integrator, though many common core notifications may come with built-in support from app-defaults. This begs the question of how to share these notification UI elements, such as if notifications relevant to a particular component are shown on the catalog page.

laceyallyn commented 2 years ago

Hey there! I'm the product manager responsible for rolling out Backstage in Zalando. We have 2 use cases that might be related to this depending on how you end up defining notifications.

The first, a request from strictly users: To enable desktop notifications for time-sensitive topics which require their attention (the original request was about failed deployments), so that they get the notification even when they are not actively in the Sunrise interface. There was also the comment that settings for this would be necessary, maybe even on a plugin-level.

The second, is a request from stakeholders who are both users and contributors To enable contributors to inform users about new features/functionality they've developed; most of these kind notifications would require a link to an interface and / or to more information (like documentation or announcements in "official" company channels), and a limited character count would be helpful to support content authors to keep it brief. It would also be ideal to be able to target these notifications to users of specific plugins. The user could read these at their leisure, and would need an indication of which they have read/interacted with before, and be to be able to dismiss them so that they no longer appear.

Hope this is helpful ☺️

timbonicus commented 2 years ago

@laceyallyn Very helpful, thank you! I haven't considered desktop notifications, but that could certainly add on top of this work once the frontend is receiving notifications.

The second is perhaps similar to what we have in mind for Home page banners mentioned above; we use this at Spotify to advertise new features, for example:

home-banner

The read receipts capability would allow this to hide announcements once they are acknowledged by the logged-in user.

manuelscurti commented 2 years ago

Hi guys! I am excited by this RFC, and open to help wherever you might need. Talking about system-wide notifications (i.e. the ones displayed by DisplayAlert at the moment), it would be great to have full flexibility on the style of them, and I see some attempts with the UINotification type definition.

However, I found out there is a cool library called notistack, that already comes with plenty of customizable settings for snackbars.

It would be great if Backstage could include this library out-of-the-box for system-wide notifications

jrusso1020 commented 1 year ago

@timbonicus curious if there is any update on the status of this RFC?

timbonicus commented 1 year ago

@jrusso1020 No update at the moment as attention has been elsewhere, but I am striving to get back to this soon with some more experimentation.

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

arslan-raza-143 commented 1 year ago

@jhaals

evankanderson commented 1 year ago

Is this issue still active?

One issue that occurred to me when discussing team notifications is that it may be useful to be able to manifest notifications in a variety of ways -- as a banner on Backstage, but also as an email / Jira / slack message, etc. Is there an architectural recommendation or suggestion on how to handle these different notification channels?

freben commented 1 year ago

It's active in the sense that we still want it! But the maintainers themselves haven't worked on it since our focus is elsewhere.

Regarding email / Jira / slack etc. One interesting development that happened just recently, is the addition of the events backend and its modules. There's probably a future where Backstage plugins emit events to our own event bus, and then you can add modules that subscribe to that, and do whatever you want based on those triggers.

I still think there's a need for two mechanisms here. One that's the pure instantaneous event transfer system, and one that's the notifications persistence system. The first is fast and almost stateless, the second has fanout / assignment, long term storage, acknowledgements tracking etc. But having an event bus in between might be a nice unifying layer between the backend and frontend worlds.

alper98 commented 1 year ago

Are there any updates to this? 😊

Would be cool if the frontend could be adapted to include custom implementations of the alerts instead of the AlertApi. Here at my org, we use react-toastify to display notifications/toasts 😊

benjdlambert commented 1 year ago

Don't think there's much movement yet, and there's still some architectural questions to be answered I think. But one thing to note is that I think with the introduction of the events-backend which is powering some of the webhook usecases, could unlock some of the work required to implement this.

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

heyLu commented 1 year ago

Commenting to mark this as still interesting (and not stale) to many people.

For example, we'd like to be able to "nudge" people to address the Tech Insights of the components they own. Currently we have a UI element on the homepage that lists components with issues, but we'd love to have a way to nudge people on every Backstage page they visit, not just the homepage.

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

efenner-cambia commented 1 year ago

bump

drodil commented 12 months ago

My two cents. Whenever a notification is posted, the notification-backend should utilize the events-backend to notify other backends about a new notification. This allows to further send the notification to other channels such as Slack or email or whatever. And for the frontend, the notification-backend should utilize the signals (https://github.com/backstage/backstage/pull/17997) to spin up the notification to the user (if/when that PR gets merged).

github-actions[bot] commented 10 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Shocktrooper commented 10 months ago

Bump for marking unstale

sharadpattanshetti commented 9 months ago

We are keenly looking forward for this feature.

github-actions[bot] commented 7 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

italux commented 7 months ago

Making unstale

github-actions[bot] commented 5 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

rhoml commented 3 months ago

Would be great to see this happening :)

webark commented 3 months ago

We were going to look into https://novu.co I guess they have a self hosted free version? 🤷‍♂️

drodil commented 3 months ago

@rhoml this is happening all the time. There's BEP now about the notifications #22213 and also inital implementation in #21889

drodil commented 3 months ago

Also feel free to add your input to the discussion/BEP to make this work for most of the adopters!

schultzp2020 commented 3 months ago

@timbonicus what are your thoughts on expanding the scope of the notification-backend to include some sort of adapter where users could send audit log events to a logging system like Splunk?

awanlin commented 3 months ago

@schultzp2020 have you looked at: https://github.com/backstage/backstage/tree/master/beps/0001-notifications-system. That would be the latest proposal for notifications and as @drodil mentioned there is an initial implementation in #21889

github-actions[bot] commented 1 month ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

efenner-cambia commented 1 month ago

Has this RFC been superseded by the BEP?

mareklibra commented 1 month ago

The BEP took this RFC into account. IMO, this RFC can be closed. Next features can be implemented separately, in smaller chunks.

freben commented 1 month ago

Nice!