Skip to content

Commit 8b814db

Browse files
authored
Merge pull request #4377 from nhsuk/next
Version 3.2.0
2 parents 2b4b2fe + 46cf82c commit 8b814db

File tree

139 files changed

+2172
-473
lines changed

Some content is hidden

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

139 files changed

+2172
-473
lines changed

.github/workflows/deploy-monitoring.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ jobs:
121121
name: Terraform apply (Grafana)
122122
runs-on: ubuntu-latest
123123
needs: [plan-aws, apply-aws]
124-
if: always() && needs.plan-aws-aws.result == 'success' && (needs.apply-aws.result == 'success' || needs.apply-aws.result == 'skipped')
124+
if: always() && needs.plan-aws.result == 'success' && (needs.apply-aws.result == 'success' || needs.apply-aws.result == 'skipped')
125125
permissions:
126126
id-token: write
127127
defaults:

.github/workflows/lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
cache: yarn
2222
node-version-file: .tool-versions
2323
- run: yarn install --immutable --immutable-cache --check-cache
24-
- uses: jdx/mise-action@v2
24+
- uses: jdx/mise-action@v3
2525
with:
2626
install_args: hk pkl tflint terraform
2727
- run: tflint --chdir=terraform --init

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ gem "good_job"
4444
gem "govuk-components"
4545
gem "govuk_design_system_formbuilder"
4646
gem "govuk_markdown"
47+
gem "indefinite_article"
4748
gem "jsonb_accessor"
4849
gem "jwt"
4950
gem "mechanize"

Gemfile.lock

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,25 +113,25 @@ GEM
113113
ast (2.4.3)
114114
attr_required (1.0.2)
115115
aws-eventstream (1.4.0)
116-
aws-partitions (1.1147.0)
117-
aws-sdk-accessanalyzer (1.76.0)
116+
aws-partitions (1.1150.0)
117+
aws-sdk-accessanalyzer (1.77.0)
118118
aws-sdk-core (~> 3, >= 3.228.0)
119119
aws-sigv4 (~> 1.5)
120-
aws-sdk-core (3.229.0)
120+
aws-sdk-core (3.230.0)
121121
aws-eventstream (~> 1, >= 1.3.0)
122122
aws-partitions (~> 1, >= 1.992.0)
123123
aws-sigv4 (~> 1.9)
124124
base64
125125
bigdecimal
126126
jmespath (~> 1, >= 1.6.1)
127127
logger
128-
aws-sdk-ec2 (1.549.0)
128+
aws-sdk-ec2 (1.550.0)
129129
aws-sdk-core (~> 3, >= 3.228.0)
130130
aws-sigv4 (~> 1.5)
131131
aws-sdk-ecr (1.108.0)
132132
aws-sdk-core (~> 3, >= 3.228.0)
133133
aws-sigv4 (~> 1.5)
134-
aws-sdk-iam (1.127.0)
134+
aws-sdk-iam (1.128.0)
135135
aws-sdk-core (~> 3, >= 3.228.0)
136136
aws-sigv4 (~> 1.5)
137137
aws-sdk-kms (1.110.0)
@@ -140,7 +140,7 @@ GEM
140140
aws-sdk-rds (1.287.0)
141141
aws-sdk-core (~> 3, >= 3.228.0)
142142
aws-sigv4 (~> 1.5)
143-
aws-sdk-s3 (1.196.1)
143+
aws-sdk-s3 (1.197.0)
144144
aws-sdk-core (~> 3, >= 3.228.0)
145145
aws-sdk-kms (~> 1)
146146
aws-sigv4 (~> 1.5)
@@ -172,11 +172,11 @@ GEM
172172
capybara-screenshot (1.0.26)
173173
capybara (>= 1.0, < 4)
174174
launchy
175-
caxlsx (4.2.0)
175+
caxlsx (4.3.0)
176176
htmlentities (~> 4.3, >= 4.3.4)
177177
marcel (~> 1.0)
178178
nokogiri (~> 1.10, >= 1.10.4)
179-
rubyzip (>= 1.3.0, < 3)
179+
rubyzip (>= 2.4, < 4)
180180
cgi (0.4.2)
181181
charlock_holmes (0.7.9)
182182
childprocess (5.0.0)
@@ -306,6 +306,8 @@ GEM
306306
domain_name (~> 0.5)
307307
i18n (1.14.7)
308308
concurrent-ruby (~> 1.0)
309+
indefinite_article (0.2.5)
310+
activesupport
309311
io-console (0.8.1)
310312
irb (1.15.2)
311313
pp (>= 0.6.0)
@@ -602,7 +604,7 @@ GEM
602604
rubyzip (>= 1.3.0)
603605
rubyntlm (0.6.5)
604606
base64
605-
rubyzip (2.4.1)
607+
rubyzip (3.0.2)
606608
rufo (0.18.1)
607609
sanitize (7.0.0)
608610
crass (~> 1.0.2)
@@ -790,6 +792,7 @@ DEPENDENCIES
790792
govuk_design_system_formbuilder
791793
govuk_markdown
792794
hotwire-livereload
795+
indefinite_article
793796
its
794797
jsbundling-rails
795798
jsonb_accessor
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# 14. Use AWS Cloud Map for Service Discovery
2+
3+
Date: 2025-07-21
4+
5+
## Status
6+
7+
Accepted
8+
9+
## Context
10+
11+
The introduction of the reporting service transforms the Mavis application into one consisting of multiple ECS
12+
services that need to communicate with each other internally, for data access and processing. Therefore, we require a
13+
scalable and reliable service discovery mechanism to facilitate this architectural change.
14+
15+
## Considered Options
16+
17+
Several service discovery approaches were evaluated for ECS inter-service communication, prioritizing CodeDeploy
18+
compatibility for blue-green deployments and scalability for future services.
19+
20+
### Option 1: Internal Application Load Balancer (ALB)
21+
22+
Use an internal ALB for routing via path/host rules, with ECS-integrated target groups for dynamic registration.
23+
24+
- **Pros**: Includes load balancing and health checks.
25+
- **Cons**: Incompatible with CodeDeploy's task set management (max one target group per ECS service);
26+
adds SSL and rule overhead.
27+
28+
Rejected due to deployment issues.
29+
30+
### Option 2: AWS Service Connect
31+
32+
Managed ECS discovery with DNS, load balancing, and metrics, built on Cloud Map.
33+
34+
- **Pros**: Easy setup with failover and telemetry; implementing TLS/SSL is straightforward.
35+
- **Cons**: Requires ECS controller, conflicting with CodeDeploy's blue-green needs.
36+
37+
Rejected for compatibility.
38+
39+
### Option 3: AWS Cloud Map (Service Discovery)
40+
41+
Register services in a private DNS namespace for resolution (e.g., `web.mavis.${environment}.aws-int`), using MULTIVALUE
42+
routing.
43+
44+
- **Pros**: CodeDeploy-compatible; lightweight DNS-based; ECS-integrated registration.
45+
- **Cons**: No built-in load balancing; needs manual security rules; implementing TLS/SSL requires additional complexity
46+
47+
Selected for meeting requirements.
48+
49+
### Comparison
50+
51+
With the requirement of blue-green deployments, AWS Cloud Map was the only viable option that offered a simple DNS-based
52+
service discovery mechanism that integrates well with ECS and CodeDeploy.
53+
54+
## Decision
55+
56+
We will use AWS Cloud Map (Service Discovery) to enable service-to-service communication. This involves creating a
57+
private DNS namespace within the VPC and registering ECS services (e.g., the web service) with Cloud Map. Services can
58+
then resolve each other using DNS names (e.g., `web.mavis.${environment}.aws-int`), allowing dynamic IP resolution for
59+
tasks.
60+
61+
- A private DNS namespace (`mavis.${environment}.aws-int`) will be provisioned.
62+
- The web service will be registered with a MULTIVALUE routing policy to support multiple tasks.
63+
- Security group rules will explicitly allow ingress/egress between services
64+
(e.g., reporting service to web service on port 4000).
65+
- This integrates seamlessly with Terraform for infrastructure management and does not conflict with CodeDeploy.
66+
67+
## Consequences
68+
69+
- Services will dynamically discover each other via DNS, improving scalability and reducing configuration drift.
70+
- Additional Terraform resources (e.g., `aws_service_discovery_private_dns_namespace` and
71+
`aws_service_discovery_service`) will be maintained, increasing infrastructure complexity slightly but providing
72+
better automation.
73+
- DNS caching (TTL set to 10 seconds initially) may introduce minor latency during task scaling or failures; this can be
74+
tuned based on monitoring.
75+
- Alignment with AWS-native services ensures compatibility with future enhancements but requires monitoring DNS
76+
resolution metrics to detect issues.
77+
- No changes to application code are needed beyond using the resolved DNS names for internal calls.

app/components/app_activity_log_component.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ def vaccination_events
274274
discarded =
275275
if vaccination_record.discarded?
276276
{
277-
title: "Vaccination record deleted",
277+
title: "Vaccination record archived",
278278
at: vaccination_record.discarded_at,
279279
programmes: programmes_for(vaccination_record)
280280
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<% return if discrepancies.blank? %>
2+
3+
<div class="nhsuk-table__panel-with-heading-tab">
4+
<h3 class="nhsuk-table__heading-tab">
5+
<%= pluralize(discrepancies.count, "NHS number") %>
6+
<%= discrepancies.count == 1 ? "was" : "were" %> updated
7+
</h3>
8+
9+
<p>
10+
<%= pluralize(discrepancies.count, "incorrect NHS number") %>
11+
updated with <%= discrepancies.count == 1 ? "that" : "those" %> found on Spine.
12+
Update your original data source if necessary.
13+
</p>
14+
15+
<%= govuk_table(html_attributes: { class: "nhsuk-table-responsive" }) do |table| %>
16+
<% table.with_head do |head| %>
17+
<% head.with_row do |row| %>
18+
<% row.with_cell(text: "Child record") %>
19+
<% row.with_cell(text: "NHS number (upload)") %>
20+
<% row.with_cell(text: "NHS number (Spine)") %>
21+
<% end %>
22+
<% end %>
23+
24+
<% table.with_body do |body| %>
25+
<% discrepancies.each do |changeset| %>
26+
<% patient = changeset.patient %>
27+
28+
<% body.with_row do |row| %>
29+
<% row.with_cell do %>
30+
<span class="nhsuk-table-responsive__heading">Child record</span>
31+
<span>
32+
<% if can_link_to?(patient) %>
33+
<%= link_to patient.full_name, patient_path(patient) %>
34+
<% else %>
35+
<%= patient.full_name %>
36+
<% end %>
37+
</span>
38+
<% end %>
39+
40+
<% row.with_cell do %>
41+
<span class="nhsuk-table-responsive__heading">Uploaded NHS number</span>
42+
<%= helpers.format_nhs_number(changeset.uploaded_nhs_number) %>
43+
<% end %>
44+
45+
<% row.with_cell do %>
46+
<span class="nhsuk-table-responsive__heading">PDS NHS number</span>
47+
<%= helpers.format_nhs_number(changeset.pds_nhs_number) %>
48+
<% end %>
49+
<% end %>
50+
<% end %>
51+
<% end %>
52+
<% end %>
53+
</div>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
class AppPatientPDSDiscrepancyTableComponent < ViewComponent::Base
4+
def initialize(discrepancies:, current_user:)
5+
super
6+
7+
@discrepancies = discrepancies
8+
@current_user = current_user
9+
end
10+
11+
private
12+
13+
attr_reader :discrepancies, :current_user
14+
15+
def can_link_to?(record)
16+
allowed_ids.include?(record.id)
17+
end
18+
19+
def allowed_ids
20+
@allowed_ids ||= PatientPolicy::Scope.new(current_user, Patient).resolve.ids
21+
end
22+
end

app/components/app_session_details_summary_component.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@ def patient_sessions
2626

2727
def cohort_row
2828
count = patient_sessions.count
29-
href = import_session_path(session)
29+
30+
actions =
31+
if @session.school?
32+
href = import_session_path(session)
33+
[{ text: "Import class lists", href: }]
34+
else
35+
[]
36+
end
3037

3138
{
3239
key: {
@@ -35,7 +42,7 @@ def cohort_row
3542
value: {
3643
text: I18n.t("children", count:)
3744
},
38-
actions: [{ text: "Import class lists", href: }]
45+
actions:
3946
}
4047
end
4148

app/components/app_session_summary_component.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def rows
3030
end
3131

3232
def school_urn_row
33-
if (text = location.urn).present?
33+
if (text = location.urn_and_site).present?
3434
{ key: { text: "School URN" }, value: { text: } }
3535
end
3636
end

0 commit comments

Comments
 (0)