Files
flatrender/services/notification/internal/models/models.go
T
soroush.asadi 90ac0b81d1 feat: V2 microservices stack — backend services, gateway, JWT auth
Add full V2 architecture: identity, content, studio (.NET 10) and file,
render, notification, gateway (Go) services with vendored deps, plus DB
migrations, event/API contracts, and an init-db script.

Wire the Next.js frontend to the gateway: server-side JWT auth routes
(login/register/refresh/logout/me), gateway fetch helper, and session/
cookie/jwt helpers under src/lib.

Containerize the stack via docker-compose.v2.yml and per-service
Dockerfiles. Base images resolve through a Nexus mirror (Docker Hub) and
MCR directly; npm/NuGet pull from Nexus groups. Self-host fonts via
next/font/local to avoid Google Fonts (geo-blocked).

Add CI workflow and ignore .env.v2, *.stackdump, and .NET bin/obj.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 23:29:31 +03:30

196 lines
7.6 KiB
Go

package models
import (
"time"
"github.com/google/uuid"
)
// ── Enum consts ───────────────────────────────────────────────────────────────
const (
// NotificationKind
KindRenderCompleted = "RenderCompleted"
KindRenderFailed = "RenderFailed"
KindRenderProgress = "RenderProgress"
KindPlanExpiring = "PlanExpiring"
KindPlanExpired = "PlanExpired"
KindPaymentSuccess = "PaymentSuccess"
KindPaymentFailed = "PaymentFailed"
KindStorageWarning = "StorageWarning"
KindStorageFull = "StorageFull"
KindExportExpiring = "ExportExpiring"
KindExportDeleted = "ExportDeleted"
KindGiftEarned = "GiftEarned"
KindQuestCompleted = "QuestCompleted"
KindLevelUp = "LevelUp"
KindAccountSecurity = "AccountSecurity"
KindSystemAnnouncement = "SystemAnnouncement"
KindTenantInvite = "TenantInvite"
KindMarketing = "Marketing"
KindOther = "Other"
// Priority
PriorityLow = "Low"
PriorityNormal = "Normal"
PriorityHigh = "High"
PriorityUrgent = "Urgent"
// DeliveryChannel
ChannelInApp = "InApp"
ChannelPush = "Push"
ChannelEmail = "Email"
ChannelSMS = "SMS"
ChannelTelegram = "Telegram"
ChannelWebhook = "Webhook"
// DeliveryStatus
StatusPending = "Pending"
StatusSent = "Sent"
StatusDelivered = "Delivered"
StatusFailed = "Failed"
StatusBounced = "Bounced"
StatusSuppressed = "Suppressed"
)
// ── Domain entities ──────────────────────────────────────────────────────────
type Notification struct {
ID uuid.UUID `json:"id"`
TenantID uuid.UUID `json:"tenant_id"`
UserID uuid.UUID `json:"user_id"`
NotificationType string `json:"notification_type"`
Priority string `json:"priority"`
Title string `json:"title"`
Message string `json:"message"`
Label *string `json:"label,omitempty"`
Signature *string `json:"signature,omitempty"`
Icon *string `json:"icon,omitempty"`
Image *string `json:"image,omitempty"`
AnimationDemo *string `json:"animation_demo,omitempty"`
Design *string `json:"design,omitempty"`
ActionURL *string `json:"action_url,omitempty"`
ActionText *string `json:"action_text,omitempty"`
RenderJobID *uuid.UUID `json:"render_job_id,omitempty"`
ExportID *uuid.UUID `json:"export_id,omitempty"`
PaymentID *uuid.UUID `json:"payment_id,omitempty"`
GiftID *uuid.UUID `json:"gift_id,omitempty"`
EarnedGiftID *uuid.UUID `json:"earned_gift_id,omitempty"`
IsEmergency bool `json:"is_emergency"`
Seen bool `json:"seen"`
SeenAt *time.Time `json:"seen_at,omitempty"`
Clicked bool `json:"clicked"`
ClickedAt *time.Time `json:"clicked_at,omitempty"`
GiftUsed bool `json:"gift_used"`
ExpireDate *time.Time `json:"expire_date,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type NotificationPreference struct {
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"user_id"`
NotificationType string `json:"notification_type"`
Channel string `json:"channel"`
Enabled bool `json:"enabled"`
UpdatedAt time.Time `json:"updated_at"`
}
type NotificationTemplate struct {
ID uuid.UUID `json:"id"`
TenantID *uuid.UUID `json:"tenant_id,omitempty"`
Code string `json:"code"`
Channel string `json:"channel"`
Locale string `json:"locale"`
Subject *string `json:"subject,omitempty"`
BodyText *string `json:"body_text,omitempty"`
BodyHTML *string `json:"body_html,omitempty"`
PushTitle *string `json:"push_title,omitempty"`
PushBody *string `json:"push_body,omitempty"`
PushIcon *string `json:"push_icon,omitempty"`
VariablesSchema *string `json:"variables_schema,omitempty"`
IsActive bool `json:"is_active"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type NotificationDelivery struct {
ID uuid.UUID `json:"id"`
TenantID uuid.UUID `json:"tenant_id"`
UserID uuid.UUID `json:"user_id"`
NotificationID *uuid.UUID `json:"notification_id,omitempty"`
Channel string `json:"channel"`
Recipient string `json:"recipient"`
Subject *string `json:"subject,omitempty"`
Provider *string `json:"provider,omitempty"`
ProviderMessageID *string `json:"provider_message_id,omitempty"`
Status string `json:"status"`
ErrorMessage *string `json:"error_message,omitempty"`
Attempt int `json:"attempt"`
MaxAttempts int `json:"max_attempts"`
SentAt *time.Time `json:"sent_at,omitempty"`
DeliveredAt *time.Time `json:"delivered_at,omitempty"`
FailedAt *time.Time `json:"failed_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
// ── Request / Response types ─────────────────────────────────────────────────
type PagedResponse[T any] struct {
Data []T `json:"data"`
Meta PaginationMeta `json:"meta"`
}
type PaginationMeta struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
Total int64 `json:"total"`
HasMore bool `json:"has_more"`
}
type CreateNotificationRequest struct {
UserID uuid.UUID `json:"user_id" binding:"required"`
TenantID uuid.UUID `json:"tenant_id" binding:"required"`
NotificationType string `json:"notification_type" binding:"required"`
Priority *string `json:"priority"`
Title string `json:"title" binding:"required"`
Message string `json:"message" binding:"required"`
Label *string `json:"label"`
Icon *string `json:"icon"`
Image *string `json:"image"`
ActionURL *string `json:"action_url"`
ActionText *string `json:"action_text"`
RenderJobID *uuid.UUID `json:"render_job_id"`
ExportID *uuid.UUID `json:"export_id"`
PaymentID *uuid.UUID `json:"payment_id"`
GiftID *uuid.UUID `json:"gift_id"`
EarnedGiftID *uuid.UUID `json:"earned_gift_id"`
IsEmergency bool `json:"is_emergency"`
ExpireDate *time.Time `json:"expire_date"`
Channels []string `json:"channels"` // which delivery channels to trigger
}
type UpdatePreferenceRequest struct {
NotificationType string `json:"notification_type" binding:"required"`
Channel string `json:"channel" binding:"required"`
Enabled bool `json:"enabled"`
}
type TemplateUpsertRequest struct {
Code string `json:"code" binding:"required"`
Channel string `json:"channel" binding:"required"`
Locale string `json:"locale" binding:"required"`
Subject *string `json:"subject"`
BodyText *string `json:"body_text"`
BodyHTML *string `json:"body_html"`
PushTitle *string `json:"push_title"`
PushBody *string `json:"push_body"`
PushIcon *string `json:"push_icon"`
IsActive *bool `json:"is_active"`
}
type APIError struct {
Code string `json:"code"`
Message string `json:"message"`
}