Skip to content

Commit 5c0243a

Browse files
committed
Merge branch 'main' into feature/eja-eli-204-add-api-gateway
2 parents 2409dfb + ad8abda commit 5c0243a

Some content is hidden

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

58 files changed

+1907
-796
lines changed

README.md

Lines changed: 102 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,22 @@ The software will only be used for signposting an individual to an appropriate s
1616
- [Setup](#setup)
1717
- [Prerequisites](#prerequisites)
1818
- [Configuration](#configuration)
19-
- [Environment variables](#environment-variables)
19+
- [Environment variables - Local](#environment-variables---local)
20+
- [Environment variables - DEV, PROD or PRE-PROD](#environment-variables---dev-prod-or-pre-prod)
2021
- [Usage](#usage)
2122
- [Testing](#testing)
2223
- [Sandbox and Specification](#sandbox-and-specification)
2324
- [Conflict with yanai](#conflict-with-yanai)
2425
- [Creating a Postman collection](#creating-a-postman-collection)
2526
- [Design](#design)
2627
- [Diagrams](#diagrams)
27-
- [Modularity](#modularity)
2828
- [Contributing](#contributing)
2929
- [Contacts](#contacts)
3030
- [Licence](#licence)
3131

3232
## Setup
3333

34-
First, ensure [Pprerequisites](#prerequisites) are met. Then clone the repository, and install dependencies.
34+
First, ensure [Prerequisites](#prerequisites) are met. Then clone the repository, and install dependencies.
3535

3636
```shell
3737
git clone https://github.com/NHSDigital/eligibility-signposting-api.git
@@ -68,18 +68,32 @@ The following software packages, or their equivalents, are expected to be instal
6868
6969
### Configuration
7070
71-
#### Environment variables
71+
#### Environment variables - Local
7272
7373
| Variable | Default | Description |
7474
|--------------------------|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
7575
| `AWS_ACCESS_KEY_ID` | `dummy_key` | AWS Access Key |
7676
| `AWS_DEFAULT_REGION` | `eu-west-1` | AWS Region |
7777
| `AWS_SECRET_ACCESS_KEY` | `dummy_secret` | AWS Secret Access Key |
7878
| `DYNAMODB_ENDPOINT` | `http://localhost:4566` | Endpoint for the app to access DynamoDB |
79+
| `S3_ENDPOINT` | `http://localhost:4566` | Endpoint for the app to access S3 |
7980
| `ELIGIBILITY_TABLE_NAME` | `test_eligibility_datastore` | AWS DynamoDB table for person data. |
80-
| `LOG_LEVEL` | `WARNING` | Logging level. Must be one of `DEBUG`, `INFO`, `WARNING`, `ERROR` or `CRITICAL` as per [Logging Levels](https://docs.python.org/3/library/logging.html#logging-levels) |
81+
| `LOG_LEVEL` | `WARNING` | Logging level. Must be one of `DEBUG`, `INFO`, `WARNING`, `ERROR` or `CRITICAL` as per [Logging Levels](https://docs.python.org/3/library/logging.html#logging-levels) |
8182
| `RULES_BUCKET_NAME` | `test-rules-bucket` | AWS S3 bucket from which to read rules. |
8283
84+
#### Environment variables - DEV, PROD or PRE-PROD
85+
86+
| Variable | Default | Description | Comments |
87+
|--------------------------|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|
88+
| `AWS_DEFAULT_REGION` | `eu-west-1` | AWS Region | |
89+
| `AWS_ACCESS_KEY_ID` | None | AWS Access Key | **AWS_ACCESS_KEY_ID** is set to None, <br/>because it is provided by the AWS environment automatically. |
90+
| `AWS_SECRET_ACCESS_KEY` | None | AWS Secret Access Key | **AWS_SECRET_ACCESS_KEY** is set to None, <br/>because it is provided by the AWS environment automatically. |
91+
| `DYNAMODB_ENDPOINT` | None | Endpoint for the app to access DynamoDB | **DYNAMODB_ENDPOINT** are set to None, <br/>since we are using aws service default endpoints which are provided automatically. |
92+
| `S3_ENDPOINT` | None | Endpoint for the app to access S3 | **S3_ENDPOINT** are set to None, <br/>since we are using aws service default endpoints which are provided automatically. |
93+
| `ELIGIBILITY_TABLE_NAME` | `test_eligibility_datastore` | AWS DynamoDB table for person data. | |
94+
| `LOG_LEVEL` | `WARNING` | Logging level. Must be one of `DEBUG`, `INFO`, `WARNING`, `ERROR` or `CRITICAL` as per [Logging Levels](https://docs.python.org/3/library/logging.html#logging-levels) | |
95+
| `RULES_BUCKET_NAME` | `test-rules-bucket` | AWS S3 bucket from which to read rules. | |
96+
8397
## Usage
8498
8599
After a successful installation, provide an informative example of how this project can be used. Additional code snippets, screenshots and demos work well in this space. You may also link to the other documentation resources, e.g. the [User Guide](./docs/user-guide.md) to demonstrate more use cases and to show more features.
@@ -128,25 +142,91 @@ Local tests will use [localstack](https://www.localstack.cloud/), started & stop
128142

129143
### Diagrams
130144

131-
The [C4 model](https://c4model.com/) is a simple and intuitive way to create software architecture diagrams that are clear, consistent, scalable and most importantly collaborative. This should result in documenting all the system interfaces, external dependencies and integration points.
132-
133-
![Repository Template](./docs/diagrams/Repository_Template_GitHub_Generic.png)
134-
135-
The source for diagrams should be in Git for change control and review purposes. Recommendations are [draw.io](https://app.diagrams.net/) (example above in [docs](.docs/diagrams/) folder) and [Mermaids](https://github.com/mermaid-js/mermaid). Here is an example Mermaids sequence diagram:
136-
137145
```mermaid
138-
sequenceDiagram
139-
User->>+Service: GET /users?params=...
140-
Service->>Service: auth request
141-
Service->>Database: get all users
142-
Database-->>Service: list of users
143-
Service->>Service: filter users
144-
Service-->>-User: list[User]
145-
```
146+
graph TB
147+
subgraph "System Context"
148+
direction TB
149+
Client["NHS App / Client"]
150+
Consumer["Postman / Consumer"]
151+
API["Eligibility Signposting API"]
152+
AWS["AWS"]
153+
end
154+
155+
Client -->|"HTTP Request"| API
156+
Consumer -->|"HTTP Request"| API
157+
API -->|"Deployed on"| AWS
158+
159+
subgraph "Container Diagram"
160+
direction TB
161+
subgraph "AWS Infrastructure"
162+
direction TB
163+
APIGW["API Gateway"]
164+
Lambda["Python Lambda (app.py)"]
165+
DynamoDB["DynamoDB Table"]
166+
S3Bucket["S3 Bucket (rules)"]
167+
IAM["IAM Roles & Policies"]
168+
end
169+
subgraph "CI/CD Pipeline"
170+
direction TB
171+
GH["GitHub Actions"]
172+
TF["Terraform"]
173+
end
174+
end
175+
176+
Client -->|"HTTPS POST /eligibility"| APIGW
177+
APIGW -->|"Invoke"| Lambda
178+
Lambda -->|"GetItem/PutItem"| DynamoDB
179+
Lambda -->|"GetObject"| S3Bucket
180+
Lambda -->|"Uses"| IAM
181+
182+
GH -->|"runs pipelines"| TF
183+
TF -->|"provisions"| APIGW
184+
TF -->|"provisions"| DynamoDB
185+
TF -->|"provisions"| S3Bucket
186+
TF -->|"provisions"| IAM
187+
188+
subgraph "Eligibility Lambda Function - Components"
189+
direction TB
190+
App["app.py (WireUp DI)"]
191+
Config["config.py, error_handler.py"]
192+
subgraph "Presentation Layer"
193+
direction TB
194+
View["views/eligibility.py"]
195+
ResponseModel["views/response_model/eligibility.py"]
196+
end
197+
subgraph "Business Logic Layer"
198+
direction TB
199+
Service["services/eligibility_services.py"]
200+
Operators["services/rules/operators.py"]
201+
end
202+
subgraph "Data Access Layer"
203+
direction TB
204+
RepoElig["repos/eligibility_repo.py"]
205+
RepoRules["repos/rules_repo.py"]
206+
Factory["repos/factory.py, exceptions.py"]
207+
end
208+
subgraph "Models"
209+
direction TB
210+
ModelElig["model/eligibility.py"]
211+
ModelRules["model/rules.py"]
212+
end
213+
end
214+
215+
Lambda -->|"loads"| App
216+
App -->|injects| View
217+
View -->|calls| Service
218+
Service -->|calls| Operators
219+
Service -->|calls| RepoElig
220+
Service -->|calls| RepoRules
221+
RepoElig -->|uses| DynamoDB
222+
RepoRules -->|uses| S3Bucket
223+
View -->|uses| ResponseModel
224+
App -->|reads| Config
225+
Service -->|uses| ModelElig
226+
Operators -->|uses| ModelRules
227+
App -->|wires| Factory
146228
147-
### Modularity
148-
149-
Most of the projects are built with customisability and extendability in mind. At a minimum, this can be achieved by implementing service level configuration options and settings. The intention of this section is to show how this can be used. If the system processes data, you could mention here for example how the input is prepared for testing - anonymised, synthetic or live data.
229+
```
150230

151231
## Contributing
152232

infrastructure/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
# Local .terraform directories
44
**/.terraform/*
55

6+
# Ignore lock file
7+
*.terraform.lock.hcl
8+
69
# .tfstate files
710
*.tfstate
811
*.tfstate.*

infrastructure/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ guard-%:
1414
# Initializes the Terraform configuration for the specified stack and environment.
1515
terraform-init: guard-env guard-stack
1616
rm -rf ./stacks/$(stack)/.terraform
17-
terraform -chdir=./stacks/$(stack) init -backend-config=backends/$(env).$(stack).tfbackend -upgrade -reconfigure
17+
terraform -chdir=./stacks/$(stack) init -backend-config=backends/$(env).$(stack).tfbackend -upgrade
1818
terraform -chdir=./stacks/$(stack) get -update
1919

2020
# Selects or creates a Terraform workspace for the specified stack and environment.

infrastructure/modules/dynamodb/kms.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ resource "aws_kms_key" "dynamodb_cmk" {
33
deletion_window_in_days = 14
44
is_enabled = true
55
enable_key_rotation = true
6+
tags = var.tags
67
}
78

89
resource "aws_kms_alias" "dynamodb_cmk" {

infrastructure/modules/dynamodb/outputs.tf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,12 @@ output "arn" {
55
output "table_name" {
66
value = aws_dynamodb_table.dynamodb_table.name
77
}
8+
9+
output "dynamodb_kms_key_arn" {
10+
value = aws_kms_key.dynamodb_cmk.arn
11+
}
12+
13+
output "dynamodb_kms_key_id" {
14+
value = aws_kms_key.dynamodb_cmk.id
15+
}
16+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../_shared/default_variables.tf
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
resource "aws_kms_key" "lambda_cmk" {
2+
description = "${terraform.workspace == "default" ? "" : "${terraform.workspace}-"}${var.lambda_func_name} Master Key"
3+
deletion_window_in_days = 14
4+
is_enabled = true
5+
enable_key_rotation = true
6+
tags = var.tags
7+
}
8+
9+
resource "aws_kms_alias" "lambda_cmk" {
10+
name = "alias/${terraform.workspace == "default" ? "" : "${terraform.workspace}-"}${var.lambda_func_name}-cmk"
11+
target_key_id = aws_kms_key.lambda_cmk.key_id
12+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
resource "aws_lambda_function" "eligibility_signposting_lambda" {
2+
# If the file is not in the current working directory you will need to include a
3+
# path.module in the filename.
4+
filename = var.file_name
5+
function_name = var.lambda_func_name
6+
role = var.eligibility_lambda_role_arn
7+
handler = var.handler
8+
9+
source_code_hash = filebase64sha256(var.file_name)
10+
11+
runtime = "python3.13"
12+
timeout = 30
13+
memory_size = 128 # Default
14+
15+
environment {
16+
variables = {
17+
ELIGIBILITY_TABLE_NAME = var.eligibility_status_table_name,
18+
RULES_BUCKET_NAME = var.eligibility_rules_bucket_name,
19+
ENV = var.environment
20+
}
21+
}
22+
vpc_config {
23+
subnet_ids = var.vpc_intra_subnets
24+
security_group_ids = var.security_group_ids
25+
}
26+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
output "aws_lambda_function_id" {
2+
value = aws_lambda_function.eligibility_signposting_lambda.id
3+
}
4+
output "aws_lambda_function_arn" {
5+
value = aws_lambda_function.eligibility_signposting_lambda.arn
6+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
variable "workspace" {
2+
description = "Usually the developer short code or the name of the environment."
3+
type = string
4+
}
5+
6+
variable "eligibility_lambda_role_arn" {
7+
description = "lambda read role arn for dynamodb"
8+
type = string
9+
}
10+
11+
variable "lambda_func_name" {
12+
description = "Name of the Lambda function"
13+
type = string
14+
}
15+
16+
variable "vpc_intra_subnets" {
17+
description = "vpc private subnets for lambda"
18+
type = list(string)
19+
}
20+
21+
variable "security_group_ids" {
22+
description = "security groups for lambda"
23+
type = list(string)
24+
}
25+
26+
variable "file_name" {
27+
description = "path of the the zipped lambda"
28+
type = string
29+
}
30+
31+
variable "handler" {
32+
description = "lambda handler name"
33+
type = string
34+
}
35+
36+
variable "eligibility_rules_bucket_name" {
37+
description = "campaign config rules bucket name"
38+
type = string
39+
}
40+
41+
variable "eligibility_status_table_name" {
42+
description = "eligibility datastore table name"
43+
type = string
44+
}
45+

0 commit comments

Comments
 (0)