Browse Source

Yarn package upgrades (#2590)

* Upgrade yarn packages to clear dependabot warnings

* Add prettier

* Run prettier

* Update docs

* Update babel config for moved plugins

* Add node_modules and similar to prettierignore, since on CI it's not run from same directory as gitignore
equation-before-demo
Rachael Booth 4 months ago committed by GitHub
parent
commit
3773dd7d9b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      .github/workflows/aws_deploy.yml
  2. 19
      .prettierignore
  3. 1
      .prettierrc
  4. 12
      .rubocop.yml
  5. 10
      README.md
  6. 10
      app/frontend/styles/_button.scss
  7. 2
      app/frontend/styles/_feedback.scss
  8. 4
      app/frontend/styles/_filter-layout.scss
  9. 8
      app/frontend/styles/_filter.scss
  10. 4
      app/frontend/styles/_panel.scss
  11. 2
      app/frontend/styles/_primary-navigation.scss
  12. 2
      app/frontend/styles/_sub-navigation.scss
  13. 2
      app/frontend/styles/_table-group.scss
  14. 2
      app/frontend/styles/_task-list.scss
  15. 4
      app/frontend/styles/application.scss
  16. 13
      app/views/content/privacy_notice.md
  17. 8
      babel.config.js
  18. 376
      config/forms/2021_2022.json
  19. 1008
      config/forms/2022_2023.json
  20. 16
      config/forms/schema/2021_2022.json
  21. 47
      config/forms/schema/generic.json
  22. 1
      config/storage.yml
  23. 2
      docker-compose.yml
  24. 2
      docs/adr/adr-006-saving-values.md
  25. 7
      docs/adr/adr-015-asset-pipeline.md
  26. 2
      docs/adr/adr-016-hotwire.md
  27. 3
      docs/adr/adr-018-form-setup.md
  28. 1
      docs/adr/adr-019-form-end-dates.md
  29. 31
      docs/api/v1.json
  30. 10
      docs/app_api.md
  31. 8
      docs/documentation_website.md
  32. 2
      docs/form/builder.md
  33. 4
      docs/form/definition.md
  34. 4
      docs/form/question.md
  35. 41
      docs/infrastructure.md
  36. 19
      docs/monitoring.md
  37. 238
      docs/setup.md
  38. 17
      docs/testing.md
  39. 7
      lib/tasks/lint.rake
  40. 5
      package.json
  41. 88
      spec/fixtures/forms/2021_2022.json
  42. 4
      spec/fixtures/forms/2022_2023.json
  43. 4583
      yarn.lock

4
.github/workflows/aws_deploy.yml

@ -53,7 +53,7 @@ jobs:
id: ecr-login
uses: aws-actions/amazon-ecr-login@v1
with:
mask-password: 'true'
mask-password: "true"
- name: Check if image with tag already exists
run: |
@ -90,7 +90,7 @@ jobs:
id: ecr-login
uses: aws-actions/amazon-ecr-login@v1
with:
mask-password: 'true'
mask-password: "true"
- name: Get timestamp
id: timestamp

19
.prettierignore

@ -0,0 +1,19 @@
# Ignore everything except as negated below
*
!*.scss
!*.md
!*.yml
!*.json
# Ensures subdirectories are checked for files matching the above
!*/
config/locales/
app/views/content/data_sharing_agreement.md
/node_modules
/vendor
/coverage
/public/assets
/app/assets/builds/*

1
.prettierrc

@ -0,0 +1 @@
{}

12
.rubocop.yml

@ -11,12 +11,12 @@ inherit_gem:
AllCops:
Exclude:
- 'bin/*'
- 'db/schema.rb'
- 'node_modules/**/*'
- 'config/application.rb'
- 'config/puma.rb'
- 'vendor/**/*'
- "bin/*"
- "db/schema.rb"
- "node_modules/**/*"
- "config/application.rb"
- "config/puma.rb"
- "vendor/**/*"
Style/Documentation:
Enabled: false

10
README.md

@ -7,11 +7,11 @@ Ruby on Rails app that handles the submission of lettings and sales of social ho
## Domain documentation
* [Domain and technical documentation](https://communitiesuk.github.io/submit-social-housing-lettings-and-sales-data)
* [Local development setup](https://communitiesuk.github.io/submit-social-housing-lettings-and-sales-data/setup)
* [Architecture decision records](https://communitiesuk.github.io/submit-social-housing-lettings-and-sales-data/adr)
* [API browser](https://communitiesuk.github.io/submit-social-housing-lettings-and-sales-data/api) (using this [OpenAPI specification](docs/api/v1.json))
* [Design history](https://core-design-history.herokuapp.com)
- [Domain and technical documentation](https://communitiesuk.github.io/submit-social-housing-lettings-and-sales-data)
- [Local development setup](https://communitiesuk.github.io/submit-social-housing-lettings-and-sales-data/setup)
- [Architecture decision records](https://communitiesuk.github.io/submit-social-housing-lettings-and-sales-data/adr)
- [API browser](https://communitiesuk.github.io/submit-social-housing-lettings-and-sales-data/api) (using this [OpenAPI specification](docs/api/v1.json))
- [Design history](https://core-design-history.herokuapp.com)
## User interface

10
app/frontend/styles/_button.scss

@ -1,8 +1,14 @@
$app-button-shadow-size: $govuk-border-width-form-element;
$app-button-inverse-background-colour: govuk-colour("white");
$app-button-inverse-foreground-colour: $govuk-brand-colour;
$app-button-inverse-shadow-colour: govuk-shade($app-button-inverse-foreground-colour, 30%);
$app-button-inverse-hover-background-colour: govuk-tint($app-button-inverse-foreground-colour, 90%);
$app-button-inverse-shadow-colour: govuk-shade(
$app-button-inverse-foreground-colour,
30%
);
$app-button-inverse-hover-background-colour: govuk-tint(
$app-button-inverse-foreground-colour,
90%
);
.app-button--inverse,
.app-button--inverse:link,

2
app/frontend/styles/_feedback.scss

@ -88,7 +88,7 @@
&:hover {
// backup style for browsers that don't support rgba
background: govuk-colour("mid-grey");
background: rgba(govuk-colour("black"), .2);
background: rgba(govuk-colour("black"), 0.2);
color: govuk-colour("black");
}

4
app/frontend/styles/_filter-layout.scss

@ -34,7 +34,9 @@
.app-filter-layout__content {
@include govuk-media-query(wide) {
float: right;
max-width: calc(#{govuk-grid-width("three-quarters")} - #{govuk-spacing(6)});
max-width: calc(
#{govuk-grid-width("three-quarters")} - #{govuk-spacing(6)}
);
width: 100%;
}
}

8
app/frontend/styles/_filter.scss

@ -5,7 +5,7 @@
.govuk-checkboxes__label,
.govuk-radios__label {
&:before {
&::before {
background-color: govuk-colour("white");
}
}
@ -47,7 +47,9 @@
&:focus {
background-color: $govuk-focus-colour;
color: $govuk-focus-text-colour;
box-shadow: 0 -2px $govuk-focus-colour, 0 4px $govuk-focus-text-colour;
box-shadow:
0 -2px $govuk-focus-colour,
0 4px $govuk-focus-text-colour;
outline: none;
}
@ -57,7 +59,7 @@
border: 0;
}
&:before {
&::before {
background-image: url("../assets/images/icon-cross.svg");
content: "";
display: inline-block;

4
app/frontend/styles/_panel.scss

@ -19,8 +19,8 @@
margin-bottom: 0;
}
.govuk-radios__label:before,
& :after {
.govuk-radios__label::before,
& ::after {
color: govuk-colour("black");
border-color: govuk-colour("black");
background-color: govuk-colour("white");

2
app/frontend/styles/_primary-navigation.scss

@ -54,7 +54,7 @@
@include govuk-typography-weight-bold;
// Extend the touch area of the link to the list
&:after {
&::after {
bottom: 0;
content: "";
left: 0;

2
app/frontend/styles/_sub-navigation.scss

@ -64,7 +64,7 @@
position: relative;
// Extend the touch area of the link to the list
&:after {
&::after {
bottom: 0;
content: "";
left: 0;

2
app/frontend/styles/_table-group.scss

@ -2,7 +2,7 @@
overflow-x: auto;
overflow-y: hidden;
margin: govuk-spacing(-3) govuk-spacing(-3) govuk-spacing(3);
padding: govuk-spacing(3) govuk-spacing(3);
padding: govuk-spacing(3);
scrollbar-color: $govuk-text-colour govuk-colour("light-grey");
.govuk-table {

2
app/frontend/styles/_task-list.scss

@ -10,7 +10,7 @@
}
.app-task-list__section-heading {
@include govuk-font($size:24, $weight: bold);
@include govuk-font($size: 24, $weight: bold);
display: table;
margin-top: govuk-spacing(0);
margin-bottom: govuk-spacing(4);

4
app/frontend/styles/application.scss

@ -13,8 +13,8 @@ $govuk-new-link-styles: true;
// Add additional breakpoint named `wide`
$govuk-breakpoints: (
mobile: 320px,
tablet: 641px,
mobile: 320px,
tablet: 641px,
desktop: 769px,
wide: 921px,
);

13
app/views/content/privacy_notice.md

@ -6,7 +6,6 @@ If your household enters a new social housing tenancy or purchases a social hous
The information is provided via ‘<%= t('service_name') %>’, a service funded and managed by MHCLG. It collects information on the tenants or residents, tenancy or sale, and the dwelling itself. Some of this data is personal and sensitive, so MHCLG is responsible for ensuring it’s processed in line with data protection legislation.
## Why do we share this information?
Information collected via CORE is shared with other government departments and agencies. It’s shared with the Greater London Authority and the Regulator of Social Housing. Data providers can also access data for their organisations via CORE. Data is only shared for research and statistical purposes.
@ -27,16 +26,16 @@ Information collected via CORE relates to your tenancy, the dwelling you are liv
Collected data will be held for as long as necessary for research and statistical purposes. When no longer needed, data will be deleted in a safe manner. We’re aware some collected data is particularly sensitive. For example:
* ethnic group
* if previous tenure is a hospital, prison or approved probation hostel support
* if household left last settled home because discharged from prison, a long stay hospital or other institution
* if referral source is probation or prison, youth offending or community mental health team, or health service
- ethnic group
- if previous tenure is a hospital, prison or approved probation hostel support
- if household left last settled home because discharged from prison, a long stay hospital or other institution
- if referral source is probation or prison, youth offending or community mental health team, or health service
MHCLG publishes data annually, in aggregate form, as part of a report and complementary tables.
* For annual lettings data, visit: [https://www.gov.uk/government/collections/rents-lettings-and-tenancies](https://www.gov.uk/government/collections/rents-lettings-and-tenancies)
- For annual lettings data, visit: [https://www.gov.uk/government/collections/rents-lettings-and-tenancies](https://www.gov.uk/government/collections/rents-lettings-and-tenancies)
* For annual sales data, visit: [https://www.gov.uk/government/collections/social-housing-sales-including-right-to-buy-and-transfers](https://www.gov.uk/government/collections/social-housing-sales-including-right-to-buy-and-transfers)
- For annual sales data, visit: [https://www.gov.uk/government/collections/social-housing-sales-including-right-to-buy-and-transfers](https://www.gov.uk/government/collections/social-housing-sales-including-right-to-buy-and-transfers)
Detail-level data is anonymised and protected, minimising identification risk. It's held with the UK Data Archive.

8
babel.config.js

@ -35,10 +35,10 @@ module.exports = function (api) {
'babel-plugin-macros',
'@babel/plugin-syntax-dynamic-import',
isTestEnv && 'babel-plugin-dynamic-import-node',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-private-methods',
'@babel/plugin-proposal-private-property-in-object',
'@babel/plugin-transform-class-properties',
'@babel/plugin-transform-object-rest-spread',
'@babel/plugin-transform-private-methods',
'@babel/plugin-transform-private-property-in-object',
'@babel/plugin-transform-regenerator',
'@babel/plugin-transform-runtime',
[

376
config/forms/2021_2022.json

@ -34,9 +34,7 @@
}
},
"conditional_for": {
"postcode_full": [
1
]
"postcode_full": [1]
},
"hidden_in_check_answers": {
"depends_on": [
@ -61,12 +59,14 @@
"is_la_inferred": true
}
},
"inferred_check_answers_value": [{
"condition": {
"postcode_known": 0
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"postcode_known": 0
},
"value": "Not known"
}
]
}
},
"depends_on": [
@ -851,9 +851,7 @@
}
},
"conditional_for": {
"mrcdate": [
1
]
"mrcdate": [1]
}
},
"mrcdate": {
@ -999,9 +997,7 @@
}
},
"conditional_for": {
"tenancyother": [
3
]
"tenancyother": [3]
}
},
"tenancyother": {
@ -1043,9 +1039,7 @@
}
},
"conditional_for": {
"tenancyother": [
3
]
"tenancyother": [3]
}
},
"tenancyother": {
@ -1277,9 +1271,7 @@
}
},
"conditional_for": {
"age1": [
0
]
"age1": [0]
},
"hidden_in_check_answers": {
"depends_on": [
@ -1301,12 +1293,14 @@
"max": 120,
"step": 1,
"width": 2,
"inferred_check_answers_value": [{
"condition": {
"age1_known": 1
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"age1_known": 1
},
"value": "Not known"
}
]
}
},
"depends_on": [
@ -2056,9 +2050,7 @@
}
},
"conditional_for": {
"age2": [
0
]
"age2": [0]
},
"hidden_in_check_answers": {
"depends_on": [
@ -2080,12 +2072,14 @@
"max": 120,
"step": 1,
"width": 2,
"inferred_check_answers_value": [{
"condition": {
"age2_known": 1
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"age2_known": 1
},
"value": "Not known"
}
]
}
},
"depends_on": [
@ -2591,9 +2585,7 @@
}
},
"conditional_for": {
"age3": [
0
]
"age3": [0]
},
"hidden_in_check_answers": {
"depends_on": [
@ -2615,12 +2607,14 @@
"max": 120,
"step": 1,
"width": 2,
"inferred_check_answers_value": [{
"condition": {
"age3_known": 1
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"age3_known": 1
},
"value": "Not known"
}
]
}
},
"depends_on": [
@ -3123,9 +3117,7 @@
}
},
"conditional_for": {
"age4": [
0
]
"age4": [0]
},
"hidden_in_check_answers": {
"depends_on": [
@ -3147,12 +3139,14 @@
"max": 120,
"step": 1,
"width": 2,
"inferred_check_answers_value": [{
"condition": {
"age4_known": 1
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"age4_known": 1
},
"value": "Not known"
}
]
}
},
"depends_on": [
@ -3652,9 +3646,7 @@
}
},
"conditional_for": {
"age5": [
0
]
"age5": [0]
},
"hidden_in_check_answers": {
"depends_on": [
@ -3676,12 +3668,14 @@
"max": 120,
"step": 1,
"width": 2,
"inferred_check_answers_value": [{
"condition": {
"age5_known": 1
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"age5_known": 1
},
"value": "Not known"
}
]
}
},
"depends_on": [
@ -4178,9 +4172,7 @@
}
},
"conditional_for": {
"age6": [
0
]
"age6": [0]
},
"hidden_in_check_answers": {
"depends_on": [
@ -4202,12 +4194,14 @@
"max": 120,
"step": 1,
"width": 2,
"inferred_check_answers_value": [{
"condition": {
"age6_known": 1
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"age6_known": 1
},
"value": "Not known"
}
]
}
},
"depends_on": [
@ -4701,9 +4695,7 @@
}
},
"conditional_for": {
"age7": [
0
]
"age7": [0]
},
"hidden_in_check_answers": {
"depends_on": [
@ -4725,12 +4717,14 @@
"max": 120,
"step": 1,
"width": 2,
"inferred_check_answers_value": [{
"condition": {
"age7_known": 1
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"age7_known": 1
},
"value": "Not known"
}
]
}
},
"depends_on": [
@ -5221,9 +5215,7 @@
}
},
"conditional_for": {
"age8": [
0
]
"age8": [0]
},
"hidden_in_check_answers": {
"depends_on": [
@ -5245,12 +5237,14 @@
"max": 120,
"step": 1,
"width": 2,
"inferred_check_answers_value": [{
"condition": {
"age8_known": 1
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"age8_known": 1
},
"value": "Not known"
}
]
}
},
"depends_on": [
@ -6251,7 +6245,7 @@
"value": "Other"
},
"47": {
"value":"Tenant prefers not to say"
"value": "Tenant prefers not to say"
},
"divider": {
"value": true
@ -6261,9 +6255,7 @@
}
},
"conditional_for": {
"reasonother": [
20
]
"reasonother": [20]
}
},
"reasonother": {
@ -6495,9 +6487,7 @@
}
},
"conditional_for": {
"ppostcode_full": [
0
]
"ppostcode_full": [0]
},
"hidden_in_check_answers": {
"depends_on": [
@ -6522,12 +6512,14 @@
"is_previous_la_inferred": true
}
},
"inferred_check_answers_value": [{
"condition": {
"ppcodenk": 1
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"ppcodenk": 1
},
"value": "Not known"
}
]
}
}
},
@ -6560,9 +6552,7 @@
}
},
"conditional_for": {
"prevloc": [
1
]
"prevloc": [1]
}
},
"prevloc": {
@ -6957,12 +6947,14 @@
"W92000004": "Wales",
"9300000XX": "Outside UK"
},
"inferred_check_answers_value": [{
"condition": {
"previous_la_known": 0
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"previous_la_known": 0
},
"value": "Not known"
}
]
}
},
"depends_on": [
@ -7618,9 +7610,7 @@
}
},
"conditional_for": {
"chcharge": [
1
]
"chcharge": [1]
}
},
"chcharge": {
@ -7715,9 +7705,7 @@
}
},
"conditional_for": {
"chcharge": [
1
]
"chcharge": [1]
}
},
"chcharge": {
@ -7762,9 +7750,7 @@
}
},
"conditional_for": {
"chcharge": [
1
]
"chcharge": [1]
}
},
"chcharge": {
@ -7809,9 +7795,7 @@
}
},
"conditional_for": {
"chcharge": [
1
]
"chcharge": [1]
}
},
"chcharge": {
@ -7888,12 +7872,7 @@
"width": 5,
"prefix": "£",
"suffix": " every week",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -7907,12 +7886,7 @@
"width": 5,
"prefix": "£",
"suffix": " every week",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -7926,12 +7900,7 @@
"width": 5,
"prefix": "£",
"suffix": " every week",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -7945,12 +7914,7 @@
"width": 5,
"prefix": "£",
"suffix": " every week",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -7966,12 +7930,7 @@
"suffix": " every week",
"readonly": true,
"requires_js": true,
"fields_added": [
"brent",
"scharge",
"pscharge",
"supcharg"
]
"fields_added": ["brent", "scharge", "pscharge", "supcharg"]
}
},
"depends_on": [
@ -8111,12 +8070,7 @@
"width": 5,
"prefix": "£",
"suffix": " every 2 weeks",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8130,12 +8084,7 @@
"width": 5,
"prefix": "£",
"suffix": " every 2 weeks",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8149,12 +8098,7 @@
"width": 5,
"prefix": "£",
"suffix": " every 2 weeks",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8168,12 +8112,7 @@
"width": 5,
"prefix": "£",
"suffix": " every 2 weeks",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8189,12 +8128,7 @@
"suffix": " every 2 weeks",
"readonly": true,
"requires_js": true,
"fields_added": [
"brent",
"scharge",
"pscharge",
"supcharg"
]
"fields_added": ["brent", "scharge", "pscharge", "supcharg"]
}
},
"depends_on": [
@ -8234,12 +8168,7 @@
"width": 5,
"prefix": "£",
"suffix": " every 4 weeks",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8253,12 +8182,7 @@
"width": 5,
"prefix": "£",
"suffix": " every 4 weeks",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8272,12 +8196,7 @@
"width": 5,
"prefix": "£",
"suffix": " every 4 weeks",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8291,12 +8210,7 @@
"width": 5,
"prefix": "£",
"suffix": " every 4 weeks",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8312,12 +8226,7 @@
"suffix": " every 4 weeks",
"readonly": true,
"requires_js": true,
"fields_added": [
"brent",
"scharge",
"pscharge",
"supcharg"
]
"fields_added": ["brent", "scharge", "pscharge", "supcharg"]
}
},
"depends_on": [
@ -8357,12 +8266,7 @@
"width": 5,
"prefix": "£",
"suffix": " every month",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8376,12 +8280,7 @@
"width": 5,
"prefix": "£",
"suffix": " every month",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8395,12 +8294,7 @@
"width": 5,
"prefix": "£",
"suffix": " every month",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8414,12 +8308,7 @@
"width": 5,
"prefix": "£",
"suffix": " every month",
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge",
"hidden_in_check_answers": true
},
@ -8435,12 +8324,7 @@
"suffix": " every month",
"readonly": true,
"requires_js": true,
"fields_added": [
"brent",
"scharge",
"pscharge",
"supcharg"
]
"fields_added": ["brent", "scharge", "pscharge", "supcharg"]
}
},
"depends_on": [
@ -8637,9 +8521,7 @@
}
},
"conditional_for": {
"tshortfall": [
0
]
"tshortfall": [0]
}
},
"tshortfall": {

1008
config/forms/2022_2023.json

File diff suppressed because it is too large Load Diff

16
config/forms/schema/2021_2022.json

@ -4,12 +4,7 @@
"title": "Form",
"description": "A form",
"type": "object",
"required": [
"form_type",
"start_year",
"end_year",
"sections"
],
"required": ["form_type", "start_year", "end_year", "sections"],
"properties": {
"form_type": {
"description": "",
@ -40,9 +35,7 @@
"[a-z_]+": {
"description": "",
"type": "object",
"required": [
"label"
],
"required": ["label"],
"properties": {
"label": {
"description": "",
@ -69,10 +62,7 @@
"[a-z_]+": {
"description": "",
"type": "object",
"required": [
"header",
"check_answer_label"
],
"required": ["header", "check_answer_label"],
"properties": {
"check_answer_label": {
"description": "",

47
config/forms/schema/generic.json

@ -4,12 +4,7 @@
"title": "Form",
"description": "A form",
"type": "object",
"required": [
"form_type",
"start_year",
"end_year",
"sections"
],
"required": ["form_type", "start_year", "end_year", "sections"],
"properties": {
"form_type": {
"description": "",
@ -40,9 +35,7 @@
"[a-z_]+": {
"description": "SubSection Name",
"type": "object",
"required": [
"label"
],
"required": ["label"],
"properties": {
"label": {
"description": "",
@ -54,10 +47,7 @@
"^(?!(depends_on))[a-z_]+$": {
"description": "Page Name",
"type": "object",
"required": [
"header",
"questions"
],
"required": ["header", "questions"],
"properties": {
"header": {
"description": "",
@ -73,10 +63,7 @@
"[a-z_]+": {
"description": "Question Name",
"type": "object",
"required": [
"header",
"type"
],
"required": ["header", "type"],
"properties": {
"header": {
"description": "",
@ -115,20 +102,22 @@
"description": "fields that get inferred based on the value of the current field",
"type": "object"
},
"inferred_check_answers_value": [{
"description": "value that gets displayed in the check answers for this field if the given condition is met",
"type": "object",
"properties": {
"condition": {
"description": "",
"type": "object"
},
"value": {
"description": "",
"type": "object"
"inferred_check_answers_value": [
{
"description": "value that gets displayed in the check answers for this field if the given condition is met",
"type": "object",
"properties": {
"condition": {
"description": "",
"type": "object"
},
"value": {
"description": "",
"type": "object"
}
}
}
}]
]
},
"minProperties": 1
}

1
config/storage.yml

@ -5,7 +5,6 @@ test:
local:
service: Disk
root: <%= Rails.root.join("storage") %>
# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
# amazon:
# service: S3

2
docker-compose.yml

@ -1,4 +1,4 @@
version: '3.6'
version: "3.6"
volumes:
dbdata:

2
docs/adr/adr-006-saving-values.md

@ -18,6 +18,6 @@ There are a few reasons we have opted to save the values directly, they are as f
- Changing the wording/casing of the answers could result in discrepancies in the database.
- There is a small risk that if the database is accessed by someone unauthorised they would have access to personally identifiable information if we were to collect Any. We will be mitigating this risk by encrypting the production database.
- There is a small risk that if the database is accessed by someone unauthorised they would have access to personally identifiable information if we were to collect Any. We will be mitigating this risk by encrypting the production database.
This decision is not too difficult to change and can be revisited in the future if there is sufficient reason to switch to storing keys/numbers and using enums and active record to convert those to the appropriate values.

7
docs/adr/adr-015-asset-pipeline.md

@ -12,12 +12,11 @@ However, since Rails 7, it's been deprecated by the Rails CORE team and it's jav
The primary options considered were:
1. [Import maps](https://github.com/rails/importmap-rails) - Rails 7 default. Serve JS directly but do no transpiling so not suitable
2. [JSBundling](https://github.com/rails/jsbundling-rails) - Rails recommended
- With [ESBuild](https://esbuild.github.io/) - fast and does some transpiling but [doesn't support ES5/IE11](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/203)
- With [Rollup](https://www.rollupjs.org/guide/en/) - similar to ESBuild, node rather than Go based, doesn't have the big speed benefits
- With [Webpack](https://webpack.js.org/) - rather than the old approach of using Webpacker as a opinionated wrapper around webpack, this approach uses webpack directly.
- With [ESBuild](https://esbuild.github.io/) - fast and does some transpiling but [doesn't support ES5/IE11](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/203)
- With [Rollup](https://www.rollupjs.org/guide/en/) - similar to ESBuild, node rather than Go based, doesn't have the big speed benefits
- With [Webpack](https://webpack.js.org/) - rather than the old approach of using Webpacker as a opinionated wrapper around webpack, this approach uses webpack directly.
3. [Shakapacker](https://github.com/shakacode/shakapacker) - the "official" community maintained fork of Webpacker 6 RC. Requires upgrading current install since breaking changes happened between Webpacker 5 & 6
4. [Vite](https://vite-ruby.netlify.app/) - Webpack alternative

2
docs/adr/adr-016-hotwire.md

@ -14,4 +14,4 @@ For **Stimulus** we were able to do this and are continuing to use it. This is a
- Adding the StimulusJS NPM package path to our [webpack config](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/blob/main/webpack.config.js#L23) rules to be transpiled
- Adding the required Babel plugins to our [Babel config](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/blob/main/babel.config.js#L34)
For **Turbo** the same approach was attempted but proved [unsuccessful](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/430). As a result we decided to [remove Turbo](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/406) until we can drop support for Internet Explorer. This does have a perceptible impact on UX/speed but provides the most browser compatibility.
For **Turbo** the same approach was attempted but proved [unsuccessful](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/430). As a result we decided to [remove Turbo](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/406) until we can drop support for Internet Explorer. This does have a perceptible impact on UX/speed but provides the most browser compatibility.

3
docs/adr/adr-018-form-setup.md

@ -18,7 +18,8 @@ The amount of application context needed to make it work is what ultimately drov
Instead the setup section is now composed of coded Ruby class in `app/models/form/setup`.
It still has all the same components as before:
- Section
- Section
- Subsection
- Pages
- Questions

1
docs/adr/adr-019-form-end-dates.md

@ -12,6 +12,7 @@ There might be short extensions to the deadline, so shortly after the last day t
Also, if incorrect data is found during QA process, data providers might be asked to correct it. Once the data has been through its first QA processes and is as present and correct as possible, the ability to edit and delete logs is closed. This is typically in late summer/autumn, but it depends on the statistical analysis.
To accommodate the different end dates, we will now store 3 different dates on the form definition:
- Submission deadline (submission_deadline) - this is the date displayed at the top of a completed log in lettings and sales - "You can review and make changes to this log until 9 June 2024.". Nothing happens on this date
- New logs end date (new_logs_end_date) - no new logs for that collection year can be submitted, but logs can be edited
- Edit and delete logs end date (edit_end_date) - logs can no longer be edited or deleted. Completed logs can still be viewed. Materials / references to the collection year are removed.

31
docs/api/v1.json

@ -54,9 +54,7 @@
{
"schema": {
"type": "string",
"enum": [
"application/json"
]
"enum": ["application/json"]
},
"in": "header",
"name": "Accept",
@ -109,9 +107,7 @@
"Invalid Age": {
"value": {
"errors": {
"age1": [
"Tenant age must be between 16 and 120"
]
"age1": ["Tenant age must be between 16 and 120"]
}
}
}
@ -136,9 +132,7 @@
{
"schema": {
"type": "string",
"enum": [
"application/json"
]
"enum": ["application/json"]
},
"in": "header",
"name": "Accept",
@ -177,9 +171,7 @@
{
"schema": {
"type": "string",
"enum": [
"application/json"
]
"enum": ["application/json"]
},
"in": "header",
"name": "Accept",
@ -219,9 +211,7 @@
"reasonable_preference_reason": [
"If reasonable preference is Yes, a reason must be given"
],
"age1": [
"Tenant age must be between 16 and 120"
]
"age1": ["Tenant age must be between 16 and 120"]
}
}
}
@ -247,9 +237,7 @@
"schema": {
"type": "string",
"pattern": "application/json",
"enum": [
"application/json"
]
"enum": ["application/json"]
},
"in": "header",
"name": "Accept",
@ -430,12 +418,7 @@
"sex1": {
"type": "string",
"minLength": 1,
"enum": [
"F: Female",
"M:Male",
"X:Non-binary",
"R:Refused"
],
"enum": ["F: Female", "M:Male", "X:Non-binary", "R:Refused"],
"maxLength": 1
},
"ethnic": {

10
docs/app_api.md

@ -6,10 +6,10 @@ nav_order: 8
In order to use the app as an API, you will need to configure requests to the API as so:
* Configure your request with Basic Auth. Set the username to be the same as `API_USER` and password as the `API_KEY` (`API_USER` and `API_KEY` are environment variables that should be set for the application)
* Check the endpoint you are calling is an action that is `create`, `show` or `update`
* Check you are setting the following request headers:
* `Content-Type = application/json`
* `Action = application/json` N.B. If you use `*/*` instead, the request won't be recognised as an API request`
- Configure your request with Basic Auth. Set the username to be the same as `API_USER` and password as the `API_KEY` (`API_USER` and `API_KEY` are environment variables that should be set for the application)
- Check the endpoint you are calling is an action that is `create`, `show` or `update`
- Check you are setting the following request headers:
- `Content-Type = application/json`
- `Action = application/json` N.B. If you use `*/*` instead, the request won't be recognised as an API request`
Currently only the logs controller is configured to accept and authenticate API requests, when the above API environment variables are set.

8
docs/documentation_website.md

@ -7,13 +7,13 @@ nav_order: 11
The documentation website can be generated and run locally using Jekyll.
1. Change into the `/docs/` directory:\
`cd docs`
`cd docs`
2. Install Jekyll and its dependencies:\
`bundle install`
`bundle install`
3. Start the Jekyll server:\
`bundle exec jekyll serve`
`bundle exec jekyll serve`
4. View the website:\
<http://localhost:4000>
<http://localhost:4000>

2
docs/form/builder.md

@ -115,7 +115,7 @@ Assumptions made by the format:
- For conditionally shown questions, conditions that have been implemented and can be used are:
- Radio question answer option selected matches one of conditional e.g.\
`["answer-options-1-string", "answer-option-3-string"]`
`["answer-options-1-string", "answer-option-3-string"]`
- Numeric question value matches condition e.g. [">2"], ["<7"] or ["== 6"]

4
docs/form/definition.md

@ -16,12 +16,12 @@ The current system is built around a form definition written in JSON. At the top
An example of this might look like the following:
```json
{
{
"form_type": "lettings",
"start_date": "2021-04-01T00:00:00.000+01:00",
"end_date": "2022-07-01T00:00:00.000+01:00",
"sections": {
...
...
}
}
```

4
docs/form/question.md

@ -31,7 +31,7 @@ An example question might look something like this:
}
```
In the above example the the question has the id `postcode_known`.
In the above example the the question has the id `postcode_known`.
The `check_answer_label` contains the text that will be displayed in the label of the table on the check answers page.
@ -85,6 +85,6 @@ The answer the data inputter provides to some questions allows us to infer the v
In the above example the width is an optional attribute and can be provided for text type questions to determine the width of the text box on the page when when the question is displayed to a user (this allows you to match the width of the text box on the page to that of the design for a question).
The above example links to the first example as both of these questions would be on the same page. The `inferred_check_answers_value` is what should be displayed on the check answers page for this question if we infer it. If the value of `postcode_known` was given as `0` (which is a no), as seen in the condition part of `inferred_check_answers_value` then we can infer that the data inputter does not know the postcode and so we would display the value of `Not known` on the check answers page for the postcode.
The above example links to the first example as both of these questions would be on the same page. The `inferred_check_answers_value` is what should be displayed on the check answers page for this question if we infer it. If the value of `postcode_known` was given as `0` (which is a no), as seen in the condition part of `inferred_check_answers_value` then we can infer that the data inputter does not know the postcode and so we would display the value of `Not known` on the check answers page for the postcode.
In the above example the `inferred_answers` refers to a question where we can infer the answer based on the answer of this question. In this case the `la` question can be inferred from the postcode value given by the data inputter as we are able to lookup the local authority based on the postcode given. We then set a property on the lettings log `is_la_inferred` to true to indicate that this is an answer we've inferred.

41
docs/infrastructure.md

@ -7,32 +7,38 @@ nav_order: 5
## Current infrastructure
Currently, there are four environments with infrastructure:
- Meta
- Development (Review Apps)
- Staging
- Production
### Meta
This holds the Terraform “backend” and the ECR(s).
The Terraform “backend” consists of:
- S3 buckets - for storing Terraform state files. One for all non-production environments (including the meta environment itself), and another just for production.
- DynamoDB - for managing access and locking of all state files.
The ECR(s) are:
- core - holds the application Docker images.
- db-migration - holds the Docker images curated to help migrate a DB from PaaS to AWS.
- s3-migration - holds the Docker images curated to help migrate S3 files from PaaS to AWS.
N.B. the migration ECRs may or may not be present, depending on if the Terraform has been configured to create migration infrastructure. The migration infrastructure is only used to help migrate the DB and S3 from PaaS to AWS, so is usually therefore only temporarily present.
N.B. the migration ECRs may or may not be present, depending on if the Terraform has been configured to create migration infrastructure. The migration infrastructure is only used to help migrate the DB and S3 from PaaS to AWS, so is usually therefore only temporarily present.
### Development / Staging / Production
These are the main environments holding the “application” infrastructure.
These are the main environments holding the “application” infrastructure.
Though not exhaustive, each of them will generally contain the following key components:
- ECS Fargate cluster
- RDS (PostgreSQL database)
- ElastiCache (Redis data store)
- S3 buckets
- One for Bulk upload (sometimes also to referred to as the CSV bucket)
- One for CDS Export
- One for Bulk upload (sometimes also to referred to as the CSV bucket)
- One for CDS Export
- VPC
- Private subnets
- Public subnets
@ -43,11 +49,12 @@ Though not exhaustive, each of them will generally contain the following key com
- WAF (Firewall)
### Development / Review Apps
The development environment is used for Review Apps, and has some infrastructure that is created per-review-app and some that is shared by all apps.
The development environment is used for Review Apps, and has some infrastructure that is created per-review-app and some that is shared by all apps.
In general, each review app has its own ECS Fargate cluster and Redis instances (plus any infrastructure to enable this), while the rest is shared.
Where to find the Infrastructure?
The infrastructure is managed as code.
The infrastructure is managed as code.
In the terraform folder of the codebase, there will be dedicated sub-folders for each of the aforementioned environments, where all the infrastructure for them is defined.
## Deployment (Pipeline — Recommended)
@ -64,7 +71,6 @@ To deploy you need to:
6. Post success message on Slack.
7. Tag tickets as ‘Released’ and move tickets to done on JIRA.
## CI/CD
When a commit is made to `main` the following GitHub action jobs are triggered:
@ -88,26 +94,27 @@ After a sucessful deployment a comment will be added to the pull request with th
Once a pull request has been closed the review app infrastructure will be tore down to save on any costs. Should you wish to re-open a closed pull request the review app will be spun up again.
### Review app deployment failures
### Review app deployment failures
One reason a review app deployment might fail is that it is attempting to run migrations which conflict with data in the database. For example you might have introduced a unique constraint, but the database associated with the review app has duplicate data in it that would violate this constraint, and so the migration cannot be run.
## Destroying/recreating infrastructure
Things to watch out for when destroying/creating infra:
- All resources
- The lifecycle meta-argument prevent_destroy will stop you destroying things. Best to set this to false before trying to destroy!
- The lifecycle meta-argument prevent_destroy will stop you destroying things. Best to set this to false before trying to destroy!
- Database
- skip_final_snapshot being false will prevent you from destroying the db without creating a final snapshot.
- skip_final_snapshot being false will prevent you from destroying the db without creating a final snapshot.
- Load Balancer
- Sometimes when creating infra, you may see the error message: failure configuring LB attributes: InvalidConfigurationRequest: Access Denied for bucket: <load-balancer-access-log-bucket-name>. Please check S3bucket permission during a terraform apply. To get around this you may have wait a few minutes and try applying again to ensure everything is fully updated (the error shouldn’t appear on the second attempt). It’s unclear what the exact cause is, but as this is related to infra that enables load balancer access logging, it is suspected there might be a delay with the S3 bucket permissions being realised or the load balancer recognising it can access the bucket.
- Sometimes when creating infra, you may see the error message: failure configuring LB attributes: InvalidConfigurationRequest: Access Denied for bucket: <load-balancer-access-log-bucket-name>. Please check S3bucket permission during a terraform apply. To get around this you may have wait a few minutes and try applying again to ensure everything is fully updated (the error shouldn’t appear on the second attempt). It’s unclear what the exact cause is, but as this is related to infra that enables load balancer access logging, it is suspected there might be a delay with the S3 bucket permissions being realised or the load balancer recognising it can access the bucket.
- S3
- Terraform won’t let you delete buckets that have objects in them.
- Terraform won’t let you delete buckets that have objects in them.
- Secrets
- If you destroy secrets, they will actually be marked as ‘scheduled to delete’ which will take effect after a minimum of 7 days. You can’t recreate secrets with the same name during this period. If you want to destroy immediately, you need to do it from the command line (using your staging developer role, rather than your MHCLG-wide role used to apply Terraform) with this command: aws secretsmanager delete-secret --force-delete-without-recovery --secret-id <secret-arn>. (Note that if a secret is marked as scheduled to delete, you can undo this in the console to make it an ‘active’ secret again.)
- You may need to manually re-enter secret values into Secrets Manager at some point. When you do, just paste the secret value as plain text (don’t enter a key name, or format it as JSON).
- If you destroy secrets, they will actually be marked as ‘scheduled to delete’ which will take effect after a minimum of 7 days. You can’t recreate secrets with the same name during this period. If you want to destroy immediately, you need to do it from the command line (using your staging developer role, rather than your MHCLG-wide role used to apply Terraform) with this command: aws secretsmanager delete-secret --force-delete-without-recovery --secret-id <secret-arn>. (Note that if a secret is marked as scheduled to delete, you can undo this in the console to make it an ‘active’ secret again.)
- You may need to manually re-enter secret values into Secrets Manager at some point. When you do, just paste the secret value as plain text (don’t enter a key name, or format it as JSON).
- ECS
- Sometimes task definitions don’t get deleted. You may need to manually delete them.
- After destroying the db, you’ll need to make sure the ad hoc ECS task which seeds the database gets run in order to set up the database correctly.
- Sometimes task definitions don’t get deleted. You may need to manually delete them.
- After destroying the db, you’ll need to make sure the ad hoc ECS task which seeds the database gets run in order to set up the database correctly.
- SNS
- When creating an email subscription in an environment, Terraform will look up the email to use as the subscription endpoint from Secrets Manager. If you haven’t already created this (e.g. by running terraform apply -target="module.monitoring" -var="create_secrets_first=true") then this will lead to the subscription creation erroring, because it can’t retrieve the value of the secret (because it doesn’t exist yet). If this happens, remember you’ll need to go to Secrets Manager in the console and enter the desired email (as plaintext, no quotation marks or anything else required) as the value of the secret (which is most likely called MONITORING_EMAIL). Then run another apply with Terraform and this time it should succeed.
- When creating an email subscription in an environment, Terraform will look up the email to use as the subscription endpoint from Secrets Manager. If you haven’t already created this (e.g. by running terraform apply -target="module.monitoring" -var="create_secrets_first=true") then this will lead to the subscription creation erroring, because it can’t retrieve the value of the secret (because it doesn’t exist yet). If this happens, remember you’ll need to go to Secrets Manager in the console and enter the desired email (as plaintext, no quotation marks or anything else required) as the value of the secret (which is most likely called MONITORING_EMAIL). Then run another apply with Terraform and this time it should succeed.

19
docs/monitoring.md

@ -3,36 +3,46 @@ nav_order: 6
---
# Logs and Debugging
## Logs
Logs can be found in two locations:
- AWS CloudWatch (for general application / infrastructure logging)
- Sentry (for application error logging)
### CloudWatch
The CloudWatch service can be accessed from the AWS Console. You should authenticate onto the infrastructure environment whose logs you want to check.
From CloudWatch, navigate to the desired log group (e.g. for the app task running on ECS) and open the desired log stream, in order to read its log “events”.
Alternatively, you can also navigate to a specific AWS service / resource in question (e.g. ECS tasks), selecting the instance of interest (e.g. a specific ECS task), and finding the “logs” tab (or similar) to view the log “events”.
### Sentry
To access Sentry, ensure you have been added to the MHCLG account.
Generally error logs in Sentry will also be present somewhere in the CloudWatch logs, but they will be easier to assess here (e.g. number of occurrences over a time period). The logs in Sentry are created by the application when it makes Rails.logger.error calls.
## Debugging
### Application infrastructure
For debugging / investigating infrastructure issues you can use the AWS CloudWatch automatic dashboards. (e.g. is there a lack of physical space on the database, how long has the ECS had very high compute usage for etc.)
They can be found in the CloudWatch service on AWS console, by going to dashboards → automatic dashboards, and selecting the desired dashboard (e.g. Elastic Container Service).
They can be found in the CloudWatch service on AWS console, by going to dashboards → automatic dashboards, and selecting the desired dashboard (e.g. Elastic Container Service).
Alternatively, you can also navigate to the AWS resource in question (e.g. RDS database), selecting the instance of interest, and selecting the “monitoring” / ”metrics” tab (or similar), as this can provide alternate useful information also.
### Exec into a container
You can open a terminal directly on a running container / app, in order to run some commands that may help with debugging an issue.
You can open a terminal directly on a running container / app, in order to run some commands that may help with debugging an issue.
To do this, you will need to “exec” into the container.
#### Prerequisites
- AWS CLI
- AWS Session manager plugin Install the Session Manager plugin for the AWS CLI - AWS Systems Manager
- AWS Session manager plugin Install the Session Manager plugin for the AWS CLI - AWS Systems Manager
- AWS access
#### Accessing the rails console
Prerequisite:
Configure AWS auth following the [documentation in the infra repo](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data-infrastructure/blob/main/docs/development_setup.md). This also details how to enter a subshell with suitable AWS credentials.
@ -51,8 +61,9 @@ env=staging
taskArns=$(aws ecs list-tasks --cluster "core-$env-app" --query "taskArns[*]")
aws ecs describe-tasks --cluster "core-$env-app" --tasks "${taskArns[@]}" --query "tasks[*].{arn:taskArn, status:lastStatus, startedAt:startedAt, group:group, image:containers[0].image}" --output text
```
You can then use `aws ecs execute-command --cluster "core-$env-app" --task <taskid> --interactive --command <command>` to run the relevant command on a specific task.
You can then use `aws ecs execute-command --cluster "core-$env-app" --task <taskid> --interactive --command <command>` to run the relevant command on a specific task.
### Database
In order to investigate or look more closely at the database, you can exec into a container as above, and use the rails console to query the database.

238
docs/setup.md

@ -18,87 +18,104 @@ We recommend using [RBenv](https://github.com/rbenv/rbenv) to manage Ruby versio
We recommend using [nvm](https://github.com/nvm-sh/nvm) to manage NodeJS versions.
## Pre-setup installation
1. Install PostgreSQL
macOS:
macOS:
```bash
brew install postgresql
brew services start postgresql
```
```bash
brew install postgresql
brew services start postgresql
```
Linux (Debian):
Linux (Debian):
```bash
sudo apt install -y postgresql postgresql-contrib libpq-dev
sudo systemctl start postgresql
```
```bash
sudo apt install -y postgresql postgresql-contrib libpq-dev
sudo systemctl start postgresql
```
2. Create a Postgres user
```bash
sudo su - postgres -c "createuser <username> -s -P"
```
```bash
sudo su - postgres -c "createuser <username> -s -P"
```
3. Install RBenv and Ruby-build
macOS:
macOS:
```bash
brew install rbenv
rbenv init
mkdir -p ~/.rbenv/plugins
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
```
```bash
brew install rbenv
rbenv init
mkdir -p ~/.rbenv/plugins
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
```
Linux (Debian):
Linux (Debian):
```bash
sudo apt install -y rbenv git
rbenv init
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
mkdir -p ~/.rbenv/plugins
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
```
```bash
sudo apt install -y rbenv git
rbenv init
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
mkdir -p ~/.rbenv/plugins
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
```
4. Install Ruby and Bundler
```bash
rbenv install 3.1.4
rbenv global 3.1.4
source ~/.bashrc
gem install bundler
```
```bash
rbenv install 3.1.4
rbenv global 3.1.4
source ~/.bashrc
gem install bundler
```
5. Install JavaScript dependencies
Note that we currently use node v16, which is no longer the latest LTS version so you will need to specify the version number when installing
macOS (using nvm):
macOS (using nvm):
```bash
nvm install 16
nvm use 16
brew install yarn
```
Linux (Debian):
Linux (Debian):
```bash
curl -sL https://deb.nodesource.com/setup_16.x | sudo bash -
sudo apt -y install nodejs
mkdir -p ~/.npm-packages
npm config set prefix ~/.npm-packages
echo 'NPM_PACKAGES="~/.npm-packages"' >> ~/.bashrc
echo 'export PATH="$PATH:$NPM_PACKAGES/bin"' >> ~/.bashrc
source ~/.bashrc
npm install --location=global yarn
```
6. (For running tests) Install Gecko Driver
Linux (Debian):
```bash
wget https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux64.tar.gz
tar -xvzf geckodriver-v0.31.0-linux64.tar.gz
rm geckodriver-v0.31.0-linux64.tar.gz
chmod +x geckodriver
sudo mv geckodriver /usr/local/bin/
```
```bash
curl -sL https://deb.nodesource.com/setup_16.x | sudo bash -
sudo apt -y install nodejs
mkdir -p ~/.npm-packages
npm config set prefix ~/.npm-packages
echo 'NPM_PACKAGES="~/.npm-packages"' >> ~/.bashrc
echo 'export PATH="$PATH:$NPM_PACKAGES/bin"' >> ~/.bashrc
source ~/.bashrc
npm install --location=global yarn
```
Also ensure you have firefox installed
6. Clone the repo
7. Clone the repo
```bash
git clone https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data.git
```
```bash
git clone https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data.git
```
## Application setup
@ -106,99 +123,102 @@ We recommend using [nvm](https://github.com/nvm-sh/nvm) to manage NodeJS version
2. Install the dependencies:
```bash
bundle install && yarn install
```
```bash
bundle install && yarn install
```
3. Create the database & run migrations:
```bash
bundle exec rake db:create db:migrate
```
```bash
bundle exec rake db:create db:migrate
```
4. Seed the database if required:
```bash
bundle exec rake db:seed
```
```bash
bundle exec rake db:seed
```
## Running Locally
### Application
Start the dev servers
5. Start the dev servers
a. Using Foreman:
a. Using Foreman:
```bash
./bin/dev
```
```bash
./bin/dev
```
b. Individually:
b. Individually:
Rails:
Rails:
```bash
bundle exec rails s
```
```bash
bundle exec rails s
```
JavaScript (for hot reloading):
JavaScript (for hot reloading):
```bash
yarn build --mode=development --watch
```
```bash
yarn build --mode=development --watch
```
If you’re not modifying front end assets you can bundle them as a one off task:
If you’re not modifying front end assets you can bundle them as a one off task:
```bash
yarn build --mode=development
```
```bash
yarn build --mode=development
```
Development mode will target the latest versions of Chrome, Firefox and Safari for transpilation while production mode will target older browsers.
Development mode will target the latest versions of Chrome, Firefox and Safari for transpilation while production mode will target older browsers.
The Rails server will start on <http://localhost:3000>.
The Rails server will start on <http://localhost:3000>.
### Tests
6. Install Gecko Driver
```bash
bundle exec rspec
```
Linux (Debian):
Or to run individual tests / files use your IDE
```bash
wget https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux64.tar.gz
tar -xvzf geckodriver-v0.31.0-linux64.tar.gz
rm geckodriver-v0.31.0-linux64.tar.gz
chmod +x geckodriver
sudo mv geckodriver /usr/local/bin/
```
### Formatting
Running the test suite (front end assets need to be built or server needs to be running):
- `yarn prettier . --write` for scss, yml, md, and json files
- `yarn standard --fix` for js files
```bash
bundle exec rspec
```
Note that these tests assume you have firefox installed.
### Linting
```bash
bundle exec rake lint
```
## Using Docker
1. Build the image:
```bash
docker-compose build
```
```bash
docker-compose build
```
2. Run the database migrations:
```bash
docker-compose run --rm app /bin/bash -c 'rake db:migrate'
```
```bash
docker-compose run --rm app /bin/bash -c 'rake db:migrate'
```
3. Seed the database if required:
```bash
docker-compose run --rm app /bin/bash -c 'rake db:seed'
```
```bash
docker-compose run --rm app /bin/bash -c 'rake db:seed'
```
4. To be able to debug with Pry run the app using:
```bash
docker-compose run --service-ports app
```
```bash
docker-compose run --service-ports app
```
If this is not needed you can run `docker-compose up` as normal
@ -206,6 +226,6 @@ The Rails server will start on <http://localhost:8080>.
5. To run the test suite in docker:
```bash
docker-compose run --rm app /bin/bash -c ' RAILS_ENV=test rspec'
```
```bash
docker-compose run --rm app /bin/bash -c ' RAILS_ENV=test rspec'
```

17
docs/testing.md

@ -32,51 +32,64 @@ bundle exec rake parallel:setup
RAILS_ENV=test bundle exec rake parallel:spec
```
## Factories for Lettings Log, Sales Log, Organisation, and User
## Factories for Lettings Log, Sales Log, Organisation, and User
Each of these factories has nested relationships and callbacks that ensure associated objects are created and linked properly. For instance, creating a `lettings_log` involves creating or associating with a `user`, which in turn is linked to an `organisation`, potentially leading to creating `organisation_rent_periods` and a `data_protection_confirmation`.
This documentation outlines the objects that are created and/or persisted to the database when using FactoryBot to create or build models for LettingsLog, SalesLog, Organisation, and User. There are other factories, but they are simpler, less frequently used and don't have as much resource hierarchy.
### Lettings Log
Objects Created/Persisted:
- **User**: The `assigned_to` user is created.
- **Organisation**: The `assigned_to` user’s organisation created by `User` factory.
- **DataProtectionConfirmation**: If `organisation` does not have DSA signed, `DataProtectionConfirmation` gets created with `assigned_to` user as a `data_protection_officer`
- **OrganisationRentPeriod**: If `log.period` is present and the `managing_organisation` does not have an `OrganisationRentPeriod` for that period, a new `OrganisationRentPeriod` is created and associated with `managing_organisation`.
Example Usage:
```
let(:lettings_log) { create(:lettings_log) }
```
### Sales Log
Objects Created/Persisted:
- **User**: The `assigned_to` user is created.
- **Organisation**: The `assigned_to` user’s organisation created by `User` factory.
- **DataProtectionConfirmation**: If `organisation` does not have DSA signed, `DataProtectionConfirmation` gets created with `assigned_to` user as a `data_protection_officer`
Example Usage:
```
let(:sales_log) { create(:sales_log) }
```
### Organisation
Objects Created/Persisted:
- **OrganisationRentPeriod**: For each rent period in transient attribute `rent_periods`, an `OrganisationRentPeriod` is created.
- **DataProtectionConfirmation**: If `with_dsa` is `true` (default), a `DataProtectionConfirmation` is created with a `data_protection_officer`
- **User**: Data protection officer that signs the data protection confirmation
Example Usage:
```
let(:organisation) { create(:organisation, rent_periods: [1, 2])}
```
### User
Objects Created/Persisted:
- **Organisation**: User’s organisation.
- **DataProtectionConfirmation**: If `organisation` does not have DSA signed, `DataProtectionConfirmation` gets created with this user as a `data_protection_officer`
Example Usage:
```
let(:user) { create(:user) }
```
```

7
lib/tasks/lint.rake

@ -18,5 +18,10 @@ task stylelint: :environment do
sh "yarn stylelint app/frontend/styles"
end
desc "Run Prettier"
task prettier: :environment do
sh "yarn prettier . --check"
end
desc "Run all the linters"
task lint: %i[rubocop erblint standard stylelint]
task lint: %i[rubocop erblint standard stylelint prettier]

5
package.json

@ -36,9 +36,10 @@
"version": "0.1.0",
"devDependencies": {
"are-you-es5": "^2.1.2",
"prettier": "3.3.3",
"standard": "^17.0.0",
"stylelint": "^15.10.1",
"stylelint-config-gds": "^0.2.0"
"stylelint": "^16.8.2",
"stylelint-config-gds": "^2.0.0"
},
"browserslist": {
"production": [

88
spec/fixtures/forms/2021_2022.json vendored

@ -338,16 +338,16 @@
}
},
"conditional_for": {
"leftreg": [
1
]
"leftreg": [1]
},
"inferred_check_answers_value": [{
"condition": {
"armedforces": 3
},
"value": "Prefers not to say"
}]
"inferred_check_answers_value": [
{
"condition": {
"armedforces": 3
},
"value": "Prefers not to say"
}
]
},
"leftreg": {
"header": "Are they still serving?",
@ -512,9 +512,7 @@
}
},
"conditional_for": {
"postcode_full": [
1
]
"postcode_full": [1]
},
"hidden_in_check_answers": true
},
@ -530,12 +528,14 @@
"is_la_inferred": true
}
},
"inferred_check_answers_value": [{
"condition": {
"postcode_known": 0
},
"value": "Not known"
}]
"inferred_check_answers_value": [
{
"condition": {
"postcode_known": 0
},
"value": "Not known"
}
]
}
}
},
@ -769,13 +769,13 @@
"check_answer_label": "Net income soft validation",
"hidden_in_check_answers": {
"depends_on": [
{
"net_income_value_check": 0
},
{
"net_income_value_check": 1
}
]
{
"net_income_value_check": 0
},
{
"net_income_value_check": 1
}
]
},
"header": "Are you sure this is correct?",
"type": "interruption_screen",
@ -789,7 +789,11 @@
}
}
},
"interruption_screen_question_ids": ["ecstat1", "incfreq", "earnings"]
"interruption_screen_question_ids": [
"ecstat1",
"incfreq",
"earnings"
]
},
"net_income_uc_proportion": {
"questions": {
@ -838,9 +842,7 @@
}
},
"conditional_for": {
"conditional_question": [
0
]
"conditional_question": [0]
}
},
"conditional_question": {
@ -932,12 +934,7 @@
"min": 0,
"step": 0.01,
"width": 4,
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge"
},
"scharge": {
@ -948,12 +945,7 @@
"min": 0,
"step": 0.01,
"width": 4,
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge"
},
"pscharge": {
@ -964,12 +956,7 @@
"min": 0,
"step": 0.01,
"width": 4,
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge"
},
"supcharg": {
@ -981,12 +968,7 @@
"max": 300,
"step": 0.01,
"width": 4,
"fields-to-add": [
"brent",
"scharge",
"pscharge",
"supcharg"
],
"fields-to-add": ["brent", "scharge", "pscharge", "supcharg"],
"result-field": "tcharge"
},
"tcharge": {

4
spec/fixtures/forms/2022_2023.json vendored

@ -41,9 +41,7 @@
}
}
},
"depends_on": [
false
]
"depends_on": [false]
}
},
"depends_on": [

4583
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save