feat(sprint-6): Phase 6 — Notifications (WebSocket) + PWA
- WebSocket: Spring STOMP + SockJS, NotificationService, persistent notifications table - NotificationController: GET/PUT endpoints for notification management - Frontend: notification bell with unread badge, dropdown panel, real-time via STOMP - PWA: manifest.json, service worker (manual sw.js), offline page, install prompt - PWA icons (192+512), dark theme colors, standalone display - Full i18n (de/en) for notifications and PWA - Flyway V10 migration for notifications table - spring-boot-starter-websocket dependency added
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
package de.cannamanage.domain.entity;
|
||||
|
||||
import de.cannamanage.domain.enums.NotificationType;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Persistent notification entity — survives page refresh.
|
||||
* Delivered in real-time via WebSocket, but also queryable via REST.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "notifications", indexes = {
|
||||
@Index(name = "idx_notifications_user", columnList = "user_id, read, created_at DESC")
|
||||
})
|
||||
public class Notification extends AbstractTenantEntity {
|
||||
|
||||
@Column(name = "user_id", nullable = false)
|
||||
private UUID userId;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "type", nullable = false, length = 50)
|
||||
private NotificationType type;
|
||||
|
||||
@Column(name = "title", nullable = false)
|
||||
private String title;
|
||||
|
||||
@Column(name = "message", nullable = false, columnDefinition = "TEXT")
|
||||
private String message;
|
||||
|
||||
@Column(name = "link", length = 500)
|
||||
private String link;
|
||||
|
||||
@Column(name = "read", nullable = false)
|
||||
private boolean read = false;
|
||||
|
||||
public Notification() {}
|
||||
|
||||
public Notification(UUID userId, NotificationType type, String title, String message, String link) {
|
||||
this.userId = userId;
|
||||
this.type = type;
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
public UUID getUserId() { return userId; }
|
||||
public void setUserId(UUID userId) { this.userId = userId; }
|
||||
|
||||
public NotificationType getType() { return type; }
|
||||
public void setType(NotificationType type) { this.type = type; }
|
||||
|
||||
public String getTitle() { return title; }
|
||||
public void setTitle(String title) { this.title = title; }
|
||||
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
|
||||
public String getLink() { return link; }
|
||||
public void setLink(String link) { this.link = link; }
|
||||
|
||||
public boolean isRead() { return read; }
|
||||
public void setRead(boolean read) { this.read = read; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.cannamanage.domain.enums;
|
||||
|
||||
/**
|
||||
* Types of notifications sent to users.
|
||||
*/
|
||||
public enum NotificationType {
|
||||
QUOTA_WARNING,
|
||||
BATCH_RECALLED,
|
||||
DISTRIBUTION_RECORDED,
|
||||
SUBSCRIPTION_EXPIRING
|
||||
}
|
||||
Reference in New Issue
Block a user