Добавление базы данных Postgres в проект и запуск миграций через Flyway для NestJS-mod приложения
База данных будет подниматься через Docker Compose.
Миграции пишутся вручную и запускаются через Flyway мигратор.
Приложение имеет свой логин и пароль, который отличается от рутового.
Конфигурации для Docker Compose и Flyway генерируются через запуск NestJS-mod в режиме инфраструктуры.
1. Устанавливаем пакет для генерации Docker Compose и Flyway файлов
Команды
# Install all need dependencies
npm i --save @nestjs-mod/docker-compose @nestjs-mod/flyway
# Install all need dev-dependencies
npm i --save-dev node-flywaydb@3.0.7
Вывод консоли
$ npm i --save @nestjs-mod/docker-compose @nestjs-mod/flyway
added 41 packages, and audited 2484 packages in 23s
299 packages are looking for funding
run `npm fund` for details
14 vulnerabilities (4 moderate, 10 high)
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
$ npm i --save-dev node-flywaydb@3.0.7
added 15 packages, and audited 2499 packages in 6s
300 packages are looking for funding
run `npm fund` for details
16 vulnerabilities (6 moderate, 10 high)
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
2. Добавляем инфраструктурные модули в серверный код
Они будут использованны для генерации дополнительных файлов и скриптов.
Обновленный файл apps/server/src/main.ts
import { DefaultNestApplicationInitializer, DefaultNestApplicationListener, InfrastructureMarkdownReportGenerator, PACKAGE_JSON_FILE, ProjectUtils, bootstrapNestApplication, isInfrastructureMode } from '@nestjs-mod/common';
import { DOCKER_COMPOSE_FILE, DockerCompose, DockerComposePostgreSQL } from '@nestjs-mod/docker-compose'; // <--
import { FLYWAY_JS_CONFIG_FILE, Flyway } from '@nestjs-mod/flyway'; // <--
import { NestjsPinoLoggerModule } from '@nestjs-mod/pino';
import { ECOSYSTEM_CONFIG_FILE, Pm2 } from '@nestjs-mod/pm2';
import { TerminusHealthCheckModule } from '@nestjs-mod/terminus';
import { MemoryHealthIndicator } from '@nestjs/terminus';
import { join } from 'path';
import { AppModule } from './app/app.module';
const appFeatureName = 'app'; // <--
const rootFolder = join(__dirname, '..', '..', '..');
const appFolder = join(rootFolder, 'apps', 'server');
bootstrapNestApplication({
modules: {
system: [
ProjectUtils.forRoot({
staticConfiguration: {
applicationPackageJsonFile: join(appFolder, PACKAGE_JSON_FILE),
packageJsonFile: join(rootFolder, PACKAGE_JSON_FILE),
envFile: join(rootFolder, '.env'),
},
}),
DefaultNestApplicationInitializer.forRoot({
staticConfiguration: { bufferLogs: true },
}),
NestjsPinoLoggerModule.forRoot(),
TerminusHealthCheckModule.forRootAsync({
configurationFactory: (memoryHealthIndicator: MemoryHealthIndicator) => ({
standardHealthIndicators: [
{
name: 'memory_heap',
check: () => memoryHealthIndicator.checkHeap('memory_heap', 150 * 1024 * 1024),
},
],
}),
inject: [MemoryHealthIndicator],
}),
DefaultNestApplicationListener.forRoot({
staticConfiguration: {
// When running in infrastructure mode, the backend server does not start.
mode: isInfrastructureMode() ? 'silent' : 'listen',
},
}),
],
feature: [AppModule.forRoot()],
infrastructure: [
InfrastructureMarkdownReportGenerator.forRoot({
staticConfiguration: {
markdownFile: join(appFolder, 'INFRASTRUCTURE.MD'),
skipEmptySettings: true,
},
}),
Pm2.forRoot({
configuration: {
ecosystemConfigFile: join(rootFolder, ECOSYSTEM_CONFIG_FILE),
applicationScriptFile: join('dist/apps/server/main.js'),
},
}),
DockerCompose.forRoot({
// <--
configuration: {
dockerComposeFileVersion: '3',
dockerComposeFile: join(appFolder, DOCKER_COMPOSE_FILE),
},
}),
DockerComposePostgreSQL.forRoot(), // <--
DockerComposePostgreSQL.forFeature({
// <--
featureModuleName: appFeatureName,
}),
Flyway.forRoot({
// <--
staticConfiguration: {
featureName: appFeatureName,
migrationsFolder: join(appFolder, 'src', 'migrations'),
configFile: join(rootFolder, FLYWAY_JS_CONFIG_FILE),
},
}),
],
},
});
3. Создаем документацию по проекту и параллельно создаем дополнительный код и скрипты для Docker Compose и Flyway
Команды
# Build all applications and library
npm run build
# Generate markdown report
npm run docs:infrastructure
Вывод консоли
$ npm run build
> @nestjs-mod-fullstack/source@0.0.0 build
> npm run generate && npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=build --skip-nx-cache=true
> @nestjs-mod-fullstack/source@0.0.0 generate
> ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix
NX Successfully ran target generate for 0 projects (29ms)
> @nestjs-mod-fullstack/source@0.0.0 make-ts-list
> ./node_modules/.bin/rucken make-ts-list
> @nestjs-mod-fullstack/source@0.0.0 lint:fix
> npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix
> @nestjs-mod-fullstack/source@0.0.0 tsc:lint
> ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json
✔ nx run server-e2e:lint [existing outputs match the cache, left as is]
✔ nx run server:lint (1s)
✔ nx run client:lint (1s)
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— ————————————————————————————————————————————————
NX Successfully ran target lint for 3 projects (1s)
With additional flags:
--fix=true
Nx read the output from the cache instead of running the command for 1 out of 3 tasks.
> @nestjs-mod-fullstack/source@0.0.0 tsc:lint
> ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json
✔ nx run server:build:production (3s)
✔ nx run client:build:production (15s)
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
NX Successfully ran target build for 2 projects (15s)
$ npm run docs:infrastructure
> @nestjs-mod-fullstack/source@0.0.0 docs:infrastructure
> export NESTJS_MODE=infrastructure && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=start --parallel=1
NX Running target start for project server:
- server
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> nx run server:start
> node dist/apps/server/main.js
[22:07:23.987] INFO (491733): Starting Nest application...
context: "NestFactory"
[22:07:23.987] INFO (491733): DefaultNestApp dependencies initialized
context: "InstanceLoader"
[22:07:23.987] INFO (491733): ProjectUtilsSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.987] INFO (491733): DefaultNestApplicationInitializerSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.987] INFO (491733): DefaultNestApplicationInitializerShared dependencies initialized
context: "InstanceLoader"
[22:07:23.987] INFO (491733): NestjsPinoLoggerModuleSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.987] INFO (491733): NestjsPinoLoggerModuleShared dependencies initialized
context: "InstanceLoader"
[22:07:23.987] INFO (491733): TerminusHealthCheckModuleSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.987] INFO (491733): DefaultNestApplicationListenerSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.987] INFO (491733): DefaultNestApplicationListenerShared dependencies initialized
context: "InstanceLoader"
[22:07:23.987] INFO (491733): AppModuleSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): AppModuleShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): InfrastructureMarkdownReportGeneratorSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): Pm2Settings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): Pm2Shared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): ProjectUtils dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerComposeSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): ProjectUtils dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerComposePostgreSQLSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerCompose dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerComposePostgreSQL dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerComposePostgreSQLSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerComposePostgreSQLShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): FlywaySettings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): FlywayShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): InfrastructureMarkdownReportGeneratorSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): ProjectUtils dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): InfrastructureMarkdownReportStorage dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): InfrastructureMarkdownReportStorageSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): ProjectUtils dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerCompose dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): FlywaySettings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): FlywayShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): ProjectUtils dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DefaultNestApplicationListenerSettings dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DefaultNestApplicationListenerShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerComposeShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): InfrastructureMarkdownReportStorageShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): AppModule dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): ProjectUtils dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DefaultNestApplicationInitializer dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DefaultNestApplicationListener dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): InfrastructureMarkdownReportGenerator dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerComposePostgreSQL dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): Flyway dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DefaultNestApplicationListener dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): NestjsPinoLoggerModule dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): TerminusModule dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): TerminusModule dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): ProjectUtilsShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): InfrastructureMarkdownReportGeneratorShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): Pm2 dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerCompose dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerComposePostgreSQL dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): InfrastructureMarkdownReportGeneratorShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): Flyway dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): InfrastructureMarkdownReportGenerator dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): LoggerModule dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): DockerComposePostgreSQLShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): TerminusHealthCheckModuleShared dependencies initialized
context: "InstanceLoader"
[22:07:23.988] INFO (491733): TerminusHealthCheckModule dependencies initialized
context: "InstanceLoader"
[22:07:23.996] INFO (491733): TerminusHealthCheckController {/health}:
context: "RoutesResolver"
[22:07:23.997] INFO (491733): Mapped {/health, GET} route
context: "RouterExplorer"
[22:07:23.997] INFO (491733): AppController {/}:
context: "RoutesResolver"
[22:07:23.997] INFO (491733): Mapped {/, GET} route
context: "RouterExplorer"
[22:07:24.010] DEBUG (491733):
0: "SERVER_ROOT_DATABASE_URL: Description='Connection string for PostgreSQL with root credentials (example: postgres://postgres:postgres_password@localhost:5432/postgres?schema=public, username must be \"postgres\")', Original Name='rootDatabaseUrl'"
1: "SERVER_PORT: Description='The port on which to run the server.', Default='3000', Original Name='port'"
2: "SERVER_HOSTNAME: Description='Hostname on which to listen for incoming packets.', Original Name='hostname'"
3: "SERVER_APP_DATABASE_URL: Description='Connection string for PostgreSQL with module credentials (example: postgres://feat:feat_password@localhost:5432/feat?schema=public)', Original Name='databaseUrl'"
context: "All application environments"
[22:07:24.027] INFO (491733): Nest application successfully started
context: "NestApplication"
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
NX Successfully ran target start for project server
4. Заполняем новые переменные окружения
После запуска серверного приложения в режиме инфраструктуы в файле переменных окружения появятся дополнительные переменные, примеры значений можно посмотреть в отчете по инфраструктуре apps/server/INFRASTRUCTURE.MD
.
Обновленный файл .env
SERVER_PORT=3000
SERVER_ROOT_DATABASE_URL=postgres://postgres:postgres_password@localhost:5432/postgres?schema=public
SERVER_APP_DATABASE_URL=postgres://app:app_password@localhost:5432/app?schema=public
# server-postgre-sql (generated)
SERVER_POSTGRE_SQL_POSTGRESQL_USERNAME=postgres
SERVER_POSTGRE_SQL_POSTGRESQL_PASSWORD=postgres_password
SERVER_POSTGRE_SQL_POSTGRESQL_DATABASE=postgres