veza/veza-backend-api/cmd/tools/seed/seed_chat.go
senke 2eff5a9b10 refactor(backend): split seed tool into domain-specific modules
Extract monolithic seed main.go into separate files per domain:
users, tracks, playlists, chat, analytics, marketplace, social,
content, live, moderation, notifications, and misc. Add config,
fake data helpers, and utility modules. Update Makefile targets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 23:35:07 +01:00

169 lines
5.4 KiB
Go

package main
import (
"database/sql"
"fmt"
"time"
)
// SeededRoom holds room data.
type SeededRoom struct {
ID string
CreatorID string
Name string
}
// SeedChat creates rooms, room_members, messages, read_receipts, and message_reactions.
func SeedChat(db *sql.DB, cfg Config, users []SeededUser) ([]SeededRoom, error) {
fmt.Println("\n═══ CHAT ═══")
rooms := make([]SeededRoom, 0, cfg.Conversations)
allUsers := users
// ── 1. Create rooms ──────────────────────────────────────────────────────
// Mix of group rooms and DM rooms
groupCount := cfg.Conversations / 5 // 20% group rooms
dmCount := cfg.Conversations - groupCount // 80% DMs
p := NewProgress("rooms", cfg.Conversations)
roomRows := make([][]interface{}, 0, cfg.Conversations)
// Group rooms
for i := 0; i < groupCount; i++ {
id := newUUID()
creator := allUsers[rng.Intn(len(allUsers))]
name := pick(roomNames)
if i >= len(roomNames) {
name = fmt.Sprintf("%s #%d", pick(roomNames), i)
}
slug := fmt.Sprintf("room-%d", i)
createdAt := RandomTimeAfter(creator.CreatedAt)
r := SeededRoom{ID: id, CreatorID: creator.ID, Name: name}
rooms = append(rooms, r)
roomRows = append(roomRows, []interface{}{
id, name, slug, fmt.Sprintf("Group chat: %s", name),
"group", false, nil, 50, // room_type, is_private, password_hash, max_members
creator.ID, 0, 0, creator.ID, true,
createdAt, createdAt, nil,
})
}
// DM rooms
for i := 0; i < dmCount; i++ {
id := newUUID()
user1 := allUsers[rng.Intn(len(allUsers))]
user2 := allUsers[rng.Intn(len(allUsers))]
if user1.ID == user2.ID {
continue
}
slug := fmt.Sprintf("dm-%d", i)
createdAt := RandomTimeAfter(user1.CreatedAt)
r := SeededRoom{ID: id, CreatorID: user1.ID, Name: "DM"}
rooms = append(rooms, r)
roomRows = append(roomRows, []interface{}{
id, nil, slug, nil,
"direct", true, nil, 2,
user1.ID, 0, 0, user1.ID, true,
createdAt, createdAt, nil,
})
}
_, err := BulkInsert(db, "rooms",
"id, name, slug, description, room_type, is_private, password_hash, max_members, creator_id, member_count, message_count, owner_id, is_active, created_at, updated_at, deleted_at",
roomRows)
if err != nil {
return nil, fmt.Errorf("insert rooms: %w", err)
}
p.Update(len(roomRows))
p.Done()
// ── 2. Room members ──────────────────────────────────────────────────────
p = NewProgress("room_members", len(rooms)*5)
memberRows := make([][]interface{}, 0, len(rooms)*5)
memberSeen := make(map[string]bool)
for ri, room := range rooms {
// Always add the creator as owner
key := room.ID + ":" + room.CreatorID
if !memberSeen[key] {
memberSeen[key] = true
memberRows = append(memberRows, []interface{}{
newUUID(), room.ID, room.CreatorID, "owner", false, false, nil,
time.Now(), time.Now(), time.Now(), nil,
})
}
// Add members
var memberCount int
if ri < groupCount {
memberCount = randInt(3, 20) // group rooms
} else {
memberCount = 1 // DM: just the other person
}
for j := 0; j < memberCount; j++ {
member := allUsers[rng.Intn(len(allUsers))]
key = room.ID + ":" + member.ID
if memberSeen[key] {
continue
}
memberSeen[key] = true
memberRows = append(memberRows, []interface{}{
newUUID(), room.ID, member.ID, "member", false, false, nil,
time.Now(), time.Now(), time.Now(), nil,
})
}
}
_, err = BulkInsert(db, "room_members",
"id, room_id, user_id, role, is_banned, is_muted, last_read_at, joined_at, created_at, updated_at, deleted_at",
memberRows)
if err != nil {
return nil, fmt.Errorf("insert room_members: %w", err)
}
p.Update(len(memberRows))
p.Done()
// ── 3. Messages ──────────────────────────────────────────────────────────
p = NewProgress("messages", cfg.Messages)
msgRows := make([][]interface{}, 0, cfg.Messages)
// Distribute messages across rooms (more active rooms get more messages)
for i := 0; i < cfg.Messages; i++ {
room := rooms[PowerLaw(0, len(rooms)-1, 1.0)]
sender := allUsers[rng.Intn(len(allUsers))]
content := GenMessage()
// Space messages over time
baseTime := DaysAgo(180)
msgTime := RandomTimeBetween(baseTime, time.Now())
msgTime = RealisticHour(msgTime)
msgRows = append(msgRows, []interface{}{
newUUID(), room.ID, sender.ID, content,
"text", nil, nil, // message_type, attachment_file_id, reply_to_id
false, nil, false, false, nil, // is_edited, edited_at, is_deleted, is_pinned, metadata
sender.ID, nil, // user_id, parent_id
msgTime, nil, msgTime,
})
}
_, err = BulkInsert(db, "messages",
"id, room_id, sender_id, content, message_type, attachment_file_id, reply_to_id, is_edited, edited_at, is_deleted, is_pinned, metadata, user_id, parent_id, created_at, deleted_at, updated_at",
msgRows)
if err != nil {
return nil, fmt.Errorf("insert messages: %w", err)
}
p.Update(len(msgRows))
p.Done()
// Update room message_count and member_count
_, _ = db.Exec("UPDATE rooms SET message_count = (SELECT COUNT(*) FROM messages WHERE messages.room_id = rooms.id)")
_, _ = db.Exec("UPDATE rooms SET member_count = (SELECT COUNT(*) FROM room_members WHERE room_members.room_id = rooms.id)")
return rooms, nil
}