fix: Produktions-Crash durch TypeORM-synchronize beheben
Build and Push Multi-Platform Images / build-and-push (push) Successful in 44s
Build and Push Multi-Platform Images / build-and-push (push) Successful in 44s
NODE_ENV=production deaktiviert synchronize (zerstörerischer ADD/DROP-COLUMN- Churn auf MariaDB, der die 8126-Byte-Zeilengröße sprengte) und aktiviert migrationsRun. Neue data-source.ts als einzige Konfigquelle (Laufzeit + CLI), Migrations-Workflow (generate/run/revert) inkl. dotenv ergänzt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Generated
+16
-3
@@ -24,6 +24,7 @@
|
||||
"axios": "^1.14.0",
|
||||
"basic-ftp": "^5.2.1",
|
||||
"chokidar": "^4.0.3",
|
||||
"dotenv": "^17.4.2",
|
||||
"form-data": "^4.0.5",
|
||||
"imapflow": "^1.3.2",
|
||||
"jsqr": "^1.4.0",
|
||||
@@ -3023,6 +3024,18 @@
|
||||
"rxjs": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/config/node_modules/dotenv": {
|
||||
"version": "17.2.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
||||
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/core": {
|
||||
"version": "11.1.17",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.17.tgz",
|
||||
@@ -6291,9 +6304,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.2.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
||||
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
|
||||
"version": "17.4.2",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
|
||||
"integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
"typeorm": "typeorm-ts-node-commonjs -d ./src/database/data-source.ts",
|
||||
"migration:generate": "npm run typeorm -- migration:generate",
|
||||
"migration:run": "npm run typeorm -- migration:run",
|
||||
"migration:revert": "npm run typeorm -- migration:revert"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^11.0.1",
|
||||
@@ -35,6 +39,7 @@
|
||||
"axios": "^1.14.0",
|
||||
"basic-ftp": "^5.2.1",
|
||||
"chokidar": "^4.0.3",
|
||||
"dotenv": "^17.4.2",
|
||||
"form-data": "^4.0.5",
|
||||
"imapflow": "^1.3.2",
|
||||
"jsqr": "^1.4.0",
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import 'reflect-metadata';
|
||||
import { join } from 'path';
|
||||
import { config as loadEnv } from 'dotenv';
|
||||
import { DataSource, DataSourceOptions } from 'typeorm';
|
||||
import {
|
||||
Client,
|
||||
DocumentType,
|
||||
DocumentField,
|
||||
Task,
|
||||
Postprocessing,
|
||||
PostprocessingAction,
|
||||
PostprocessingLog,
|
||||
ExportTarget,
|
||||
Setting,
|
||||
Kontonummer,
|
||||
Document,
|
||||
UserClient,
|
||||
Email,
|
||||
Attachment,
|
||||
Content,
|
||||
ApiKey,
|
||||
CorrespondentSetting,
|
||||
BarcodeTemplate,
|
||||
InboxDocument,
|
||||
InboxPostprocessingAction,
|
||||
CorrespondentEmailMapping,
|
||||
UserSettings,
|
||||
LabelPrintJob,
|
||||
} from './entities';
|
||||
|
||||
// CLI-Kontext: .env laden (Laufzeit im Container liefert die Variablen via Docker,
|
||||
// dotenv ist dort ein No-Op). dotenv überschreibt bereits gesetzte Variablen nicht.
|
||||
loadEnv();
|
||||
loadEnv({ path: join(process.cwd(), '..', '.env') });
|
||||
|
||||
export const entities = [
|
||||
Client,
|
||||
DocumentType,
|
||||
DocumentField,
|
||||
Task,
|
||||
Postprocessing,
|
||||
PostprocessingAction,
|
||||
PostprocessingLog,
|
||||
ExportTarget,
|
||||
Setting,
|
||||
Kontonummer,
|
||||
Document,
|
||||
UserClient,
|
||||
Email,
|
||||
Attachment,
|
||||
Content,
|
||||
ApiKey,
|
||||
CorrespondentSetting,
|
||||
BarcodeTemplate,
|
||||
InboxDocument,
|
||||
InboxPostprocessingAction,
|
||||
CorrespondentEmailMapping,
|
||||
UserSettings,
|
||||
LabelPrintJob,
|
||||
];
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
export const dataSourceOptions: DataSourceOptions = {
|
||||
type: 'mysql',
|
||||
host: process.env.DB_HOST ?? 'localhost',
|
||||
port: Number(process.env.DB_PORT ?? 3306),
|
||||
username: process.env.DB_USERNAME ?? 'root',
|
||||
password: process.env.DB_PASSWORD ?? '',
|
||||
database: process.env.DB_DATABASE ?? 'paperlessadd',
|
||||
charset: 'utf8mb4',
|
||||
entities,
|
||||
migrations: [join(__dirname, 'migrations', '*.{ts,js}')],
|
||||
// In Produktion: kein synchronize (zerstörerischer ALTER-Churn), Migrationen
|
||||
// werden beim Start automatisch ausgeführt. In Dev: synchronize wie bisher.
|
||||
synchronize: !isProduction,
|
||||
migrationsRun: isProduction,
|
||||
};
|
||||
|
||||
// Wird von der TypeORM-CLI verwendet (migration:generate / :run / :revert).
|
||||
export default new DataSource(dataSourceOptions);
|
||||
@@ -1,75 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import {
|
||||
Client,
|
||||
DocumentType,
|
||||
DocumentField,
|
||||
Task,
|
||||
Postprocessing,
|
||||
PostprocessingAction,
|
||||
PostprocessingLog,
|
||||
ExportTarget,
|
||||
Setting,
|
||||
Kontonummer,
|
||||
Document,
|
||||
UserClient,
|
||||
Email,
|
||||
Attachment,
|
||||
Content,
|
||||
ApiKey,
|
||||
CorrespondentSetting,
|
||||
BarcodeTemplate,
|
||||
InboxDocument,
|
||||
InboxPostprocessingAction,
|
||||
CorrespondentEmailMapping,
|
||||
UserSettings,
|
||||
LabelPrintJob,
|
||||
} from './entities';
|
||||
|
||||
const entities = [
|
||||
Client,
|
||||
DocumentType,
|
||||
DocumentField,
|
||||
Task,
|
||||
Postprocessing,
|
||||
PostprocessingAction,
|
||||
PostprocessingLog,
|
||||
ExportTarget,
|
||||
Setting,
|
||||
Kontonummer,
|
||||
Document,
|
||||
UserClient,
|
||||
Email,
|
||||
Attachment,
|
||||
Content,
|
||||
ApiKey,
|
||||
CorrespondentSetting,
|
||||
BarcodeTemplate,
|
||||
InboxDocument,
|
||||
InboxPostprocessingAction,
|
||||
CorrespondentEmailMapping,
|
||||
UserSettings,
|
||||
LabelPrintJob,
|
||||
];
|
||||
import { dataSourceOptions, entities } from './data-source';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: (config: ConfigService) => ({
|
||||
type: 'mysql' as const,
|
||||
host: config.get<string>('DB_HOST', 'localhost'),
|
||||
port: config.get<number>('DB_PORT', 3306),
|
||||
username: config.get<string>('DB_USERNAME', 'root'),
|
||||
password: config.get<string>('DB_PASSWORD', ''),
|
||||
database: config.get<string>('DB_DATABASE', 'paperlessadd'),
|
||||
entities,
|
||||
synchronize: config.get<string>('NODE_ENV') !== 'production',
|
||||
charset: 'utf8mb4',
|
||||
}),
|
||||
}),
|
||||
// Eine einzige Konfigurationsquelle (data-source.ts), geteilt zwischen
|
||||
// NestJS-Laufzeit und TypeORM-CLI (Migrationen).
|
||||
TypeOrmModule.forRoot(dataSourceOptions),
|
||||
TypeOrmModule.forFeature(entities),
|
||||
],
|
||||
exports: [TypeOrmModule],
|
||||
|
||||
Reference in New Issue
Block a user