'string', 'file_name' => 'string', 'file_name_old' => 'string', 'fileable_id' => 'bigInteger', 'fileable_type' => 'string', ]; foreach ($legacyColumns as $column => $type) { if (Schema::hasColumn('files', $column)) { if ($type === 'bigInteger') { $table->unsignedBigInteger($column)->nullable()->change(); } else { $table->string($column, 255)->nullable()->change(); } } } // 파일명 시스템 개선 if (! Schema::hasColumn('files', 'display_name')) { $table->string('display_name', 255)->after('file_path')->comment('사용자가 보는 이름'); } if (! Schema::hasColumn('files', 'stored_name')) { $table->string('stored_name', 255)->after('display_name')->comment('실제 저장 이름 (64bit 난수)'); } // 폴더 관리 if (! Schema::hasColumn('files', 'folder_id')) { $table->unsignedBigInteger('folder_id')->nullable()->after('tenant_id')->comment('folders 테이블 FK'); } if (! Schema::hasColumn('files', 'is_temp')) { $table->boolean('is_temp')->default(true)->after('folder_id')->comment('temp 폴더 여부'); } // 파일 분류 if (! Schema::hasColumn('files', 'file_type')) { $table->enum('file_type', ['document', 'image', 'excel', 'archive'])->after('mime_type')->comment('파일 타입'); } // 문서 연결 if (! Schema::hasColumn('files', 'document_id')) { $table->unsignedBigInteger('document_id')->nullable()->after('file_type')->comment('문서 ID'); } if (! Schema::hasColumn('files', 'document_type')) { $table->string('document_type', 50)->nullable()->after('document_id')->comment('문서 타입'); } // 감사 컬럼 if (! Schema::hasColumn('files', 'uploaded_by')) { $table->unsignedBigInteger('uploaded_by')->nullable()->after('description')->comment('업로더 user_id'); } if (! Schema::hasColumn('files', 'deleted_by')) { $table->unsignedBigInteger('deleted_by')->nullable()->after('deleted_at')->comment('삭제자 user_id'); } if (! Schema::hasColumn('files', 'created_by')) { $table->unsignedBigInteger('created_by')->nullable()->after('deleted_by')->comment('생성자 user_id'); } if (! Schema::hasColumn('files', 'updated_by')) { $table->unsignedBigInteger('updated_by')->nullable()->after('created_by')->comment('수정자 user_id'); } }); // 인덱스 추가 Schema::table('files', function (Blueprint $table) { $table->index(['tenant_id', 'folder_id'], 'idx_tenant_folder'); $table->index('is_temp'); $table->index('document_id'); $table->index('created_at'); $table->index('stored_name'); }); } /** * Reverse the migrations. */ public function down(): void { // 인덱스 삭제 (에러 무시) try { Schema::table('files', function (Blueprint $table) { $table->dropIndex('idx_tenant_folder'); }); } catch (\Exception $e) { // 인덱스가 없으면 무시 } try { Schema::table('files', function (Blueprint $table) { $table->dropIndex(['is_temp']); }); } catch (\Exception $e) { // 인덱스가 없으면 무시 } try { Schema::table('files', function (Blueprint $table) { $table->dropIndex(['document_id']); }); } catch (\Exception $e) { // 인덱스가 없으면 무시 } try { Schema::table('files', function (Blueprint $table) { $table->dropIndex(['created_at']); }); } catch (\Exception $e) { // 인덱스가 없으면 무시 } try { Schema::table('files', function (Blueprint $table) { $table->dropIndex(['stored_name']); }); } catch (\Exception $e) { // 인덱스가 없으면 무시 } // 컬럼 삭제 (존재하는 것만) Schema::table('files', function (Blueprint $table) { $columnsToCheck = [ 'display_name', 'stored_name', 'folder_id', 'is_temp', 'file_type', 'document_id', 'document_type', 'uploaded_by', 'deleted_by', 'created_by', 'updated_by', ]; $columnsToDrop = []; foreach ($columnsToCheck as $column) { if (Schema::hasColumn('files', $column)) { $columnsToDrop[] = $column; } } if (! empty($columnsToDrop)) { $table->dropColumn($columnsToDrop); } }); } };