Skip to content

Commit da5e67c

Browse files
authored
Merge pull request #3963 from nhsuk/next
Version 2.9.0
2 parents 115865c + e4a6cbf commit da5e67c

File tree

101 files changed

+2073
-371
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+2073
-371
lines changed

.prettierignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ terraform/.terraform
3939
*.tfstate
4040
*.tfstate.backup
4141
scratchpad
42-
spec/fixtures/fhir/immunisation.json
42+
spec/fixtures/fhir/immunisation-create.json
43+
spec/fixtures/fhir/immunisation-update.json

Gemfile.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ GEM
101101
public_suffix (>= 2.0.2, < 7.0)
102102
aes_key_wrap (1.1.0)
103103
amazing_print (1.8.1)
104-
annotaterb (4.16.0)
104+
annotaterb (4.17.0)
105105
activerecord (>= 6.0.0)
106106
activesupport (>= 6.0.0)
107107
array_enum (1.6.0)
@@ -182,7 +182,7 @@ GEM
182182
climate_control (1.2.0)
183183
coderay (1.1.3)
184184
concurrent-ruby (1.3.5)
185-
config (5.5.2)
185+
config (5.6.1)
186186
deep_merge (~> 1.2, >= 1.2.1)
187187
ostruct
188188
connection_pool (2.5.3)
@@ -552,7 +552,7 @@ GEM
552552
rspec-mocks (~> 3.13)
553553
rspec-support (~> 3.13)
554554
rspec-support (3.13.4)
555-
rubocop (1.77.0)
555+
rubocop (1.78.0)
556556
json (~> 2.3)
557557
language_server-protocol (~> 3.17.0.2)
558558
lint_roller (~> 1.1.0)
@@ -569,8 +569,8 @@ GEM
569569
rubocop-capybara (2.22.1)
570570
lint_roller (~> 1.1)
571571
rubocop (~> 1.72, >= 1.72.1)
572-
rubocop-govuk (5.1.16)
573-
rubocop (= 1.77.0)
572+
rubocop-govuk (5.1.17)
573+
rubocop (= 1.78.0)
574574
rubocop-ast (= 1.45.1)
575575
rubocop-capybara (= 2.22.1)
576576
rubocop-rails (= 2.32.0)
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# 13. Amazon Managed Grafana for Monitoring and Alerting
2+
3+
Date: 2025-07-01
4+
5+
## Status
6+
7+
Accepted
8+
9+
## Context
10+
11+
Currently, monitoring is done via CloudWatch and alerts are based on Sentry. We want to improve the monitoring and
12+
alerting capabilities of the Mavis application by integrating a more robust and unified solution.
13+
14+
### Acceptance Criteria
15+
16+
1. Fully cloud native solution that integrates with AWS services.
17+
2. Monitoring does not require access to the AWS console.
18+
3. Can be fully managed and automated using terraform.
19+
4. Aligns with TechRadar's accepted technologies.
20+
5. Authentication aligns with existing Identity and Access Management (IAM) setup.
21+
6. Allows Alerts to be configured and managed within the same platform.
22+
23+
## Considered Options
24+
25+
### Option 1 : AWS CloudWatch Dashboards and Alarms
26+
27+
This option involves expanding our use of the native AWS CloudWatch service for all monitoring and alerting, creating
28+
more sophisticated dashboards and migrating all alerts to CloudWatch Alarms.
29+
30+
- **Pros**:
31+
- Deeply integrated with all AWS services.
32+
- Fully manageable via Terraform.
33+
- Provides both dashboarding and alerting in a single service.
34+
- **Cons**:
35+
- Less flexible and powerful dashboarding capabilities.
36+
- User experience requires returning to the AWS console.
37+
38+
### Option 2 : Splunk
39+
40+
This option would involve leveraging our existing Splunk integration to handle not just log aggregation but also
41+
metric-based monitoring and alerting.
42+
43+
- **Pros**:
44+
- Powerful alerting features based on complex log queries.
45+
- Can view dashboards without accessing the AWS console.
46+
- **Cons**:
47+
- Primarily a log analysis tool, not ideal for metric-based monitoring.
48+
- Integrating it AWS is more difficult as it is an external service.
49+
- Restricting NHS-wide access to dashboards and alerts would require additional configuration.
50+
51+
### Option 3 : Amazon OpenSearch Service
52+
53+
This involves using the managed OpenSearch service, which includes OpenSearch Dashboards and an integrated alerting
54+
plugin.
55+
56+
- **Pros**:
57+
- Fully managed AWS service.
58+
- Provides powerful log analytics, visualization, and alerting.
59+
- Can view dashboards without accessing the AWS console.
60+
- **Cons**:
61+
- Core strength is in log data, not metrics.
62+
- Metric-based alerting setup is more complex than specialized tools.
63+
- Potentially overkill for our primary requirements.
64+
65+
### Option 4 : Amazon Managed Grafana
66+
67+
A fully managed service for the open-source Grafana platform, which is a popular tool for analytics, interactive
68+
visualization, and alerting.
69+
70+
- **Pros**:
71+
- Purpose-built for unified dashboards and alerting.
72+
- Best-in-class visualization capabilities.
73+
- Integrates seamlessly with CloudWatch and AWS IAM Identity Center.
74+
- Fully manageable via Terraform.
75+
- Can view dashboards without accessing the AWS console.
76+
- **Cons**:
77+
- Introduces a new service to the architecture.
78+
79+
## Decision
80+
81+
We will adopt **Amazon Managed Grafana** as our primary monitoring and alerting solution.
82+
83+
It is the only option that excels at meeting all our acceptance criteria, especially the need for a unified platform for
84+
both visualization and alerting. It provides best-in-class dashboard features while also integrating an alerting system.
85+
The service also integrates well with multiple types of data (logs, streams, metrics, etc.)
86+
This allows us to consolidate our tooling and deprecate the use of Sentry for alerts, creating a more streamlined
87+
operational workflow. Its native integration with AWS for data sources (CloudWatch) and authentication (IAM Identity
88+
Center) makes it a natural fit, and as an AWS Service it is tech radar accepted.
89+
90+
## Consequences
91+
92+
- We will provision a new Amazon Managed Grafana workspace using Terraform.
93+
- User access will be managed via AWS IAM Identity Center, granting authorized personnel access to dashboards and alert
94+
configurations without needing to log into the AWS console.
95+
- CloudWatch will be configured as the primary data source within Grafana.
96+
- An initial set of dashboards for key application and infrastructure metrics (e.g., CPU/Memory utilization, database
97+
connections, latency) will be created.
98+
- All future alerting will be configured and managed within Grafana, deprecating our reliance on Sentry for this
99+
purpose.

app/components/app_activity_log_component.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def session_events
205205
patient_sessions.map do |patient_session|
206206
[
207207
{
208-
title: "Invited to the session at #{patient_session.location.name}",
208+
title: "Added to the session at #{patient_session.location.name}",
209209
at: patient_session.created_at,
210210
programmes: programmes_for(patient_session)
211211
}

app/components/app_consent_confirmation_component.rb

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,13 @@ def vaccinations_text(consent_form_programmes)
6666
.map do |consent_form_programme|
6767
programme = consent_form_programme.programme
6868

69-
if programme.flu?
70-
if consent_form_programme.vaccine_method_nasal?
71-
"nasal flu"
72-
elsif consent_form_programme.vaccine_method_injection?
73-
"flu injection"
74-
else
75-
programme.name.downcase
76-
end
69+
if programme.has_multiple_vaccine_methods?
70+
vaccine_method = consent_form_programme.vaccine_methods.first
71+
method_prefix =
72+
Vaccine.human_enum_name(:method_prefix, vaccine_method)
73+
"#{method_prefix} #{programme.name_in_sentence}".lstrip
7774
else
78-
programme.name
75+
programme.name_in_sentence
7976
end
8077
end
8178

app/components/app_patient_session_record_component.rb

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

33
class AppPatientSessionRecordComponent < ViewComponent::Base
44
erb_template <<-ERB
5-
<h2 class="nhsuk-heading-m">Record vaccination</h2>
5+
<h2 class="nhsuk-heading-m"><%= heading %></h2>
66
77
<% if helpers.policy(VaccinationRecord).new? %>
88
<%= render AppVaccinateFormComponent.new(vaccinate_form) %>
@@ -36,4 +36,18 @@ def default_vaccinate_form
3636

3737
VaccinateForm.new(patient_session:, programme:, pre_screening_confirmed:)
3838
end
39+
40+
def heading
41+
vaccination =
42+
if programme.has_multiple_vaccine_methods?
43+
vaccine_method = patient.approved_vaccine_methods(programme:).first
44+
method_string =
45+
Vaccine.human_enum_name(:method, vaccine_method).downcase
46+
"vaccination with #{method_string}"
47+
else
48+
"vaccination"
49+
end
50+
51+
"Record #{programme.name_in_sentence} #{vaccination}"
52+
end
3953
end

app/components/app_patient_session_search_result_card_component.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def action_required
9696
status = patient_session.next_activity(programme:)
9797
next if status.nil?
9898

99-
"#{I18n.t(status, scope: :activity)} for #{programme.name}"
99+
"#{I18n.t(status, scope: :activity)} for #{programme.name_in_sentence}"
100100
end
101101

102102
return if next_activities.empty?

app/components/app_patient_session_triage_component.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<% end %>
1212

1313
<% if triage_status&.vaccination_history_requires_triage? %>
14-
<p>Incomplete vaccination history for <%= programme.name %>. Check if the child needs another dose.</p>
14+
<p>Incomplete vaccination history for <%= programme.name_in_sentence %>. Check if the child needs another dose.</p>
1515
<% end %>
1616

1717
<% if helpers.policy(Triage).new? %>

app/components/app_programme_status_tags_component.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def call
1313
programme_statuses.map do |programme, hash|
1414
status = hash[:status]
1515
vaccine_methods =
16-
(hash[:vaccine_methods] if programme.has_multiple_delivery_methods?)
16+
(hash[:vaccine_methods] if programme.has_multiple_vaccine_methods?)
1717
programme_status_tag(programme, status, vaccine_methods)
1818
end
1919
)

app/components/app_session_actions_component.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def ready_for_vaccinator_row
129129

130130
texts =
131131
counts_by_programme.map do |programme, count|
132-
"#{I18n.t("children", count:)} for #{programme.name}"
132+
"#{I18n.t("children", count:)} for #{programme.name_in_sentence}"
133133
end
134134

135135
href = session_record_path(session)

0 commit comments

Comments
 (0)