feat: Docker Compose deployment + auto migration on startup

- docker-compose.yml: 移除 MySQL 容器,连宿主机 MySQL
- main.ts: 启动前通过独立 DataSource 执行 runMigrations
- migration-runner.ts: 独立 migration 执行器
- app.module.ts: TypeORM 配置增加 migrations
- 修复 InitialSchema 中 room_expenses 和 financial_operations 重复索引
This commit is contained in:
2026-07-20 12:43:13 +08:00
parent 4c2192d85e
commit 990c0c16e6
5 changed files with 33 additions and 8 deletions

View File

@@ -50,6 +50,8 @@ import {
FinancialOperation, FinancialOperation,
} from './entities'; } from './entities';
import { AuthModule } from './auth/auth.module'; import { AuthModule } from './auth/auth.module';
import { InitialSchema1784520727860 } from './migrations/1784520727860-InitialSchema';
const allMigrations = [InitialSchema1784520727860];
import { AuthorizationModule } from './authorization'; import { AuthorizationModule } from './authorization';
import { RbacModule } from './rbac/rbac.module'; import { RbacModule } from './rbac/rbac.module';
import { StudentsModule } from './students/students.module'; import { StudentsModule } from './students/students.module';
@@ -158,6 +160,7 @@ import { IntegrationConfigModule } from './integration/config/config.module';
password: config.get<string>('DB_PASSWORD', ''), password: config.get<string>('DB_PASSWORD', ''),
database: config.get<string>('DB_DATABASE', 'dorm_billing'), database: config.get<string>('DB_DATABASE', 'dorm_billing'),
entities: allEntities, entities: allEntities,
migrations: allMigrations,
synchronize: config.get('DB_SYNCHRONIZE', 'true') !== 'false', synchronize: config.get('DB_SYNCHRONIZE', 'true') !== 'false',
charset: 'utf8mb4', charset: 'utf8mb4',
}; };
@@ -165,6 +168,7 @@ import { IntegrationConfigModule } from './integration/config/config.module';
return { return {
type: 'better-sqlite3' as const, type: 'better-sqlite3' as const,
database: config.get<string>('DB_DATABASE', 'dorm_billing.db'), database: config.get<string>('DB_DATABASE', 'dorm_billing.db'),
migrations: allMigrations,
entities: allEntities, entities: allEntities,
synchronize: config.get('DB_SYNCHRONIZE', 'true') !== 'false', synchronize: config.get('DB_SYNCHRONIZE', 'true') !== 'false',
}; };

View File

@@ -1,15 +1,14 @@
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common'; import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { DataSource } from 'typeorm'; import { runMigrationsOnStartup } from './migration-runner';
async function bootstrap() { async function bootstrap() {
await runMigrationsOnStartup();
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('api'); app.setGlobalPrefix('api');
app.enableCors(); app.enableCors();
const dataSource = app.get(DataSource);
await dataSource.runMigrations();
console.log('Migrations OK');
await app.listen(process.env.PORT ?? 3000); await app.listen(process.env.PORT ?? 3000);
console.log(`Server running on http://localhost:${process.env.PORT ?? 3000}`); console.log(`Server running on http://localhost:${process.env.PORT ?? 3000}`);
} }

View File

@@ -0,0 +1,24 @@
import { DataSource } from 'typeorm';
import { InitialSchema1784520727860 } from './migrations/1784520727860-InitialSchema';
import { config } from 'dotenv';
config();
const isMySQL = (process.env.DB_TYPE || 'sqlite') === 'mysql';
export async function runMigrationsOnStartup(): Promise<void> {
const ds = new DataSource({
type: isMySQL ? 'mysql' : 'better-sqlite3',
host: isMySQL ? (process.env.DB_HOST || 'localhost') : undefined,
port: isMySQL ? Number(process.env.DB_PORT || 3306) : undefined,
username: isMySQL ? (process.env.DB_USERNAME || 'root') : undefined,
password: isMySQL ? (process.env.DB_PASSWORD || '') : undefined,
database: process.env.DB_DATABASE || (isMySQL ? 'dorm_billing' : 'dorm_billing.db'),
charset: isMySQL ? 'utf8mb4' : undefined,
migrations: [InitialSchema1784520727860],
});
await ds.initialize();
await ds.runMigrations();
await ds.destroy();
}

View File

@@ -10,7 +10,7 @@ export class InitialSchema1784520727860 implements MigrationInterface {
await queryRunner.query(`CREATE TABLE \`users\` (\`id\` int NOT NULL AUTO_INCREMENT, \`username\` varchar(50) NOT NULL, \`password_hash\` varchar(255) NOT NULL, \`name\` varchar(50) NULL, \`is_active\` tinyint NOT NULL DEFAULT 1, \`last_login_at\` datetime NULL, \`is_archived\` tinyint NOT NULL DEFAULT 0, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`profile\` text NULL, UNIQUE INDEX \`IDX_fe0bb3f6520ee0469504521e71\` (\`username\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`users\` (\`id\` int NOT NULL AUTO_INCREMENT, \`username\` varchar(50) NOT NULL, \`password_hash\` varchar(255) NOT NULL, \`name\` varchar(50) NULL, \`is_active\` tinyint NOT NULL DEFAULT 1, \`last_login_at\` datetime NULL, \`is_archived\` tinyint NOT NULL DEFAULT 0, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`profile\` text NULL, UNIQUE INDEX \`IDX_fe0bb3f6520ee0469504521e71\` (\`username\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`sync_state\` (\`platform\` varchar(20) NOT NULL, \`last_sync_at\` datetime NULL, \`run_id\` varchar(64) NULL, \`running_since\` datetime NULL, PRIMARY KEY (\`platform\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`sync_state\` (\`platform\` varchar(20) NOT NULL, \`last_sync_at\` datetime NULL, \`run_id\` varchar(64) NULL, \`running_since\` datetime NULL, PRIMARY KEY (\`platform\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`sync_logs\` (\`id\` int NOT NULL AUTO_INCREMENT, \`platform\` varchar(20) NOT NULL, \`sync_type\` varchar(20) NOT NULL, \`status\` varchar(20) NOT NULL, \`records_count\` int NOT NULL DEFAULT '0', \`error_message\` text NULL, \`started_at\` datetime NULL, \`finished_at\` datetime NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`sync_logs\` (\`id\` int NOT NULL AUTO_INCREMENT, \`platform\` varchar(20) NOT NULL, \`sync_type\` varchar(20) NOT NULL, \`status\` varchar(20) NOT NULL, \`records_count\` int NOT NULL DEFAULT '0', \`error_message\` text NULL, \`started_at\` datetime NULL, \`finished_at\` datetime NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`room_expenses\` (\`id\` int NOT NULL AUTO_INCREMENT, \`room_id\` int NOT NULL, \`expense_type\` varchar(20) NOT NULL, \`amount\` decimal(10,2) NOT NULL, \`period_start\` date NOT NULL, \`period_end\` date NOT NULL, \`description\` text NULL, \`recorded_by\` int NULL, \`import_key\` varchar(120) NULL, \`status\` varchar(20) NOT NULL DEFAULT 'active', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_050485162d4fe47bd3cfd7dedb\` (\`import_key\`), UNIQUE INDEX \`IDX_050485162d4fe47bd3cfd7dedb\` (\`import_key\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`room_expenses\` (\`id\` int NOT NULL AUTO_INCREMENT, \`room_id\` int NOT NULL, \`expense_type\` varchar(20) NOT NULL, \`amount\` decimal(10,2) NOT NULL, \`period_start\` date NOT NULL, \`period_end\` date NOT NULL, \`description\` text NULL, \`recorded_by\` int NULL, \`import_key\` varchar(120) NULL, \`status\` varchar(20) NOT NULL DEFAULT 'active', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_050485162d4fe47bd3cfd7dedb\` (\`import_key\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`rooms\` (\`id\` int NOT NULL AUTO_INCREMENT, \`room_number\` varchar(20) NOT NULL, \`building\` varchar(50) NULL, \`floor\` int NULL, \`capacity\` int NOT NULL, \`status\` varchar(20) NOT NULL DEFAULT 'available', \`room_type\` varchar(20) NULL, \`rental_category\` varchar(10) NOT NULL DEFAULT 'short', \`monthly_rate\` decimal(10,2) NOT NULL DEFAULT '0.00', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_8f7c6fa4c469bab1a06fe3e49f\` (\`room_number\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`rooms\` (\`id\` int NOT NULL AUTO_INCREMENT, \`room_number\` varchar(20) NOT NULL, \`building\` varchar(50) NULL, \`floor\` int NULL, \`capacity\` int NOT NULL, \`status\` varchar(20) NOT NULL DEFAULT 'available', \`room_type\` varchar(20) NULL, \`rental_category\` varchar(10) NOT NULL DEFAULT 'short', \`monthly_rate\` decimal(10,2) NOT NULL DEFAULT '0.00', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_8f7c6fa4c469bab1a06fe3e49f\` (\`room_number\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`organizations\` (\`id\` int NOT NULL AUTO_INCREMENT, \`public_id\` varchar(36) NOT NULL, \`code\` varchar(50) NOT NULL, \`name\` varchar(100) NOT NULL, \`is_host\` tinyint NOT NULL DEFAULT 0, \`contact_name\` varchar(50) NULL, \`phone\` varchar(30) NULL, \`color\` varchar(20) NULL, \`notes\` text NULL, \`status\` varchar(20) NOT NULL DEFAULT 'active', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_0db5eda192bf60a02bd41931f8\` (\`public_id\`), UNIQUE INDEX \`IDX_7e27c3b62c681fbe3e2322535f\` (\`code\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`organizations\` (\`id\` int NOT NULL AUTO_INCREMENT, \`public_id\` varchar(36) NOT NULL, \`code\` varchar(50) NOT NULL, \`name\` varchar(100) NOT NULL, \`is_host\` tinyint NOT NULL DEFAULT 0, \`contact_name\` varchar(50) NULL, \`phone\` varchar(30) NULL, \`color\` varchar(20) NULL, \`notes\` text NULL, \`status\` varchar(20) NOT NULL DEFAULT 'active', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_0db5eda192bf60a02bd41931f8\` (\`public_id\`), UNIQUE INDEX \`IDX_7e27c3b62c681fbe3e2322535f\` (\`code\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`beds\` (\`id\` int NOT NULL AUTO_INCREMENT, \`room_id\` int NOT NULL, \`bed_number\` varchar(20) NOT NULL, \`status\` varchar(20) NOT NULL DEFAULT 'available', \`notes\` text NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_95e9ba0a907346ef7b0d5ca488\` (\`room_id\`, \`bed_number\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`beds\` (\`id\` int NOT NULL AUTO_INCREMENT, \`room_id\` int NOT NULL, \`bed_number\` varchar(20) NOT NULL, \`status\` varchar(20) NOT NULL DEFAULT 'available', \`notes\` text NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_95e9ba0a907346ef7b0d5ca488\` (\`room_id\`, \`bed_number\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
@@ -28,7 +28,7 @@ export class InitialSchema1784520727860 implements MigrationInterface {
await queryRunner.query(`CREATE TABLE \`operation_logs\` (\`id\` int NOT NULL AUTO_INCREMENT, \`user_id\` int NULL, \`username\` varchar(50) NULL, \`module\` varchar(50) NOT NULL, \`action\` varchar(50) NOT NULL, \`target_id\` int NULL, \`target_type\` varchar(50) NULL, \`detail\` text NULL, \`ip_address\` varchar(50) NULL, \`user_agent\` varchar(500) NULL, \`status\` varchar(20) NULL DEFAULT 'success', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`operation_logs\` (\`id\` int NOT NULL AUTO_INCREMENT, \`user_id\` int NULL, \`username\` varchar(50) NULL, \`module\` varchar(50) NOT NULL, \`action\` varchar(50) NOT NULL, \`target_id\` int NULL, \`target_type\` varchar(50) NULL, \`detail\` text NULL, \`ip_address\` varchar(50) NULL, \`user_agent\` varchar(500) NULL, \`status\` varchar(20) NULL DEFAULT 'success', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`notifications\` (\`id\` int NOT NULL AUTO_INCREMENT, \`recipient_id\` int NOT NULL, \`type\` varchar(30) NOT NULL, \`title\` varchar(200) NOT NULL, \`content\` text NULL, \`link\` varchar(500) NULL, \`is_read\` tinyint NOT NULL DEFAULT 0, \`read_at\` datetime NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`notifications\` (\`id\` int NOT NULL AUTO_INCREMENT, \`recipient_id\` int NOT NULL, \`type\` varchar(30) NOT NULL, \`title\` varchar(200) NOT NULL, \`content\` text NULL, \`link\` varchar(500) NULL, \`is_read\` tinyint NOT NULL DEFAULT 0, \`read_at\` datetime NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`learning_records\` (\`id\` int NOT NULL AUTO_INCREMENT, \`student_id\` int NOT NULL, \`record_date\` date NULL, \`record_type\` varchar(50) NULL, \`content\` text NULL, \`follow_up_method\` varchar(50) NULL, \`next_step\` text NULL, \`status\` varchar(20) NOT NULL DEFAULT 'active', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`learning_records\` (\`id\` int NOT NULL AUTO_INCREMENT, \`student_id\` int NOT NULL, \`record_date\` date NULL, \`record_type\` varchar(50) NULL, \`content\` text NULL, \`follow_up_method\` varchar(50) NULL, \`next_step\` text NULL, \`status\` varchar(20) NOT NULL DEFAULT 'active', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`financial_operations\` (\`id\` int NOT NULL AUTO_INCREMENT, \`operation_id\` varchar(64) NOT NULL, \`type\` varchar(64) NOT NULL, \`status\` varchar(20) NOT NULL DEFAULT 'running', \`result_json\` text NULL, \`error_message\` varchar(500) NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_f15aa4c89aa57366fdba8a84db\` (\`operation_id\`), UNIQUE INDEX \`IDX_f15aa4c89aa57366fdba8a84db\` (\`operation_id\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`financial_operations\` (\`id\` int NOT NULL AUTO_INCREMENT, \`operation_id\` varchar(64) NOT NULL, \`type\` varchar(64) NOT NULL, \`status\` varchar(20) NOT NULL DEFAULT 'running', \`result_json\` text NULL, \`error_message\` varchar(500) NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_f15aa4c89aa57366fdba8a84db\` (\`operation_id\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`expense_types\` (\`id\` int NOT NULL AUTO_INCREMENT, \`code\` varchar(30) NOT NULL, \`name\` varchar(30) NOT NULL, \`category\` varchar(20) NOT NULL DEFAULT 'room', \`sort_order\` int NOT NULL DEFAULT '0', \`enabled\` tinyint NOT NULL DEFAULT 1, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_36eda3eb0f6740ecf2ba906012\` (\`code\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`expense_types\` (\`id\` int NOT NULL AUTO_INCREMENT, \`code\` varchar(30) NOT NULL, \`name\` varchar(30) NOT NULL, \`category\` varchar(20) NOT NULL DEFAULT 'room', \`sort_order\` int NOT NULL DEFAULT '0', \`enabled\` tinyint NOT NULL DEFAULT 1, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), UNIQUE INDEX \`IDX_36eda3eb0f6740ecf2ba906012\` (\`code\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`exam_scores\` (\`id\` int NOT NULL AUTO_INCREMENT, \`student_id\` int NOT NULL, \`enrollment_id\` int NULL, \`exam_type\` varchar(50) NULL, \`exam_name\` varchar(100) NULL, \`subject\` varchar(50) NULL, \`score\` decimal(5,2) NULL, \`class_avg\` decimal(5,2) NULL, \`rank\` int NULL, \`exam_date\` date NULL, \`status\` varchar(20) NOT NULL DEFAULT 'active', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`exam_scores\` (\`id\` int NOT NULL AUTO_INCREMENT, \`student_id\` int NOT NULL, \`enrollment_id\` int NULL, \`exam_type\` varchar(50) NULL, \`exam_name\` varchar(100) NULL, \`subject\` varchar(50) NULL, \`score\` decimal(5,2) NULL, \`class_avg\` decimal(5,2) NULL, \`rank\` int NULL, \`exam_date\` date NULL, \`status\` varchar(20) NOT NULL DEFAULT 'active', \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
await queryRunner.query(`CREATE TABLE \`ding_attendance_raw\` (\`id\` int NOT NULL AUTO_INCREMENT, \`ding_user_id\` varchar(100) NOT NULL, \`user_name\` varchar(100) NOT NULL, \`attendance_date\` date NOT NULL, \`ding_id\` varchar(100) NOT NULL, \`check_in_time\` datetime NULL, \`check_out_time\` datetime NULL, \`attendance_type\` varchar(20) NOT NULL, \`time_result\` varchar(20) NOT NULL, \`location_result\` varchar(20) NULL, \`punch_source\` varchar(40) NULL, \`punch_device_name\` varchar(100) NULL, \`punch_device_id\` varchar(100) NULL, \`match_status\` varchar(20) NOT NULL DEFAULT 'unmatched', \`matched_student_id\` int NULL, \`raw_data\` text NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), INDEX \`IDX_d6680d5150f0bfa47dbc1fe96f\` (\`match_status\`), INDEX \`IDX_088de070f537b15ab7da255e5b\` (\`attendance_date\`), UNIQUE INDEX \`IDX_997849bb04ff69149fcf00a8d3\` (\`ding_id\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); await queryRunner.query(`CREATE TABLE \`ding_attendance_raw\` (\`id\` int NOT NULL AUTO_INCREMENT, \`ding_user_id\` varchar(100) NOT NULL, \`user_name\` varchar(100) NOT NULL, \`attendance_date\` date NOT NULL, \`ding_id\` varchar(100) NOT NULL, \`check_in_time\` datetime NULL, \`check_out_time\` datetime NULL, \`attendance_type\` varchar(20) NOT NULL, \`time_result\` varchar(20) NOT NULL, \`location_result\` varchar(20) NULL, \`punch_source\` varchar(40) NULL, \`punch_device_name\` varchar(100) NULL, \`punch_device_id\` varchar(100) NULL, \`match_status\` varchar(20) NOT NULL DEFAULT 'unmatched', \`matched_student_id\` int NULL, \`raw_data\` text NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), INDEX \`IDX_d6680d5150f0bfa47dbc1fe96f\` (\`match_status\`), INDEX \`IDX_088de070f537b15ab7da255e5b\` (\`attendance_date\`), UNIQUE INDEX \`IDX_997849bb04ff69149fcf00a8d3\` (\`ding_id\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`);
@@ -193,7 +193,6 @@ export class InitialSchema1784520727860 implements MigrationInterface {
await queryRunner.query(`DROP INDEX \`IDX_36eda3eb0f6740ecf2ba906012\` ON \`expense_types\``); await queryRunner.query(`DROP INDEX \`IDX_36eda3eb0f6740ecf2ba906012\` ON \`expense_types\``);
await queryRunner.query(`DROP TABLE \`expense_types\``); await queryRunner.query(`DROP TABLE \`expense_types\``);
await queryRunner.query(`DROP INDEX \`IDX_f15aa4c89aa57366fdba8a84db\` ON \`financial_operations\``); await queryRunner.query(`DROP INDEX \`IDX_f15aa4c89aa57366fdba8a84db\` ON \`financial_operations\``);
await queryRunner.query(`DROP INDEX \`IDX_f15aa4c89aa57366fdba8a84db\` ON \`financial_operations\``);
await queryRunner.query(`DROP TABLE \`financial_operations\``); await queryRunner.query(`DROP TABLE \`financial_operations\``);
await queryRunner.query(`DROP TABLE \`learning_records\``); await queryRunner.query(`DROP TABLE \`learning_records\``);
await queryRunner.query(`DROP TABLE \`notifications\``); await queryRunner.query(`DROP TABLE \`notifications\``);

View File

@@ -1,4 +1,3 @@
version: '3.8'
services: services:
backend: backend: