// models/notifications/notification_broadcast.mdl.js const { DataTypes } = require("sequelize"); const sequelize = require("../../config/db.config"); const mdl_Users = require("../users/users.mdl"); const mdl_Assets = require("../assets/assets.mdl"); const NotificationBroadcast = sequelize.define("NotificationBroadcast", { // ─── Identity ───────────────────────────────────────────────────────────── broadcast_id: { type: DataTypes.BIGINT, primaryKey: true, autoIncrement: true, label: "Broadcast ID", order: 0, hidden: true }, uuid: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, allowNull: false, unique: true, label: "UUID", order: 0, hidden: true }, // ─── Content ────────────────────────────────────────────────────────────── title: { type: DataTypes.STRING(255), allowNull: false, label: "Title", order: 1 }, // Only used by Notifications-type alerts (show_in_notifications) — Sticky // alerts (show_in_sticky) are title-only and leave this null. message: { type: DataTypes.TEXT, allowNull: true, label: "Message", order: 1.5 }, // When set, the client's "view full content" dialog shows an "Open Link" // action pointing here. When null, that dialog is plain text info only. link_url: { type: DataTypes.STRING(2048), allowNull: true, label: "Link URL", order: 2.2 }, // Custom CTA button text shown right after the title in the sticky banner // (e.g. "Shop now"). Falls back to "Open Link" when unset. link_label: { type: DataTypes.STRING(60), allowNull: true, label: "Button Label", order: 2.3 }, // Named color key (see utils/tierColors.js on the frontend) driving the // sticky banner's panel background/border — same registry rewards/tiers use. color: { type: DataTypes.STRING(20), allowNull: false, defaultValue: 'indigo', label: "Color", order: 2.4 }, // Optional per-alert image shown in the click-through details dialog when // opened from the sticky banner (see AnnouncementCarouselDialog on the // frontend). Replaces the old shared sticky_banner_settings singleton. image_asset_id: { type: DataTypes.BIGINT, allowNull: true, label: "Layout Image", order: 2.45 }, // Optional visibility window. Null start_date = show immediately once sent; // null end_date = show indefinitely. Copied onto AdminNotification/ // UserNotification rows at send time so client reads can filter without // joining back to this table (see sendBroadcast + notificationVisibility.util.js). start_date: { type: DataTypes.DATE, allowNull: true, label: "Start Date", order: 2.7 }, end_date: { type: DataTypes.DATE, allowNull: true, label: "End Date", order: 2.8 }, // ─── Visibility ────────────────────────────────────────────────────────── // Determines where a delivered announcement shows up for recipients. // - show_in_sticky: client sticky banner (fixed top) // - show_in_notifications: client + admin notifications lists/bells show_in_sticky: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false, label: "Show in Sticky Alerts", order: 2.5 }, show_in_notifications: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true, label: "Show in Notifications", order: 2.6 }, // ─── Targeting ──────────────────────────────────────────────────────────── target_type: { type: DataTypes.ENUM("admin", "user", "both", "task_list", "course", "tier_plan"), allowNull: false, label: "Target", order: 3 }, // Holds a task list UUID, course UUID, or tier plan ID (stringified) — only // set when target_type is 'task_list' / 'course' / 'tier_plan'. target_id: { type: DataTypes.STRING(64), allowNull: true, label: "Target ID", order: 3.5 }, // ─── Lifecycle ──────────────────────────────────────────────────────────── status: { type: DataTypes.ENUM("draft", "sent", "archived"), allowNull: false, defaultValue: "draft", label: "Status", order: 4 }, sent_at: { type: DataTypes.DATE, allowNull: true, label: "Sent At", order: 5 }, recipient_count: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0, label: "Recipients", order: 6 }, // ─── Audit trails ───────────────────────────────────────────────────────── createdBy: { type: DataTypes.BIGINT, allowNull: true, label: "Created By" }, updatedBy: { type: DataTypes.BIGINT, allowNull: true, label: "Modified By" }, deletedBy: { type: DataTypes.BIGINT, allowNull: true, label: "Deleted By" }, }, { tableName: "notification_broadcasts", timestamps: true, // createdAt, updatedAt paranoid: true, indexes: [ { fields: ["uuid"] }, { fields: ["status"] }, { fields: ["target_type"] }, { fields: ["deletedAt"] }, ], }); NotificationBroadcast.belongsTo(mdl_Users, { as: "creator", foreignKey: "createdBy" }); NotificationBroadcast.belongsTo(mdl_Users, { as: "updater", foreignKey: "updatedBy" }); NotificationBroadcast.belongsTo(mdl_Assets, { as: "image", foreignKey: "image_asset_id" }); module.exports = NotificationBroadcast;