Merge remote-tracking branch 'origin/feature/notification' into self-order+notification

# Conflicts:
#	go.mod
#	go.sum
#	internal/app/app.go
#	internal/router/router.go
This commit is contained in:
2026-05-10 12:23:16 +07:00
37 changed files with 3064 additions and 65 deletions
@@ -0,0 +1,92 @@
package contract
import (
"time"
"apskel-pos-be/internal/entities"
"github.com/google/uuid"
)
// ---- Request contracts ----
type SendNotificationRequest struct {
Title string `json:"title" validate:"required,min=1,max=255"`
Body string `json:"body" validate:"required"`
Type string `json:"type,omitempty" validate:"omitempty,max=100"`
Category string `json:"category,omitempty" validate:"omitempty,max=100"`
Priority entities.NotificationPriority `json:"priority,omitempty" validate:"omitempty,oneof=low normal high"`
ImageURL string `json:"image_url,omitempty" validate:"omitempty,max=512"`
ActionURL string `json:"action_url,omitempty" validate:"omitempty,max=512"`
NotifiableType string `json:"notifiable_type,omitempty" validate:"omitempty,max=100"`
NotifiableID *uuid.UUID `json:"notifiable_id,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
ReceiverIDs []uuid.UUID `json:"receiver_ids" validate:"required,min=1"`
ScheduledAt *time.Time `json:"scheduled_at,omitempty"`
ExpiredAt *time.Time `json:"expired_at,omitempty"`
}
type BroadcastNotificationRequest struct {
Title string `json:"title" validate:"required,min=1,max=255"`
Body string `json:"body" validate:"required"`
Type string `json:"type,omitempty" validate:"omitempty,max=100"`
Category string `json:"category,omitempty" validate:"omitempty,max=100"`
Priority entities.NotificationPriority `json:"priority,omitempty" validate:"omitempty,oneof=low normal high"`
ImageURL string `json:"image_url,omitempty" validate:"omitempty,max=512"`
ActionURL string `json:"action_url,omitempty" validate:"omitempty,max=512"`
NotifiableType string `json:"notifiable_type,omitempty" validate:"omitempty,max=100"`
NotifiableID *uuid.UUID `json:"notifiable_id,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
ScheduledAt *time.Time `json:"scheduled_at,omitempty"`
ExpiredAt *time.Time `json:"expired_at,omitempty"`
}
type ListNotificationsRequest struct {
Page int `form:"page" validate:"min=1"`
Limit int `form:"limit" validate:"min=1,max=100"`
IsRead *bool `form:"is_read"`
}
// ---- Response contracts ----
type NotificationResponse struct {
ID uuid.UUID `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
Type string `json:"type"`
Category string `json:"category"`
Priority entities.NotificationPriority `json:"priority"`
ImageURL string `json:"image_url"`
ActionURL string `json:"action_url"`
NotifiableType string `json:"notifiable_type"`
NotifiableID *uuid.UUID `json:"notifiable_id"`
Data map[string]interface{} `json:"data"`
ScheduledAt *time.Time `json:"scheduled_at"`
SentAt *time.Time `json:"sent_at"`
ExpiredAt *time.Time `json:"expired_at"`
CreatedBy *uuid.UUID `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type NotificationReceiverResponse struct {
ID uuid.UUID `json:"id"`
NotificationID uuid.UUID `json:"notification_id"`
UserID uuid.UUID `json:"user_id"`
IsRead bool `json:"is_read"`
ReadAt *time.Time `json:"read_at"`
IsDeleted bool `json:"is_deleted"`
DeletedAt *time.Time `json:"deleted_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Notification *NotificationResponse `json:"notification,omitempty"`
}
type ListNotificationsResponse struct {
Notifications []*NotificationReceiverResponse `json:"notifications"`
TotalCount int64 `json:"total_count"`
UnreadCount int64 `json:"unread_count"`
Page int `json:"page"`
Limit int `json:"limit"`
TotalPages int `json:"total_pages"`
}
+14 -7
View File
@@ -35,16 +35,23 @@ type UpdateUserOutletRequest struct {
}
type LoginRequest struct {
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required"`
DeviceID string `json:"device_id,omitempty"`
DeviceName string `json:"device_name,omitempty"`
DeviceType string `json:"device_type,omitempty"`
Platform string `json:"platform,omitempty"`
FCMToken string `json:"fcm_token,omitempty"`
AppVersion string `json:"app_version,omitempty"`
OsVersion string `json:"os_version,omitempty"`
}
type LoginResponse struct {
Token string `json:"token"`
RefreshToken string `json:"refresh_token"`
ExpiresAt time.Time `json:"expires_at"`
RefreshExpiresAt time.Time `json:"refresh_expires_at"`
User UserResponse `json:"user"`
Token string `json:"token"`
RefreshToken string `json:"refresh_token"`
ExpiresAt time.Time `json:"expires_at"`
RefreshExpiresAt time.Time `json:"refresh_expires_at"`
User UserResponse `json:"user"`
}
type UserResponse struct {
+59
View File
@@ -0,0 +1,59 @@
package contract
import (
"time"
"apskel-pos-be/internal/entities"
"github.com/google/uuid"
)
type RegisterUserDeviceRequest struct {
DeviceID string `json:"device_id" validate:"required,min=1,max=255"`
DeviceName string `json:"device_name,omitempty" validate:"omitempty,max=255"`
DeviceType entities.DeviceType `json:"device_type,omitempty" validate:"omitempty,oneof=mobile tablet desktop"`
Platform entities.DevicePlatform `json:"platform,omitempty" validate:"omitempty,oneof=android ios web"`
FCMToken string `json:"fcm_token,omitempty" validate:"omitempty,max=512"`
AppVersion string `json:"app_version,omitempty" validate:"omitempty,max=50"`
OsVersion string `json:"os_version,omitempty" validate:"omitempty,max=50"`
}
type UpdateUserDeviceRequest struct {
DeviceName string `json:"device_name,omitempty" validate:"omitempty,max=255"`
DeviceType entities.DeviceType `json:"device_type,omitempty" validate:"omitempty,oneof=mobile tablet desktop"`
Platform entities.DevicePlatform `json:"platform,omitempty" validate:"omitempty,oneof=android ios web"`
FCMToken string `json:"fcm_token,omitempty" validate:"omitempty,max=512"`
AppVersion string `json:"app_version,omitempty" validate:"omitempty,max=50"`
OsVersion string `json:"os_version,omitempty" validate:"omitempty,max=50"`
}
type UserDeviceResponse struct {
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"user_id"`
DeviceID string `json:"device_id"`
DeviceName string `json:"device_name"`
DeviceType entities.DeviceType `json:"device_type"`
Platform entities.DevicePlatform `json:"platform"`
FCMToken string `json:"fcm_token"`
AppVersion string `json:"app_version"`
OsVersion string `json:"os_version"`
IPAddress string `json:"ip_address"`
LastActiveAt *time.Time `json:"last_active_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type ListUserDevicesRequest struct {
Page int `json:"page" validate:"min=1"`
Limit int `json:"limit" validate:"min=1,max=100"`
UserID string `json:"user_id,omitempty"`
Platform string `json:"platform,omitempty"`
}
type ListUserDevicesResponse struct {
Devices []UserDeviceResponse `json:"devices"`
TotalCount int `json:"total_count"`
Page int `json:"page"`
Limit int `json:"limit"`
TotalPages int `json:"total_pages"`
}