Database: - notification_preferences table (user_id, tenant_id, reminder days, email/digest toggles) - notifications table (type, entity link, read/sent tracking, dedup index) Backend: - NotificationService with background goroutine checking reminders hourly - CheckDeadlineReminders: finds deadlines due in N days per user prefs, creates notifications - Overdue deadline detection and notification - Daily digest at 8am: compiles pending notifications into one email - SendEmail via `m mail send` CLI command - Deduplication: same notification type + entity + day = skip - API: GET/PATCH notifications, unread count, mark read/all-read - API: GET/PUT notification-preferences with upsert Frontend: - NotificationBell in header with unread count badge (polls every 30s) - Dropdown panel with notification list, type-colored dots, time-ago, entity links - Mark individual/all as read - NotificationSettings in Einstellungen page: reminder day toggles, email toggle, digest toggle
52 lines
1.2 KiB
Go
52 lines
1.2 KiB
Go
package main
|
|
|
|
import (
|
|
"log/slog"
|
|
"net/http"
|
|
"os"
|
|
|
|
"mgit.msbls.de/m/KanzlAI-mGMT/internal/auth"
|
|
"mgit.msbls.de/m/KanzlAI-mGMT/internal/config"
|
|
"mgit.msbls.de/m/KanzlAI-mGMT/internal/db"
|
|
"mgit.msbls.de/m/KanzlAI-mGMT/internal/logging"
|
|
"mgit.msbls.de/m/KanzlAI-mGMT/internal/router"
|
|
"mgit.msbls.de/m/KanzlAI-mGMT/internal/services"
|
|
)
|
|
|
|
func main() {
|
|
logging.Setup()
|
|
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
slog.Error("failed to load config", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
database, err := db.Connect(cfg.DatabaseURL)
|
|
if err != nil {
|
|
slog.Error("failed to connect to database", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
defer database.Close()
|
|
|
|
authMW := auth.NewMiddleware(cfg.SupabaseJWTSecret, database)
|
|
|
|
// Start CalDAV sync service
|
|
calDAVSvc := services.NewCalDAVService(database)
|
|
calDAVSvc.Start()
|
|
defer calDAVSvc.Stop()
|
|
|
|
// Start notification reminder service
|
|
notifSvc := services.NewNotificationService(database)
|
|
notifSvc.Start()
|
|
defer notifSvc.Stop()
|
|
|
|
handler := router.New(database, authMW, cfg, calDAVSvc, notifSvc)
|
|
|
|
slog.Info("starting KanzlAI API server", "port", cfg.Port)
|
|
if err := http.ListenAndServe(":"+cfg.Port, handler); err != nil {
|
|
slog.Error("server failed", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|