Skip to content

Commit f089d8c

Browse files
authored
Chore: add database migration tooling and configuration (#330)
* chore: add database migration tooling and configuration * lint: lint fixes * Resolve merge conflict in README.md table of contents * Update integration test configurations: reduce retry counts and adjust wait logic for app and LocalStack readiness * refavtor: integration test wait logic: replace inline wait command with dedicated script * refactor: add attempt logging and container log output for debugging during startup * chore: remove completed migration script The file-upload-status to files migration has already been applied. Remove the script and keep the empty migrations directory for future use. * fix: remove unused @ts-expect-error directives in repository tests * chore: remove temporary collection fallback documentation * fix: update health check URL in wait-for-app script from port 3001 to 3002 * fix(integration): align docker compose and Postman with port 3002 Match integration stack to default PORT and wait-for-app health check.
1 parent b3bfd2f commit f089d8c

15 files changed

Lines changed: 3273 additions & 2109 deletions

Dockerfile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,15 @@ USER node
3333

3434
COPY --from=development /home/node/package*.json ./
3535
COPY --from=development /home/node/.server ./.server/
36+
COPY --from=development /home/node/migrate-mongo-config.cjs ./
37+
COPY --from=development /home/node/migrations ./migrations/
38+
COPY --from=development /home/node/scripts ./scripts/
3639

37-
RUN npm ci --omit=dev
40+
RUN npm ci --omit=dev && \
41+
chmod +x scripts/run-migrations-and-start.sh
3842

3943
ARG PORT
4044
ENV PORT ${PORT}
4145
EXPOSE ${PORT}
4246

43-
CMD [ "npm", "start", "--ignore-scripts" ]
47+
CMD [ "./scripts/run-migrations-and-start.sh" ]

README.md

Lines changed: 84 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,32 @@ API to track form submissions. Currently tracks file submissions only.
44

55
See [docs/](docs/) for documentation.
66

7-
- [forms-submission-api](#forms-submission-api)
8-
- [Requirements](#requirements)
9-
- [Node.js](#nodejs)
10-
- [Local development](#local-development)
11-
- [Setup](#setup)
12-
- [Development](#development)
13-
- [Production](#production)
14-
- [Npm scripts](#npm-scripts)
15-
- [Integration Tests](#integration-tests)
16-
- [Prerequisites](#prerequisites)
17-
- [Running Integration Tests](#running-integration-tests)
18-
- [Quick Start](#quick-start)
19-
- [Manual Step-by-Step Execution](#manual-step-by-step-execution)
20-
- [What the Integration Tests Cover](#what-the-integration-tests-cover)
21-
- [Test Environment Details](#test-environment-details)
22-
- [Test Reports](#test-reports)
23-
- [Troubleshooting](#troubleshooting)
24-
- [Common Issues:](#common-issues)
25-
- [Viewing Logs:](#viewing-logs)
26-
- [API endpoints](#api-endpoints)
27-
- [Docker](#docker)
28-
- [Development image](#development-image)
29-
- [Production image](#production-image)
30-
- [Swagger](#swagger)
31-
- [Licence](#licence)
32-
- [About the licence](#about-the-licence)
7+
- [Requirements](#requirements)
8+
- [Node.js](#nodejs)
9+
- [Local development](#local-development)
10+
- [Setup](#setup)
11+
- [Development](#development)
12+
- [Production](#production)
13+
- [Npm scripts](#npm-scripts)
14+
- [Database Migrations](#database-migrations)
15+
- [Integration Tests](#integration-tests)
16+
- [Prerequisites](#prerequisites)
17+
- [Running Integration Tests](#running-integration-tests)
18+
- [Quick Start](#quick-start)
19+
- [Manual Step-by-Step Execution](#manual-step-by-step-execution)
20+
- [What the Integration Tests Cover](#what-the-integration-tests-cover)
21+
- [Test Environment Details](#test-environment-details)
22+
- [Test Reports](#test-reports)
23+
- [Troubleshooting](#troubleshooting)
24+
- [Common Issues:](#common-issues)
25+
- [Viewing Logs:](#viewing-logs)
26+
- [API endpoints](#api-endpoints)
27+
- [Docker](#docker)
28+
- [Development Image](#development-image)
29+
- [Production Image](#production-image)
30+
- [Swagger](#swagger)
31+
- [Licence](#licence)
32+
- [About the licence](#about-the-licence)
3333

3434
## Requirements
3535

@@ -72,6 +72,8 @@ NO_PROXY=
7272

7373
For proxy options, see https://www.npmjs.com/package/proxy-from-env which is used by https://github.com/TooTallNate/proxy-agents/tree/main/packages/proxy-agent. It's currently supports Hapi Wreck only, e.g. in the JWKS lookup.
7474

75+
4. **Database setup**: See [Database Migrations](#database-migrations) for information on how database migrations work in this project.
76+
7577
### Development
7678

7779
To run the application in `development` mode run:
@@ -189,7 +191,7 @@ When running on the main branch, HTML reports are generated:
189191

190192
#### Common Issues:
191193

192-
1. **Port conflicts**: The tests use ports 3001, 5556, and 27018. Make sure these are available.
194+
1. **Port conflicts**: The tests use ports 3002 (API), 5556, and 27018. Make sure these are available.
193195

194196
2. **Docker resources**: The integration tests require sufficient Docker resources. Increase Docker memory if needed.
195197

@@ -210,6 +212,60 @@ docker compose -f docker-compose.integration-test.yml logs [service_name]
210212

211213
Available services: `mongo_test`, `oidc`, `app_test`, `newman`
212214

215+
### Database Migrations
216+
217+
This project uses [migrate-mongo](https://www.npmjs.com/package/migrate-mongo) to manage database migrations.
218+
219+
#### Production
220+
221+
In production, migrations run automatically when the Docker container starts via the `scripts/run-migrations-and-start.sh` shell script. This script:
222+
223+
1. Runs all pending migrations (`migrate-mongo up`)
224+
2. Starts the application server
225+
3. Logs migration progress to the container output
226+
227+
**No manual intervention is required** - migrations execute automatically on container startup.
228+
229+
#### Local Development
230+
231+
For local development, you have two options:
232+
233+
##### Option 1: Using Docker (Recommended)
234+
235+
Migrations run automatically when using Docker:
236+
237+
```bash
238+
docker compose up --build forms-submission-api
239+
```
240+
241+
This mimics the production environment and runs migrations via the same shell script.
242+
243+
##### Option 2: Manual Migration Commands
244+
245+
To work with migrations manually, you can install migrate-mongo globally:
246+
247+
```bash
248+
npm install -g migrate-mongo
249+
```
250+
251+
Available migration commands:
252+
253+
```bash
254+
# Check migration status
255+
npm run migrate:status
256+
257+
# Run all pending migrations
258+
npm run migrate:up
259+
260+
# Rollback the last migration
261+
npm run migrate:down
262+
263+
# Create a new migration
264+
npx migrate-mongo create <migration-name> -f migrate-mongo-config.cjs
265+
```
266+
267+
**Important**: When running migrations manually, ensure your `.env` file contains the correct `MONGO_URI` and `MONGO_DATABASE` values that match your local MongoDB instance.
268+
213269
## API endpoints
214270

215271
| Endpoint | Description |
@@ -247,7 +303,7 @@ docker build --no-cache --tag forms-submission-api .
247303
Run:
248304

249305
```bash
250-
docker run -e GITHUB_API_TOKEN -p 3001:3001 forms-submission-api
306+
docker run -e GITHUB_API_TOKEN -p 3002:3002 forms-submission-api
251307
```
252308

253309
## Swagger

docker-compose.integration-test.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ services:
1212
interval: 5s
1313
timeout: 30s
1414
start_period: 10s
15-
retries: 30
15+
retries: 12
1616
environment:
1717
MONGO_INITDB_DATABASE: forms-submission-api-test
1818
networks:
@@ -80,19 +80,19 @@ services:
8080
]
8181
interval: 10s
8282
timeout: 10s
83-
retries: 18
84-
start_period: 90s
83+
retries: 12
84+
start_period: 60s
8585

8686
app_test:
8787
build:
8888
context: .
8989
target: production
9090
container_name: forms-submission-api-app-test
9191
ports:
92-
- '3001:3001'
92+
- '3002:3002'
9393
environment:
9494
MONGO_URI: mongodb://mongo_test:27017/forms-submission-api-test?replicaSet=rs0&directConnection=true
95-
PORT: 3001
95+
PORT: 3002
9696
NODE_ENV: production
9797
OIDC_JWKS_URI: 'http://oidc:80/.well-known/openid-configuration/jwks'
9898
OIDC_VERIFY_AUD: 'newman-test-client'
@@ -131,7 +131,7 @@ services:
131131
NEWMAN_CLIENT_SECRET: 'newman-mock-secret'
132132
NEWMAN_SCOPE: 'openid profile email newman-test-client'
133133
NEWMAN_TEST_EMAIL: 'test.email@defra.gov.uk'
134-
API_URL: 'http://app_test:3001'
134+
API_URL: 'http://app_test:3002'
135135
volumes:
136136
- ./test/integration/postman:/etc/newman
137137
- ./newman-reports:/etc/newman/reports

docs/temporary-collection-fallback.md

Lines changed: 0 additions & 51 deletions
This file was deleted.

migrate-mongo-config.cjs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* eslint-disable */
2+
// In this file you can configure migrate-mongo
3+
require('dotenv/config')
4+
5+
const config = {
6+
mongodb: {
7+
// Use environment variables to match the app's configuration
8+
url: process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/',
9+
10+
// Use the same database name as the app
11+
databaseName: process.env.MONGO_DATABASE || 'forms-submission-api',
12+
13+
options: {
14+
// connectTimeoutMS: 3600000, // increase connection timeout to 1 hour
15+
// socketTimeoutMS: 3600000, // increase socket timeout to 1 hour
16+
}
17+
},
18+
19+
// The migrations dir, can be an relative or absolute path. Only edit this when really necessary.
20+
migrationsDir: 'migrations',
21+
22+
// The mongodb collection where the applied changes are stored. Only edit this when really necessary.
23+
changelogCollectionName: 'changelog',
24+
25+
// The mongodb collection where the lock will be created.
26+
lockCollectionName: 'changelog_lock',
27+
28+
// The value in seconds for the TTL index that will be used for the lock. Value of 0 will disable the feature.
29+
lockTtl: 0,
30+
31+
// The file extension to create migrations and search for in migration dir
32+
migrationFileExtension: '.cjs',
33+
34+
// Enable the algorithm to create a checksum of the file contents and use that in the comparison to determine
35+
// if the file should be run. Requires that scripts are coded to be run multiple times.
36+
useFileHash: false,
37+
38+
// Don't change this, unless you know what you're doing
39+
moduleSystem: 'commonjs'
40+
}
41+
42+
module.exports = config

migrations/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)