Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion custom-words.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Custom dictionary for spellchecking. Before adding a word here, consider whether you can put
# it in a single (`) or multiline (```) code snippet instead, as they are automatically ignored
# by the spellchecker. Please keep the list sorted alphabetically.

AndroidX
AOSP
Bitwarden
Expand Down Expand Up @@ -94,3 +93,4 @@ YubiKeys
# Forbidden words
!auto-fill
!auto-filled
Rickabaugh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ Did lint need this? Your only usage is in a link which wasn't checked I thought.

We keep this alphabetically sorted by the way.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did, it's specifically the cspell check that causes the failure. Thanks for catching that it wasn't sorted!

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
adr: "0027"
status: "Draft"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
status: "Draft"
status: "Proposed"

date:
tags: [client]
---

# 0026 - Adopt Angular Signals for Component State

Placeholder for documentation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ What's happening with this whole file? Not understanding. You can have one proposed ADR as 27 most likely.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a placeholder for the 0027 - Angular signals ADR. Now that there is an active pull request, #638, I can remove the file

Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
adr: "0028"
status: "Proposed"
date: 2025-07-08
tags: [client]
---

# 0028 - Adopt `@ngrx/signals` for Component State Stores
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎨 Can your code reference be simplified somehow? Maybe just say "Angular Signals"? A lot of title usages can't render the preformatted text, but you can use the code in paragraphs.


<AdrTable frontMatter={frontMatter}></AdrTable>

## Prior Reading

- [ADR Draft - Adopt Angular Signals for Component State](https://bitwarden.atlassian.net/wiki/spaces/EN/pages/1538326529)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ This document should be retired in favor of the ADR, and therefore won't be linkable.

- [Angular Signals](https://angular.dev/guide/signals)
- [NgRx Docs](https://ngrx.io/guide/signals)

## Context and Problem Statement

Building on
[ADR Draft - Adopt Angular Signals for Component State](https://bitwarden.atlassian.net/wiki/spaces/EN/pages/1538326529)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ These are also not available to the community, so content should all be here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I've updated the links now that the Draft ADR references is in a pull request.

decision to adopt Angular signals for component state, this ADR addresses state management patterns
across our application on the component level.

The DIRT team frequently interacts with multiple services on the domain layer and exposes this data
to various components. Current implementation shows duplicate patterns for managing service data,
transforming it for UI consumption, and sharing it between components.

### Problem

We need a standardized approach to manage cross-component state that leverages Angular signals while
reducing code duplication and improving developer experience.

### Context

@ngrx/signals provides a signal store that captures these repeating patterns and centralizes state
management in a way that complements our existing signal adoption

## Considered Options

- **Continue with Angular Signals only**
- Maintain current approach using signals within individual components
- Does not provide the state management features and cross-component patterns that @ngrx/signals
offers through the signal store
- **Alternative state management solutions**
- Explore other state management libraries
- Existing options like the original NgRx store involve significant boilerplate, don’t leverage
signals, and lack team support
- **Adopt @ngrx/signals package**
- Implement the signal store to capture repeating patterns and manage state across components
- Builds upon our existing signal adoption

## Decision Outcome

**Adopt @ngrx/signals for state management on the component level**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**Adopt @ngrx/signals for state management on the component level**
Chosen option: **Adopt @ngrx/signals for state management on the component level.**


The benefits significantly outweigh the costs of learning curve and dependency addition. The
potential negatives can be addressed through phased implementation and clear documentation.

### Positive Consequences

- Improved developer experience
- Captures repeating patterns (huge bonus)
- Creates single source of truth from services to UI layer
- Builds existing signal adoption

### Negative Consequences

- Learning curve (though minimal compared to other state management solutions like NgRx store)
- Potential confusion if different state management patterns emerge or exist in the code-base
- May require refactoring existing service-level shared data patterns
- Need to establish organization-level guidance/examples (not just team-level)
- Introduces another dependency
- Limited debugging tools

### Plan

**Learning curve mitigation:** Presentation on the @ngrx/signals package for detailed
tutorial/documentation (refinement if needed)

**Pattern standardization:** Establish guidelines for when to use different state management
approaches and document existing state management patterns

**Phased implementation:** Start with DIRT proof of concept, then expand to organization level with
clear folder structure and guidelines

**Refactoring support:** Use current proof of concept as a template for migration patterns

**Limited debugging:** Current NgRx DevTools don’t fully support signal stores; Expose manual
debugging through a feature until NgRx team releases updated tooling

## Guidelines

**When to use a signal store:** Cross-component state management, service data aggregation,
repeating UI patterns

**Security considerations:** Do not store decrypted sensitive data in signal stores; use for UI
state, metadata, and non-sensitive application data only
Comment on lines 96 to 97
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're not storing decrypted data. What would we be using it for? Purely concerns like "is drawer open"?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question! We should still store the encrypted data in the stores. There are a few methods we can use to expose the decrypted data while it's in flight. When we start the migrations, we should and plan to explore the different methods to determine which best suites our security policies. This statement is to cover the overall idea that encrypted data is encrypted at rest. The main two methods to explore are using signal store computed signals, could be considered in flight but these are still exposed from the store, or expose a feature to signal stores that provides the functions to encrypt and decrypt within the component itself. The main difference is where we want the responsibility of encrypting and decrypting to lie architecturally.


**Data types:** Suitable for display preferences, loading state, filtered/sorted lists, navigation
state - not for decrypted vault data

**Team coordination:** Coordinate with security experts for any questions about data classification

## Further reading

- [NgRx Signal Store POC](https://github.com/bitwarden/clients/pull/15186)
- [The new NGRX Signal Store for Angular: 3+n Flavors - ANGULARarchitects](https://www.angulararchitects.io/en/blog/the-new-ngrx-signal-store-for-angular-2-1-flavors/)
- [Rethinking Reactivity w/ Alex Rickabaugh | Dec '23 | AngularNation.net](https://www.youtube.com/watch?v=_yMrnSa2cTI)
- [NgRx Signals Introduction Slides](https://docs.google.com/presentation/d/1vHVLlSmc51emZS6t_9MwEoH7FBp-yVovMgNPSOqaP_k/edit?usp=drive_link)