/** * 마이그레이션: 작업장 지도 이미지 기능 추가 * - workplace_categories에 layout_image 필드 추가 * - workplace_map_regions 테이블 생성 (클릭 가능한 영역 정의) */ exports.up = async function(knex) { // 1. workplace_categories 테이블에 layout_image 필드 추가 await knex.schema.alterTable('workplace_categories', function(table) { table.string('layout_image', 500).nullable().comment('공장 배치도 이미지 경로'); }); // 2. 작업장 지도 클릭 영역 정의 테이블 생성 await knex.schema.createTable('workplace_map_regions', function(table) { table.increments('region_id').primary().comment('영역 ID'); table.integer('workplace_id').unsigned().notNullable().comment('작업장 ID'); table.integer('category_id').unsigned().notNullable().comment('공장 카테고리 ID'); // 좌표 정보 (비율 기반: 0~100%) table.decimal('x_start', 5, 2).notNullable().comment('시작 X 좌표 (%)'); table.decimal('y_start', 5, 2).notNullable().comment('시작 Y 좌표 (%)'); table.decimal('x_end', 5, 2).notNullable().comment('끝 X 좌표 (%)'); table.decimal('y_end', 5, 2).notNullable().comment('끝 Y 좌표 (%)'); table.string('shape', 20).defaultTo('rect').comment('영역 모양 (rect, circle, polygon)'); table.text('polygon_points').nullable().comment('다각형인 경우 좌표 배열 (JSON)'); table.timestamps(true, true); // 외래키 table.foreign('workplace_id') .references('workplace_id') .inTable('workplaces') .onDelete('CASCADE') .onUpdate('CASCADE'); table.foreign('category_id') .references('category_id') .inTable('workplace_categories') .onDelete('CASCADE') .onUpdate('CASCADE'); }); }; exports.down = async function(knex) { // 테이블 삭제 await knex.schema.dropTableIfExists('workplace_map_regions'); // 필드 제거 await knex.schema.alterTable('workplace_categories', function(table) { table.dropColumn('layout_image'); }); };