Reorganize repo: backend/, deploy/, docs/ layout + AGENTS.md
Restructure the monorepo into clear top-level directories: - backend/: Go module root (cmd, internal, pkg, configs, migrations, docs/swagger, scripts, tests, go.mod, Makefile, .air.toml) - deploy/: Docker (Dockerfile, docker-compose*), quickstart, fluentd - docs/: project documentation + reports/ (moved from repo root) - AGENTS.md: new AI coding-agent guide at repo root Update all references to the new layout: - Dockerfile: COPY backend/go.mod, COPY backend/ (context = repo root) - docker-compose files: context ../.., dockerfile deploy/docker/Dockerfile, env_file ../../.env, volume mounts ../../backend:/app - deploy/quickstart/compose.yaml: dockerfile deploy/docker/Dockerfile - CI: working-directory: backend for go commands, file deploy/docker/Dockerfile, coverage path backend/coverage.out, health_check backend/scripts/ - backend/Makefile: docker target uses -f ../deploy/docker/Dockerfile ../ - README: architecture tree, quickstart, config paths updated Move root stray scripts (rename_models.*, run_m11_tests.sh, verify_build.sh, gorm_bool_main.go) to backend/scripts/legacy/. All moves via git mv to preserve history. Build, vet, SQLite tests, and docker compose config verified.
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
package model
|
||||
|
||||
// NotificationSetting represents per-user per-account notification preferences.
|
||||
// Reference: Chatwoot app/models/notification_setting.rb
|
||||
//
|
||||
// Uses bitmask flags for email_flags and push_flags columns.
|
||||
// Chatwoot uses FlagShihTzu gem for single-column multi-flag storage.
|
||||
// FlagShihTzu bit positions: bit_value = 2^(enum_value - 1)
|
||||
//
|
||||
// Table name: notification_settings
|
||||
//
|
||||
// id uint primaryKey autoIncrement
|
||||
// account_id uint not null; unique index with user_id
|
||||
// user_id uint not null; unique index with account_id
|
||||
// email_flags int default:0 not null; bitmask
|
||||
// push_flags int default:0 not null; bitmask
|
||||
// created_at time
|
||||
// updated_at time
|
||||
|
||||
type NotificationSetting struct {
|
||||
Base `gorm:"embedded"`
|
||||
AccountID uint `gorm:"not null;uniqueIndex:by_account_user"`
|
||||
UserID uint `gorm:"not null;uniqueIndex:by_account_user"`
|
||||
EmailFlags int `gorm:"default:0;not null"`
|
||||
PushFlags int `gorm:"default:0;not null"`
|
||||
}
|
||||
|
||||
// TableName returns the database table name.
|
||||
func (NotificationSetting) TableName() string { return "notification_settings" }
|
||||
|
||||
// Chatwoot NOTIFICATION_TYPES enum values and FlagShihTzu bit positions.
|
||||
// Reference: Chatwoot Notification::NOTIFICATION_TYPES
|
||||
// FlagShihTzu: has_flags key = "email_{type}" / "push_{type}", bit_value = 2^(enum_value - 1)
|
||||
//
|
||||
// Enum value → Flag name → Bit position → Bit value:
|
||||
// 1 → conversation_creation → bit 0 → 1
|
||||
// 2 → conversation_assignment → bit 1 → 2
|
||||
// 3 → assigned_conversation_new_message → bit 2 → 4
|
||||
// 4 → conversation_mention → bit 3 → 8
|
||||
// 5 → participating_conversation_new_message → bit 4 → 16
|
||||
// 6 → sla_missed_first_response → bit 5 → 32
|
||||
// 7 → sla_missed_next_response → bit 6 → 64
|
||||
// 8 → sla_missed_resolution → bit 7 → 128
|
||||
|
||||
const (
|
||||
// Email notification flags (bit values match Chatwoot FlagShihTzu)
|
||||
EmailFlagConversationCreation = 1 // 2^0
|
||||
EmailFlagConversationAssignment = 2 // 2^1
|
||||
EmailFlagAssignedConversationNewMessage = 4 // 2^2
|
||||
EmailFlagConversationMention = 8 // 2^3
|
||||
EmailFlagParticipatingConversationNewMessage = 16 // 2^4
|
||||
EmailFlagSLAMissedFirstResponse = 32 // 2^5
|
||||
EmailFlagSLAMissedNextResponse = 64 // 2^6
|
||||
EmailFlagSLAMissedResolution = 128 // 2^7
|
||||
|
||||
// Push notification flags (same bit values, separate column)
|
||||
PushFlagConversationCreation = 1
|
||||
PushFlagConversationAssignment = 2
|
||||
PushFlagAssignedConversationNewMessage = 4
|
||||
PushFlagConversationMention = 8
|
||||
PushFlagParticipatingConversationNewMessage = 16
|
||||
PushFlagSLAMissedFirstResponse = 32
|
||||
PushFlagSLAMissedNextResponse = 64
|
||||
PushFlagSLAMissedResolution = 128
|
||||
)
|
||||
|
||||
// AllEmailFlags returns the bitmask of all email notification types.
|
||||
func AllEmailFlags() int {
|
||||
return EmailFlagConversationCreation |
|
||||
EmailFlagConversationAssignment |
|
||||
EmailFlagAssignedConversationNewMessage |
|
||||
EmailFlagConversationMention |
|
||||
EmailFlagParticipatingConversationNewMessage |
|
||||
EmailFlagSLAMissedFirstResponse |
|
||||
EmailFlagSLAMissedNextResponse |
|
||||
EmailFlagSLAMissedResolution
|
||||
}
|
||||
|
||||
// AllPushFlags returns the bitmask of all push notification types.
|
||||
func AllPushFlags() int {
|
||||
return PushFlagConversationCreation |
|
||||
PushFlagConversationAssignment |
|
||||
PushFlagAssignedConversationNewMessage |
|
||||
PushFlagConversationMention |
|
||||
PushFlagParticipatingConversationNewMessage |
|
||||
PushFlagSLAMissedFirstResponse |
|
||||
PushFlagSLAMissedNextResponse |
|
||||
PushFlagSLAMissedResolution
|
||||
}
|
||||
|
||||
// AllEmailFlagNames returns all available email notification flag names.
|
||||
// Matches Chatwoot FlagShihTzu generated flag names: "email_{type}".
|
||||
func AllEmailFlagNames() []string {
|
||||
return []string{
|
||||
"email_conversation_creation",
|
||||
"email_conversation_assignment",
|
||||
"email_assigned_conversation_new_message",
|
||||
"email_conversation_mention",
|
||||
"email_participating_conversation_new_message",
|
||||
"email_sla_missed_first_response",
|
||||
"email_sla_missed_next_response",
|
||||
"email_sla_missed_resolution",
|
||||
}
|
||||
}
|
||||
|
||||
// AllPushFlagNames returns all available push notification flag names.
|
||||
// Matches Chatwoot FlagShihTzu generated flag names: "push_{type}".
|
||||
func AllPushFlagNames() []string {
|
||||
return []string{
|
||||
"push_conversation_creation",
|
||||
"push_conversation_assignment",
|
||||
"push_assigned_conversation_new_message",
|
||||
"push_conversation_mention",
|
||||
"push_participating_conversation_new_message",
|
||||
"push_sla_missed_first_response",
|
||||
"push_sla_missed_next_response",
|
||||
"push_sla_missed_resolution",
|
||||
}
|
||||
}
|
||||
|
||||
// Email flag name → bit value mapping for selected_email_flags parsing.
|
||||
var emailFlagNameToValue = map[string]int{
|
||||
"email_conversation_creation": EmailFlagConversationCreation,
|
||||
"email_conversation_assignment": EmailFlagConversationAssignment,
|
||||
"email_assigned_conversation_new_message": EmailFlagAssignedConversationNewMessage,
|
||||
"email_conversation_mention": EmailFlagConversationMention,
|
||||
"email_participating_conversation_new_message": EmailFlagParticipatingConversationNewMessage,
|
||||
"email_sla_missed_first_response": EmailFlagSLAMissedFirstResponse,
|
||||
"email_sla_missed_next_response": EmailFlagSLAMissedNextResponse,
|
||||
"email_sla_missed_resolution": EmailFlagSLAMissedResolution,
|
||||
}
|
||||
|
||||
// Push flag name → bit value mapping for selected_push_flags parsing.
|
||||
var pushFlagNameToValue = map[string]int{
|
||||
"push_conversation_creation": PushFlagConversationCreation,
|
||||
"push_conversation_assignment": PushFlagConversationAssignment,
|
||||
"push_assigned_conversation_new_message": PushFlagAssignedConversationNewMessage,
|
||||
"push_conversation_mention": PushFlagConversationMention,
|
||||
"push_participating_conversation_new_message": PushFlagParticipatingConversationNewMessage,
|
||||
"push_sla_missed_first_response": PushFlagSLAMissedFirstResponse,
|
||||
"push_sla_missed_next_response": PushFlagSLAMissedNextResponse,
|
||||
"push_sla_missed_resolution": PushFlagSLAMissedResolution,
|
||||
}
|
||||
|
||||
// Email bit value → flag name mapping.
|
||||
var emailValueToFlagName = map[int]string{
|
||||
EmailFlagConversationCreation: "email_conversation_creation",
|
||||
EmailFlagConversationAssignment: "email_conversation_assignment",
|
||||
EmailFlagAssignedConversationNewMessage: "email_assigned_conversation_new_message",
|
||||
EmailFlagConversationMention: "email_conversation_mention",
|
||||
EmailFlagParticipatingConversationNewMessage: "email_participating_conversation_new_message",
|
||||
EmailFlagSLAMissedFirstResponse: "email_sla_missed_first_response",
|
||||
EmailFlagSLAMissedNextResponse: "email_sla_missed_next_response",
|
||||
EmailFlagSLAMissedResolution: "email_sla_missed_resolution",
|
||||
}
|
||||
|
||||
// Push bit value → flag name mapping.
|
||||
var pushValueToFlagName = map[int]string{
|
||||
PushFlagConversationCreation: "push_conversation_creation",
|
||||
PushFlagConversationAssignment: "push_conversation_assignment",
|
||||
PushFlagAssignedConversationNewMessage: "push_assigned_conversation_new_message",
|
||||
PushFlagConversationMention: "push_conversation_mention",
|
||||
PushFlagParticipatingConversationNewMessage: "push_participating_conversation_new_message",
|
||||
PushFlagSLAMissedFirstResponse: "push_sla_missed_first_response",
|
||||
PushFlagSLAMissedNextResponse: "push_sla_missed_next_response",
|
||||
PushFlagSLAMissedResolution: "push_sla_missed_resolution",
|
||||
}
|
||||
|
||||
// HasEmailFlag checks if a specific email flag is enabled.
|
||||
func (ns *NotificationSetting) HasEmailFlag(flag int) bool {
|
||||
return ns.EmailFlags&flag != 0
|
||||
}
|
||||
|
||||
// HasPushFlag checks if a specific push flag is enabled.
|
||||
func (ns *NotificationSetting) HasPushFlag(flag int) bool {
|
||||
return ns.PushFlags&flag != 0
|
||||
}
|
||||
|
||||
// SetEmailFlagsFromNames sets email flags from a list of flag names.
|
||||
// Reference: Chatwoot selected_email_flags (FlagShihTzu flag names like "email_conversation_creation")
|
||||
func (ns *NotificationSetting) SetEmailFlagsFromNames(names []string) {
|
||||
ns.EmailFlags = 0
|
||||
for _, name := range names {
|
||||
if v, ok := emailFlagNameToValue[name]; ok {
|
||||
ns.EmailFlags |= v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetPushFlagsFromNames sets push flags from a list of flag names.
|
||||
// Reference: Chatwoot selected_push_flags
|
||||
func (ns *NotificationSetting) SetPushFlagsFromNames(names []string) {
|
||||
ns.PushFlags = 0
|
||||
for _, name := range names {
|
||||
if v, ok := pushFlagNameToValue[name]; ok {
|
||||
ns.PushFlags |= v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SelectedEmailFlagNames returns the names of enabled email flags.
|
||||
// Matches Chatwoot FlagShihTzu: returns "email_{type}" format names.
|
||||
func (ns *NotificationSetting) SelectedEmailFlagNames() []string {
|
||||
names := []string{}
|
||||
for _, bitValue := range []int{
|
||||
EmailFlagConversationCreation,
|
||||
EmailFlagConversationAssignment,
|
||||
EmailFlagAssignedConversationNewMessage,
|
||||
EmailFlagConversationMention,
|
||||
EmailFlagParticipatingConversationNewMessage,
|
||||
EmailFlagSLAMissedFirstResponse,
|
||||
EmailFlagSLAMissedNextResponse,
|
||||
EmailFlagSLAMissedResolution,
|
||||
} {
|
||||
if ns.EmailFlags&bitValue != 0 {
|
||||
names = append(names, emailValueToFlagName[bitValue])
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// SelectedPushFlagNames returns the names of enabled push flags.
|
||||
// Matches Chatwoot FlagShihTzu: returns "push_{type}" format names.
|
||||
func (ns *NotificationSetting) SelectedPushFlagNames() []string {
|
||||
names := []string{}
|
||||
for _, bitValue := range []int{
|
||||
PushFlagConversationCreation,
|
||||
PushFlagConversationAssignment,
|
||||
PushFlagAssignedConversationNewMessage,
|
||||
PushFlagConversationMention,
|
||||
PushFlagParticipatingConversationNewMessage,
|
||||
PushFlagSLAMissedFirstResponse,
|
||||
PushFlagSLAMissedNextResponse,
|
||||
PushFlagSLAMissedResolution,
|
||||
} {
|
||||
if ns.PushFlags&bitValue != 0 {
|
||||
names = append(names, pushValueToFlagName[bitValue])
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user