"use strict"; const add = (q, table, column, definition, transaction) => q.addColumn(table, column, definition, { transaction }); module.exports = { async up(q, Sequelize) { await q.sequelize.transaction(async (transaction) => { await add(q, "uploads", "storage_provider", { type: Sequelize.STRING, allowNull: false, defaultValue: "S3" }, transaction); await add(q, "uploads", "safe_name", { type: Sequelize.STRING, allowNull: true }, transaction); await add(q, "uploads", "checksum", { type: Sequelize.STRING(64), allowNull: true }, transaction); await add(q, "uploads", "owner_type", { type: Sequelize.STRING, allowNull: false, defaultValue: "USER" }, transaction); await add(q, "uploads", "owner_id", { type: Sequelize.STRING, allowNull: true }, transaction); await add(q, "uploads", "visibility", { type: Sequelize.ENUM("PRIVATE", "PUBLIC"), allowNull: false, defaultValue: "PRIVATE" }, transaction); await add(q, "uploads", "status", { type: Sequelize.ENUM("PENDING", "AVAILABLE", "FAILED", "DELETED"), allowNull: false, defaultValue: "AVAILABLE" }, transaction); await add(q, "uploads", "deletedAt", { type: Sequelize.DATE, allowNull: true }, transaction); await q.sequelize.query("UPDATE uploads SET owner_id = uploaded_by WHERE owner_id IS NULL", { transaction }); await q.changeColumn("uploads", "owner_id", { type: Sequelize.STRING, allowNull: false }, { transaction }); await q.addIndex("uploads", ["owner_id", "status"], { name: "uploads_owner_status_idx", transaction }); await q.addIndex("user_notification", ["user_id", "notification_id"], { unique: true, name: "user_notification_user_notification_unique", transaction }); await q.addIndex("user_notification", ["user_id", "isRead", "createdAt"], { name: "user_notification_inbox_idx", transaction }); await q.addIndex("notification", ["isActive", "createdAt"], { name: "notification_retention_idx", transaction }); await q.createTable("notification_deliveries", { id: { type: Sequelize.STRING, primaryKey: true }, notificationId: { type: Sequelize.STRING, allowNull: true }, userId: { type: Sequelize.STRING, allowNull: true }, channel: { type: Sequelize.ENUM("EMAIL", "PUSH"), allowNull: false }, recipient: { type: Sequelize.STRING, allowNull: false }, templateKey: { type: Sequelize.STRING, allowNull: false }, status: { type: Sequelize.ENUM("QUEUED", "PROCESSING", "SENT", "FAILED"), allowNull: false, defaultValue: "QUEUED" }, attemptCount: { type: Sequelize.INTEGER, allowNull: false, defaultValue: 0 }, lastAttemptAt: Sequelize.DATE, sentAt: Sequelize.DATE, failedAt: Sequelize.DATE, failureCode: Sequelize.STRING, createdAt: { type: Sequelize.DATE, allowNull: false }, updatedAt: { type: Sequelize.DATE, allowNull: false }, }, { transaction }); await q.addIndex("notification_deliveries", ["status", "createdAt"], { name: "notification_delivery_status_idx", transaction }); for (const [name, type, nullable] of [["event_id", Sequelize.STRING, true],["target_type",Sequelize.STRING,true],["target_id",Sequelize.STRING,true],["ip_address",Sequelize.STRING,true],["user_agent",Sequelize.STRING,true],["request_id",Sequelize.STRING,true],["metadata",Sequelize.JSON,true],["occurred_at",Sequelize.DATE,true]]) await add(q, "UserActivity", name, { type, allowNull: nullable }, transaction); await q.addIndex("UserActivity", ["event_id"], { unique: true, name: "activity_event_unique", transaction }); await q.addIndex("UserActivity", ["user_id", "occurred_at"], { name: "activity_actor_time_idx", transaction }); await q.changeColumn("UserActivity", "user_id", { type: Sequelize.STRING, allowNull: true }, { transaction }); await add(q, "Document", "created_by", { type: Sequelize.STRING, allowNull: true }, transaction); await add(q, "Document", "owner_type", { type: Sequelize.STRING, allowNull: false, defaultValue: "USER" }, transaction); await add(q, "Document", "owner_id", { type: Sequelize.STRING, allowNull: true }, transaction); await add(q, "Document", "storage_upload_id", { type: Sequelize.INTEGER, allowNull: true }, transaction); await add(q, "Document", "job_id", { type: Sequelize.STRING, allowNull: true }, transaction); await add(q, "Document", "generated_at", { type: Sequelize.DATE, allowNull: true }, transaction); await add(q, "Document", "failed_at", { type: Sequelize.DATE, allowNull: true }, transaction); await add(q, "Document", "failure_code", { type: Sequelize.STRING, allowNull: true }, transaction); await add(q, "Document", "version", { type: Sequelize.INTEGER, allowNull: false, defaultValue: 1 }, transaction); await q.addIndex("Document", ["job_id"], { unique: true, name: "document_job_unique", transaction }); await q.addIndex("Document", ["owner_id", "status"], { name: "document_owner_status_idx", transaction }); await q.addIndex("DocumentType", ["doc_type_name"], { unique: true, name: "document_type_name_unique", transaction }); }); }, async down() { throw new Error("Phase 2 migration is forward-only; restore from backup for rollback"); }, };