import { BaseEntity } from "@edr/api-common"; import { NotificationAudience, NotificationChannelsSent, NotificationPriority, NotificationType, } from "@edr/types"; import { Column, Entity, Index } from "typeorm"; /** * A single persisted in-app notification addressed to one IAM user. Producers * fan a logical notification out to N recipients by inserting one row per * resolved user id (see NotificationInboxService.notify). */ @Entity({ schema: "freight", name: "notifications" }) @Index("IDX_NOTIFICATIONS_RECIPIENT_UNREAD", ["recipientUserId", "isRead"]) @Index("IDX_NOTIFICATIONS_RECIPIENT_CREATED", ["recipientUserId", "createdAt"]) export class Notification extends BaseEntity { @Column({ name: "recipient_user_id", type: "uuid" }) recipientUserId!: string; @Column({ name: "audience", type: "varchar", length: 20 }) audience!: NotificationAudience; @Column({ name: "type", type: "varchar", length: 48, default: NotificationType.GENERIC, }) type!: NotificationType; @Column({ name: "title", type: "varchar", length: 200 }) title!: string; @Column({ name: "body", type: "text" }) body!: string; /** Deep-link path within the app the item points to (e.g. `/contracts/:id`). */ @Column({ name: "link", type: "varchar", nullable: true }) link?: string | null; /** Arbitrary structured payload (bookingId, invoiceId, contractId, …). */ @Column({ name: "data", type: "jsonb", nullable: true }) data?: Record | null; @Column({ name: "priority", type: "varchar", length: 12, default: NotificationPriority.NORMAL, }) priority!: NotificationPriority; @Column({ name: "is_read", type: "boolean", default: false }) isRead!: boolean; @Column({ name: "read_at", type: "timestamptz", nullable: true }) readAt?: Date | null; /** Per-channel fan-out outcome for HIGH-priority items (email/SMS). */ @Column({ name: "channels_sent", type: "jsonb", nullable: true }) channelsSent?: NotificationChannelsSent | null; }