251205:0000 Just start debug backend/frontend
This commit is contained in:
18
backend/src/config/database.config.ts
Normal file
18
backend/src/config/database.config.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||
import { config } from 'dotenv';
|
||||
|
||||
config();
|
||||
|
||||
export const databaseConfig: TypeOrmModuleOptions = {
|
||||
type: 'mysql',
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: parseInt(process.env.DB_PORT || '3306'),
|
||||
username: process.env.DB_USERNAME || 'root',
|
||||
password: process.env.DB_PASSWORD || 'Center#2025',
|
||||
database: process.env.DB_DATABASE || 'lcbp3_dev',
|
||||
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
|
||||
migrations: [__dirname + '/../database/migrations/*{.ts,.js}'],
|
||||
synchronize: false,
|
||||
logging: process.env.NODE_ENV === 'development',
|
||||
autoLoadEntities: true,
|
||||
};
|
||||
136
backend/src/database/migrations/InitialSchema.ts
Normal file
136
backend/src/database/migrations/InitialSchema.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class InitialSchema1701234567890 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// Organizations
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE organizations (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
organization_code VARCHAR(20) NOT NULL UNIQUE,
|
||||
organization_name VARCHAR(200) NOT NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP NULL,
|
||||
INDEX idx_org_code (organization_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
// Permissions
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE permissions (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
permission_code VARCHAR(50) NOT NULL UNIQUE,
|
||||
description TEXT NULL,
|
||||
resource VARCHAR(50) NOT NULL,
|
||||
action VARCHAR(50) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
// Roles
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE roles (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
role_name VARCHAR(50) NOT NULL UNIQUE,
|
||||
description TEXT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
// Role Permissions
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE role_permissions (
|
||||
role_id INT NOT NULL,
|
||||
permission_id INT NOT NULL,
|
||||
PRIMARY KEY (role_id, permission_id),
|
||||
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
// Users
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE users (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
username VARCHAR(50) NOT NULL UNIQUE,
|
||||
email VARCHAR(100) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
first_name VARCHAR(100) NOT NULL,
|
||||
last_name VARCHAR(100) NOT NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
// User Roles
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE user_roles (
|
||||
user_id INT NOT NULL,
|
||||
role_id INT NOT NULL,
|
||||
PRIMARY KEY (user_id, role_id),
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
// Correspondences
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE correspondences (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
document_number VARCHAR(50) NOT NULL UNIQUE,
|
||||
subject VARCHAR(255) NOT NULL,
|
||||
body TEXT NULL,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
status VARCHAR(50) DEFAULT 'Draft',
|
||||
created_by_id INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (created_by_id) REFERENCES users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
// RFAs
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE rfas (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
rfa_number VARCHAR(50) NOT NULL UNIQUE,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
discipline_code VARCHAR(20) NULL,
|
||||
status VARCHAR(50) DEFAULT 'Draft',
|
||||
created_by_id INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (created_by_id) REFERENCES users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
// Drawings
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE drawings (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
drawing_number VARCHAR(50) NOT NULL UNIQUE,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
drawing_type VARCHAR(50) NOT NULL,
|
||||
revision VARCHAR(10) NOT NULL,
|
||||
status VARCHAR(50) DEFAULT 'Draft',
|
||||
uploaded_by_id INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (uploaded_by_id) REFERENCES users(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS drawings`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS rfas`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS correspondences`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS user_roles`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS users`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS role_permissions`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS roles`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS permissions`);
|
||||
await queryRunner.query(`DROP TABLE IF EXISTS organizations`);
|
||||
}
|
||||
}
|
||||
72
backend/src/database/seeds/organization.seed.ts
Normal file
72
backend/src/database/seeds/organization.seed.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { DataSource } from 'typeorm';
|
||||
import { Organization } from '../../modules/organizations/entities/organization.entity';
|
||||
|
||||
export async function seedOrganizations(dataSource: DataSource) {
|
||||
const repo = dataSource.getRepository(Organization);
|
||||
|
||||
const orgs = [
|
||||
{ organizationCode: 'กทท.', organizationName: 'การท่าเรือแห่งประเทศไทย' },
|
||||
{
|
||||
organizationCode: 'สคฉ.3',
|
||||
organizationName: 'โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3',
|
||||
},
|
||||
{
|
||||
organizationCode: 'สคฉ.3-01',
|
||||
organizationName: 'ตรวจรับพัสดุ ที่ปรึกษาควบคุมงาน',
|
||||
},
|
||||
{
|
||||
organizationCode: 'สคฉ.3-02',
|
||||
organizationName: 'ตรวจรับพัสดุ งานทางทะเล',
|
||||
},
|
||||
{
|
||||
organizationCode: 'สคฉ.3-03',
|
||||
organizationName: 'ตรวจรับพัสดุ อาคารและระบบสาธารณูปโภค',
|
||||
},
|
||||
{
|
||||
organizationCode: 'สคฉ.3-04',
|
||||
organizationName: 'ตรวจรับพัสดุ ตรวจสอบผลกระทบสิ่งแวดล้อม',
|
||||
},
|
||||
{
|
||||
organizationCode: 'สคฉ.3-05',
|
||||
organizationName: 'ตรวจรับพัสดุ เยียวยาการประมง',
|
||||
},
|
||||
{
|
||||
organizationCode: 'สคฉ.3-06',
|
||||
organizationName: 'ตรวจรับพัสดุ งานก่อสร้าง ส่วนที่ 3',
|
||||
},
|
||||
{
|
||||
organizationCode: 'สคฉ.3-07',
|
||||
organizationName: 'ตรวจรับพัสดุ งานก่อสร้าง ส่วนที่ 4',
|
||||
},
|
||||
{
|
||||
organizationCode: 'สคฉ.3-xx',
|
||||
organizationName: 'ตรวจรับพัสดุ ที่ปรึกษาออกแบบ ส่วนที่ 4',
|
||||
},
|
||||
{ organizationCode: 'TEAM', organizationName: 'Designer Consulting Ltd.' },
|
||||
{
|
||||
organizationCode: 'คคง.',
|
||||
organizationName: 'Construction Supervision Ltd.',
|
||||
},
|
||||
{ organizationCode: 'ผรม.1', organizationName: 'Contractor งานทางทะเล' },
|
||||
{ organizationCode: 'ผรม.2', organizationName: 'Contractor งานก่อสร้าง' },
|
||||
{
|
||||
organizationCode: 'ผรม.3',
|
||||
organizationName: 'Contractor งานก่อสร้าง ส่วนที่ 3',
|
||||
},
|
||||
{
|
||||
organizationCode: 'ผรม.4',
|
||||
organizationName: 'Contractor งานก่อสร้าง ส่วนที่ 4',
|
||||
},
|
||||
{ organizationCode: 'EN', organizationName: 'Third Party Environment' },
|
||||
{ organizationCode: 'CAR', organizationName: 'Third Party Fishery Care' },
|
||||
];
|
||||
|
||||
for (const org of orgs) {
|
||||
const exists = await repo.findOneBy({
|
||||
organizationCode: org.organizationCode,
|
||||
});
|
||||
if (!exists) {
|
||||
await repo.save(repo.create(org));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,67 +1,24 @@
|
||||
import { config } from 'dotenv';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { seedWorkflowDefinitions } from '../seeds/workflow-definitions.seed'; // Import ฟังก์ชัน Seed ที่คุณมี
|
||||
// Import Entities ที่เกี่ยวข้อง
|
||||
import { WorkflowDefinition } from '../../modules/workflow-engine/entities/workflow-definition.entity';
|
||||
import { WorkflowHistory } from '../../modules/workflow-engine/entities/workflow-history.entity';
|
||||
import { WorkflowInstance } from '../../modules/workflow-engine/entities/workflow-instance.entity';
|
||||
import { databaseConfig } from '../../config/database.config';
|
||||
import { seedOrganizations } from './organization.seed';
|
||||
import { seedUsers } from './user.seed';
|
||||
|
||||
// โหลด Environment Variables (.env)
|
||||
config();
|
||||
|
||||
const runSeed = async () => {
|
||||
// ตั้งค่าการเชื่อมต่อฐานข้อมูล (ควรตรงกับ docker-compose หรือ .env ของคุณ)
|
||||
const dataSource = new DataSource({
|
||||
type: 'mariadb',
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: parseInt(process.env.DB_PORT || '3306'),
|
||||
username: process.env.DB_USERNAME || 'root',
|
||||
password: process.env.DB_PASSWORD || 'Center#2025',
|
||||
database: process.env.DB_DATABASE || 'lcbp3_dev',
|
||||
// สำคัญ: ต้องใส่ Entities ที่เกี่ยวข้องทั้งหมดเพื่อให้ TypeORM รู้จัก
|
||||
entities: [
|
||||
WorkflowDefinition,
|
||||
WorkflowInstance,
|
||||
WorkflowHistory,
|
||||
// ใส่ Entity อื่นๆ ถ้าจำเป็น หรือใช้ path pattern: __dirname + '/../../modules/**/*.entity{.ts,.js}'
|
||||
],
|
||||
synchronize: false, // ห้ามใช้ true บน Production
|
||||
});
|
||||
async function runSeeds() {
|
||||
const dataSource = new DataSource(databaseConfig as any);
|
||||
await dataSource.initialize();
|
||||
|
||||
try {
|
||||
console.log('🔌 Connecting to database...');
|
||||
await dataSource.initialize();
|
||||
console.log('✅ Database connected.');
|
||||
console.log('🌱 Seeding database...');
|
||||
|
||||
console.log('🌱 Running Seeds...');
|
||||
await seedWorkflowDefinitions(dataSource);
|
||||
console.log('✅ Seeding completed successfully.');
|
||||
await seedOrganizations(dataSource);
|
||||
await seedUsers(dataSource);
|
||||
|
||||
console.log('✅ Seeding completed!');
|
||||
} catch (error) {
|
||||
console.error('❌ Error during seeding:', error);
|
||||
console.error('❌ Seeding failed:', error);
|
||||
} finally {
|
||||
if (dataSource.isInitialized) {
|
||||
await dataSource.destroy();
|
||||
console.log('🔌 Database connection closed.');
|
||||
}
|
||||
await dataSource.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
runSeed();
|
||||
|
||||
/*
|
||||
npx ts-node -r tsconfig-paths/register src/database/run-seed.ts
|
||||
|
||||
**หรือเพิ่มใน `package.json` (แนะนำ):**
|
||||
คุณสามารถเพิ่ม script ใน `package.json` เพื่อให้เรียกใช้ได้ง่ายขึ้นในอนาคต:
|
||||
|
||||
"scripts": {
|
||||
"seed": "ts-node -r tsconfig-paths/register src/database/seeds/run-seed.ts"
|
||||
}
|
||||
|
||||
http://googleusercontent.com/immersive_entry_chip/1
|
||||
|
||||
### 💡 ข้อควรระวัง
|
||||
1. **Environment Variables:** ตรวจสอบให้แน่ใจว่าค่า Config (Host, User, Password) ในไฟล์ `run-seed.ts` หรือ `.env` นั้นถูกต้องและตรงกับ Docker Container ที่กำลังรันอยู่
|
||||
2. **Entities:** หากฟังก์ชัน Seed มีการเรียกใช้ Entity อื่นนอกเหนือจาก `WorkflowDefinition` ต้องนำมาใส่ใน `entities: [...]` ของ `DataSource` ให้ครบ ไม่อย่างนั้นจะเจอ Error `RepositoryNotFoundError`
|
||||
|
||||
*/
|
||||
runSeeds();
|
||||
|
||||
106
backend/src/database/seeds/user.seed.ts
Normal file
106
backend/src/database/seeds/user.seed.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { DataSource } from 'typeorm';
|
||||
import { User } from '../../modules/users/entities/user.entity';
|
||||
import { Role } from '../../modules/auth/entities/role.entity';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
|
||||
export async function seedUsers(dataSource: DataSource) {
|
||||
const userRepo = dataSource.getRepository(User);
|
||||
const roleRepo = dataSource.getRepository(Role);
|
||||
|
||||
// Create Roles
|
||||
const rolesData = [
|
||||
{
|
||||
roleName: 'Superadmin',
|
||||
description:
|
||||
'ผู้ดูแลระบบสูงสุด: สามารถทำทุกอย่างในระบบ, จัดการองค์กร, และจัดการข้อมูลหลักระดับ Global',
|
||||
},
|
||||
{
|
||||
roleName: 'Org Admin',
|
||||
description:
|
||||
'ผู้ดูแลองค์กร: จัดการผู้ใช้ในองค์กร, จัดการบทบาท / สิทธิ์ภายในองค์กร, และดูรายงานขององค์กร',
|
||||
},
|
||||
{
|
||||
roleName: 'Document Control',
|
||||
description:
|
||||
'ควบคุมเอกสารขององค์กร: เพิ่ม / แก้ไข / ลบเอกสาร, และกำหนดสิทธิ์เอกสารภายในองค์กร',
|
||||
},
|
||||
{
|
||||
roleName: 'Editor',
|
||||
description:
|
||||
'ผู้แก้ไขเอกสารขององค์กร: เพิ่ม / แก้ไขเอกสารที่ได้รับมอบหมาย',
|
||||
},
|
||||
{
|
||||
roleName: 'Viewer',
|
||||
description: 'ผู้ดูเอกสารขององค์กร: ดูเอกสารที่มีสิทธิ์เข้าถึงเท่านั้น',
|
||||
},
|
||||
{
|
||||
roleName: 'Project Manager',
|
||||
description:
|
||||
'ผู้จัดการโครงการ: จัดการสมาชิกในโครงการ, สร้าง / จัดการสัญญาในโครงการ, และดูรายงานโครงการ',
|
||||
},
|
||||
{
|
||||
roleName: 'Contract Admin',
|
||||
description:
|
||||
'ผู้ดูแลสัญญา: จัดการสมาชิกในสัญญา, สร้าง / จัดการข้อมูลหลักเฉพาะสัญญา, และอนุมัติเอกสารในสัญญา',
|
||||
},
|
||||
];
|
||||
|
||||
const roleMap = new Map();
|
||||
for (const r of rolesData) {
|
||||
let role = await roleRepo.findOneBy({ roleName: r.roleName });
|
||||
if (!role) {
|
||||
role = await roleRepo.save(roleRepo.create(r));
|
||||
}
|
||||
roleMap.set(r.roleName, role);
|
||||
}
|
||||
|
||||
// Create Users
|
||||
const usersData = [
|
||||
{
|
||||
username: 'superadmin',
|
||||
email: 'superadmin@example.com',
|
||||
firstName: 'Super',
|
||||
lastName: 'Admin',
|
||||
roleName: 'Superadmin',
|
||||
},
|
||||
{
|
||||
username: 'admin',
|
||||
email: 'admin@example.com',
|
||||
firstName: 'Admin',
|
||||
lastName: 'คคง.',
|
||||
roleName: 'Org Admin',
|
||||
},
|
||||
{
|
||||
username: 'editor01',
|
||||
email: 'editor01@example.com',
|
||||
firstName: 'DC',
|
||||
lastName: 'C1',
|
||||
roleName: 'Editor',
|
||||
},
|
||||
{
|
||||
username: 'viewer01',
|
||||
email: 'viewer01@example.com',
|
||||
firstName: 'Viewer',
|
||||
lastName: 'สคฉ.03',
|
||||
roleName: 'Viewer',
|
||||
},
|
||||
];
|
||||
|
||||
const salt = await bcrypt.genSalt();
|
||||
const passwordHash = await bcrypt.hash('password123', salt); // Default password
|
||||
|
||||
for (const u of usersData) {
|
||||
const exists = await userRepo.findOneBy({ username: u.username });
|
||||
if (!exists) {
|
||||
const user = userRepo.create({
|
||||
username: u.username,
|
||||
email: u.email,
|
||||
firstName: u.firstName,
|
||||
lastName: u.lastName,
|
||||
passwordHash,
|
||||
roles: [roleMap.get(u.roleName)],
|
||||
});
|
||||
await userRepo.save(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
backend/src/modules/auth/entities/role.entity.ts
Normal file
45
backend/src/modules/auth/entities/role.entity.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
Entity,
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
ManyToMany,
|
||||
JoinTable,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity('permissions')
|
||||
export class Permission {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: number;
|
||||
|
||||
@Column({ name: 'permission_code', length: 50, unique: true })
|
||||
permissionCode!: string;
|
||||
|
||||
@Column({ name: 'description', type: 'text', nullable: true })
|
||||
description!: string;
|
||||
|
||||
@Column({ name: 'resource', length: 50 })
|
||||
resource!: string;
|
||||
|
||||
@Column({ name: 'action', length: 50 })
|
||||
action!: string;
|
||||
}
|
||||
|
||||
@Entity('roles')
|
||||
export class Role {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: number;
|
||||
|
||||
@Column({ name: 'role_name', length: 50, unique: true })
|
||||
roleName!: string;
|
||||
|
||||
@Column({ name: 'description', type: 'text', nullable: true })
|
||||
description!: string;
|
||||
|
||||
@ManyToMany(() => Permission)
|
||||
@JoinTable({
|
||||
name: 'role_permissions',
|
||||
joinColumn: { name: 'role_id', referencedColumnName: 'id' },
|
||||
inverseJoinColumn: { name: 'permission_id', referencedColumnName: 'id' },
|
||||
})
|
||||
permissions!: Permission[];
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { User } from '../../users/entities/user.entity';
|
||||
|
||||
@Entity('correspondences')
|
||||
export class Correspondence {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: number;
|
||||
|
||||
@Column({ name: 'document_number', length: 50, unique: true })
|
||||
documentNumber!: string;
|
||||
|
||||
@Column({ length: 255 })
|
||||
subject!: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
body!: string;
|
||||
|
||||
@Column({ length: 50 })
|
||||
type!: string;
|
||||
|
||||
@Column({ length: 50, default: 'Draft' })
|
||||
status!: string;
|
||||
|
||||
@Column({ name: 'created_by_id' })
|
||||
createdById!: number;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'created_by_id' })
|
||||
createdBy!: User;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at' })
|
||||
updatedAt!: Date;
|
||||
}
|
||||
44
backend/src/modules/drawings/entities/drawing.entity.ts
Normal file
44
backend/src/modules/drawings/entities/drawing.entity.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import {
|
||||
Entity,
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { User } from '../../users/entities/user.entity';
|
||||
|
||||
@Entity('drawings')
|
||||
export class Drawing {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: number;
|
||||
|
||||
@Column({ name: 'drawing_number', length: 50, unique: true })
|
||||
drawingNumber!: string;
|
||||
|
||||
@Column({ length: 255 })
|
||||
title!: string;
|
||||
|
||||
@Column({ name: 'drawing_type', length: 50 })
|
||||
drawingType!: string;
|
||||
|
||||
@Column({ length: 10 })
|
||||
revision!: string;
|
||||
|
||||
@Column({ length: 50, default: 'Draft' })
|
||||
status!: string;
|
||||
|
||||
@Column({ name: 'uploaded_by_id' })
|
||||
uploadedById!: number;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'uploaded_by_id' })
|
||||
uploadedBy!: User;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at' })
|
||||
updatedAt!: Date;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import {
|
||||
Entity,
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
DeleteDateColumn,
|
||||
Index,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity('organizations')
|
||||
export class Organization {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: number;
|
||||
|
||||
@Column({ name: 'organization_code', length: 20, unique: true })
|
||||
@Index('idx_org_code')
|
||||
organizationCode!: string;
|
||||
|
||||
@Column({ name: 'organization_name', length: 200 })
|
||||
organizationName!: string;
|
||||
|
||||
@Column({ name: 'is_active', default: true })
|
||||
isActive!: boolean;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at' })
|
||||
updatedAt!: Date;
|
||||
|
||||
@DeleteDateColumn({ name: 'deleted_at' })
|
||||
deletedAt!: Date;
|
||||
}
|
||||
41
backend/src/modules/rfas/entities/rfa.entity.ts
Normal file
41
backend/src/modules/rfas/entities/rfa.entity.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import {
|
||||
Entity,
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { User } from '../../users/entities/user.entity';
|
||||
|
||||
@Entity('rfas')
|
||||
export class Rfa {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: number;
|
||||
|
||||
@Column({ name: 'rfa_number', length: 50, unique: true })
|
||||
rfaNumber!: string;
|
||||
|
||||
@Column({ length: 255 })
|
||||
title!: string;
|
||||
|
||||
@Column({ name: 'discipline_code', length: 20, nullable: true })
|
||||
disciplineCode!: string;
|
||||
|
||||
@Column({ length: 50, default: 'Draft' })
|
||||
status!: string;
|
||||
|
||||
@Column({ name: 'created_by_id' })
|
||||
createdById!: number;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'created_by_id' })
|
||||
createdBy!: User;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at' })
|
||||
updatedAt!: Date;
|
||||
}
|
||||
52
backend/src/modules/users/entities/user.entity.ts
Normal file
52
backend/src/modules/users/entities/user.entity.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import {
|
||||
Entity,
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
DeleteDateColumn,
|
||||
ManyToMany,
|
||||
JoinTable,
|
||||
} from 'typeorm';
|
||||
import { Role } from '../../auth/entities/role.entity';
|
||||
|
||||
@Entity('users')
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: number;
|
||||
|
||||
@Column({ length: 50, unique: true })
|
||||
username!: string;
|
||||
|
||||
@Column({ length: 100, unique: true })
|
||||
email!: string;
|
||||
|
||||
@Column({ name: 'password_hash', length: 255 })
|
||||
passwordHash!: string;
|
||||
|
||||
@Column({ name: 'first_name', length: 100 })
|
||||
firstName!: string;
|
||||
|
||||
@Column({ name: 'last_name', length: 100 })
|
||||
lastName!: string;
|
||||
|
||||
@Column({ name: 'is_active', default: true })
|
||||
isActive!: boolean;
|
||||
|
||||
@ManyToMany(() => Role)
|
||||
@JoinTable({
|
||||
name: 'user_roles',
|
||||
joinColumn: { name: 'user_id', referencedColumnName: 'id' },
|
||||
inverseJoinColumn: { name: 'role_id', referencedColumnName: 'id' },
|
||||
})
|
||||
roles!: Role[];
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'updated_at' })
|
||||
updatedAt!: Date;
|
||||
|
||||
@DeleteDateColumn({ name: 'deleted_at' })
|
||||
deletedAt!: Date;
|
||||
}
|
||||
Reference in New Issue
Block a user