refactor(core): restructure conversation/channel/message domains and modernize deployment

- Replace chat package with conversation flow architecture
- Add channel identity avatar support (migration 0002)
- Refactor channel adapters, identities, and message routing
- Update frontend: simplify composables, modernize UI components
- Improve Docker builds with cache mounts and version metadata
- Optimize healthchecks and simplify service dependencies
This commit is contained in:
BBQ
2026-02-12 20:52:34 +08:00
parent 30281742ef
commit 1c15eb2146
121 changed files with 3514 additions and 5961 deletions
+25 -12
View File
@@ -15,7 +15,7 @@ const clearChannelIdentityLinkedUser = `-- name: ClearChannelIdentityLinkedUser
UPDATE channel_identities
SET user_id = NULL, updated_at = now()
WHERE id = $1
RETURNING id, user_id, channel_type, channel_subject_id, display_name, metadata, created_at, updated_at
RETURNING id, user_id, channel_type, channel_subject_id, display_name, avatar_url, metadata, created_at, updated_at
`
func (q *Queries) ClearChannelIdentityLinkedUser(ctx context.Context, id pgtype.UUID) (ChannelIdentity, error) {
@@ -27,6 +27,7 @@ func (q *Queries) ClearChannelIdentityLinkedUser(ctx context.Context, id pgtype.
&i.ChannelType,
&i.ChannelSubjectID,
&i.DisplayName,
&i.AvatarUrl,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
@@ -35,9 +36,9 @@ func (q *Queries) ClearChannelIdentityLinkedUser(ctx context.Context, id pgtype.
}
const createChannelIdentity = `-- name: CreateChannelIdentity :one
INSERT INTO channel_identities (user_id, channel_type, channel_subject_id, display_name, metadata)
VALUES ($1, $2, $3, $4, $5)
RETURNING id, user_id, channel_type, channel_subject_id, display_name, metadata, created_at, updated_at
INSERT INTO channel_identities (user_id, channel_type, channel_subject_id, display_name, avatar_url, metadata)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, user_id, channel_type, channel_subject_id, display_name, avatar_url, metadata, created_at, updated_at
`
type CreateChannelIdentityParams struct {
@@ -45,6 +46,7 @@ type CreateChannelIdentityParams struct {
ChannelType string `json:"channel_type"`
ChannelSubjectID string `json:"channel_subject_id"`
DisplayName pgtype.Text `json:"display_name"`
AvatarUrl pgtype.Text `json:"avatar_url"`
Metadata []byte `json:"metadata"`
}
@@ -54,6 +56,7 @@ func (q *Queries) CreateChannelIdentity(ctx context.Context, arg CreateChannelId
arg.ChannelType,
arg.ChannelSubjectID,
arg.DisplayName,
arg.AvatarUrl,
arg.Metadata,
)
var i ChannelIdentity
@@ -63,6 +66,7 @@ func (q *Queries) CreateChannelIdentity(ctx context.Context, arg CreateChannelId
&i.ChannelType,
&i.ChannelSubjectID,
&i.DisplayName,
&i.AvatarUrl,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
@@ -71,7 +75,7 @@ func (q *Queries) CreateChannelIdentity(ctx context.Context, arg CreateChannelId
}
const getChannelIdentityByChannelSubject = `-- name: GetChannelIdentityByChannelSubject :one
SELECT id, user_id, channel_type, channel_subject_id, display_name, metadata, created_at, updated_at
SELECT id, user_id, channel_type, channel_subject_id, display_name, avatar_url, metadata, created_at, updated_at
FROM channel_identities
WHERE channel_type = $1 AND channel_subject_id = $2
`
@@ -90,6 +94,7 @@ func (q *Queries) GetChannelIdentityByChannelSubject(ctx context.Context, arg Ge
&i.ChannelType,
&i.ChannelSubjectID,
&i.DisplayName,
&i.AvatarUrl,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
@@ -98,7 +103,7 @@ func (q *Queries) GetChannelIdentityByChannelSubject(ctx context.Context, arg Ge
}
const getChannelIdentityByID = `-- name: GetChannelIdentityByID :one
SELECT id, user_id, channel_type, channel_subject_id, display_name, metadata, created_at, updated_at
SELECT id, user_id, channel_type, channel_subject_id, display_name, avatar_url, metadata, created_at, updated_at
FROM channel_identities
WHERE id = $1
`
@@ -112,6 +117,7 @@ func (q *Queries) GetChannelIdentityByID(ctx context.Context, id pgtype.UUID) (C
&i.ChannelType,
&i.ChannelSubjectID,
&i.DisplayName,
&i.AvatarUrl,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
@@ -120,7 +126,7 @@ func (q *Queries) GetChannelIdentityByID(ctx context.Context, id pgtype.UUID) (C
}
const getChannelIdentityByIDForUpdate = `-- name: GetChannelIdentityByIDForUpdate :one
SELECT id, user_id, channel_type, channel_subject_id, display_name, metadata, created_at, updated_at
SELECT id, user_id, channel_type, channel_subject_id, display_name, avatar_url, metadata, created_at, updated_at
FROM channel_identities
WHERE id = $1
FOR UPDATE
@@ -135,6 +141,7 @@ func (q *Queries) GetChannelIdentityByIDForUpdate(ctx context.Context, id pgtype
&i.ChannelType,
&i.ChannelSubjectID,
&i.DisplayName,
&i.AvatarUrl,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
@@ -143,7 +150,7 @@ func (q *Queries) GetChannelIdentityByIDForUpdate(ctx context.Context, id pgtype
}
const listChannelIdentitiesByUserID = `-- name: ListChannelIdentitiesByUserID :many
SELECT id, user_id, channel_type, channel_subject_id, display_name, metadata, created_at, updated_at
SELECT id, user_id, channel_type, channel_subject_id, display_name, avatar_url, metadata, created_at, updated_at
FROM channel_identities
WHERE user_id = $1
ORDER BY created_at DESC
@@ -164,6 +171,7 @@ func (q *Queries) ListChannelIdentitiesByUserID(ctx context.Context, userID pgty
&i.ChannelType,
&i.ChannelSubjectID,
&i.DisplayName,
&i.AvatarUrl,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
@@ -182,7 +190,7 @@ const setChannelIdentityLinkedUser = `-- name: SetChannelIdentityLinkedUser :one
UPDATE channel_identities
SET user_id = $2, updated_at = now()
WHERE id = $1
RETURNING id, user_id, channel_type, channel_subject_id, display_name, metadata, created_at, updated_at
RETURNING id, user_id, channel_type, channel_subject_id, display_name, avatar_url, metadata, created_at, updated_at
`
type SetChannelIdentityLinkedUserParams struct {
@@ -199,6 +207,7 @@ func (q *Queries) SetChannelIdentityLinkedUser(ctx context.Context, arg SetChann
&i.ChannelType,
&i.ChannelSubjectID,
&i.DisplayName,
&i.AvatarUrl,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
@@ -207,15 +216,16 @@ func (q *Queries) SetChannelIdentityLinkedUser(ctx context.Context, arg SetChann
}
const upsertChannelIdentityByChannelSubject = `-- name: UpsertChannelIdentityByChannelSubject :one
INSERT INTO channel_identities (user_id, channel_type, channel_subject_id, display_name, metadata)
VALUES ($1, $2, $3, $4, $5)
INSERT INTO channel_identities (user_id, channel_type, channel_subject_id, display_name, avatar_url, metadata)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (channel_type, channel_subject_id)
DO UPDATE SET
display_name = COALESCE(NULLIF(EXCLUDED.display_name, ''), channel_identities.display_name),
avatar_url = COALESCE(NULLIF(EXCLUDED.avatar_url, ''), channel_identities.avatar_url),
metadata = EXCLUDED.metadata,
user_id = COALESCE(channel_identities.user_id, EXCLUDED.user_id),
updated_at = now()
RETURNING id, user_id, channel_type, channel_subject_id, display_name, metadata, created_at, updated_at
RETURNING id, user_id, channel_type, channel_subject_id, display_name, avatar_url, metadata, created_at, updated_at
`
type UpsertChannelIdentityByChannelSubjectParams struct {
@@ -223,6 +233,7 @@ type UpsertChannelIdentityByChannelSubjectParams struct {
ChannelType string `json:"channel_type"`
ChannelSubjectID string `json:"channel_subject_id"`
DisplayName pgtype.Text `json:"display_name"`
AvatarUrl pgtype.Text `json:"avatar_url"`
Metadata []byte `json:"metadata"`
}
@@ -232,6 +243,7 @@ func (q *Queries) UpsertChannelIdentityByChannelSubject(ctx context.Context, arg
arg.ChannelType,
arg.ChannelSubjectID,
arg.DisplayName,
arg.AvatarUrl,
arg.Metadata,
)
var i ChannelIdentity
@@ -241,6 +253,7 @@ func (q *Queries) UpsertChannelIdentityByChannelSubject(ctx context.Context, arg
&i.ChannelType,
&i.ChannelSubjectID,
&i.DisplayName,
&i.AvatarUrl,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
+90 -62
View File
@@ -122,21 +122,24 @@ func (q *Queries) DeleteMessagesByBot(ctx context.Context, botID pgtype.UUID) er
const listMessages = `-- name: ListMessages :many
SELECT
id,
bot_id,
route_id,
sender_channel_identity_id,
sender_account_user_id AS sender_user_id,
channel_type AS platform,
source_message_id AS external_message_id,
source_reply_to_message_id,
role,
content,
metadata,
created_at
FROM bot_history_messages
WHERE bot_id = $1
ORDER BY created_at ASC
m.id,
m.bot_id,
m.route_id,
m.sender_channel_identity_id,
m.sender_account_user_id AS sender_user_id,
m.channel_type AS platform,
m.source_message_id AS external_message_id,
m.source_reply_to_message_id,
m.role,
m.content,
m.metadata,
m.created_at,
ci.display_name AS sender_display_name,
ci.avatar_url AS sender_avatar_url
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
WHERE m.bot_id = $1
ORDER BY m.created_at ASC
`
type ListMessagesRow struct {
@@ -152,6 +155,8 @@ type ListMessagesRow struct {
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
}
func (q *Queries) ListMessages(ctx context.Context, botID pgtype.UUID) ([]ListMessagesRow, error) {
@@ -176,6 +181,8 @@ func (q *Queries) ListMessages(ctx context.Context, botID pgtype.UUID) ([]ListMe
&i.Content,
&i.Metadata,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
); err != nil {
return nil, err
}
@@ -189,22 +196,25 @@ func (q *Queries) ListMessages(ctx context.Context, botID pgtype.UUID) ([]ListMe
const listMessagesBefore = `-- name: ListMessagesBefore :many
SELECT
id,
bot_id,
route_id,
sender_channel_identity_id,
sender_account_user_id AS sender_user_id,
channel_type AS platform,
source_message_id AS external_message_id,
source_reply_to_message_id,
role,
content,
metadata,
created_at
FROM bot_history_messages
WHERE bot_id = $1
AND created_at < $2
ORDER BY created_at DESC
m.id,
m.bot_id,
m.route_id,
m.sender_channel_identity_id,
m.sender_account_user_id AS sender_user_id,
m.channel_type AS platform,
m.source_message_id AS external_message_id,
m.source_reply_to_message_id,
m.role,
m.content,
m.metadata,
m.created_at,
ci.display_name AS sender_display_name,
ci.avatar_url AS sender_avatar_url
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
WHERE m.bot_id = $1
AND m.created_at < $2
ORDER BY m.created_at DESC
LIMIT $3
`
@@ -227,6 +237,8 @@ type ListMessagesBeforeRow struct {
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
}
func (q *Queries) ListMessagesBefore(ctx context.Context, arg ListMessagesBeforeParams) ([]ListMessagesBeforeRow, error) {
@@ -251,6 +263,8 @@ func (q *Queries) ListMessagesBefore(ctx context.Context, arg ListMessagesBefore
&i.Content,
&i.Metadata,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
); err != nil {
return nil, err
}
@@ -264,21 +278,24 @@ func (q *Queries) ListMessagesBefore(ctx context.Context, arg ListMessagesBefore
const listMessagesLatest = `-- name: ListMessagesLatest :many
SELECT
id,
bot_id,
route_id,
sender_channel_identity_id,
sender_account_user_id AS sender_user_id,
channel_type AS platform,
source_message_id AS external_message_id,
source_reply_to_message_id,
role,
content,
metadata,
created_at
FROM bot_history_messages
WHERE bot_id = $1
ORDER BY created_at DESC
m.id,
m.bot_id,
m.route_id,
m.sender_channel_identity_id,
m.sender_account_user_id AS sender_user_id,
m.channel_type AS platform,
m.source_message_id AS external_message_id,
m.source_reply_to_message_id,
m.role,
m.content,
m.metadata,
m.created_at,
ci.display_name AS sender_display_name,
ci.avatar_url AS sender_avatar_url
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
WHERE m.bot_id = $1
ORDER BY m.created_at DESC
LIMIT $2
`
@@ -300,6 +317,8 @@ type ListMessagesLatestRow struct {
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
}
func (q *Queries) ListMessagesLatest(ctx context.Context, arg ListMessagesLatestParams) ([]ListMessagesLatestRow, error) {
@@ -324,6 +343,8 @@ func (q *Queries) ListMessagesLatest(ctx context.Context, arg ListMessagesLatest
&i.Content,
&i.Metadata,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
); err != nil {
return nil, err
}
@@ -337,22 +358,25 @@ func (q *Queries) ListMessagesLatest(ctx context.Context, arg ListMessagesLatest
const listMessagesSince = `-- name: ListMessagesSince :many
SELECT
id,
bot_id,
route_id,
sender_channel_identity_id,
sender_account_user_id AS sender_user_id,
channel_type AS platform,
source_message_id AS external_message_id,
source_reply_to_message_id,
role,
content,
metadata,
created_at
FROM bot_history_messages
WHERE bot_id = $1
AND created_at >= $2
ORDER BY created_at ASC
m.id,
m.bot_id,
m.route_id,
m.sender_channel_identity_id,
m.sender_account_user_id AS sender_user_id,
m.channel_type AS platform,
m.source_message_id AS external_message_id,
m.source_reply_to_message_id,
m.role,
m.content,
m.metadata,
m.created_at,
ci.display_name AS sender_display_name,
ci.avatar_url AS sender_avatar_url
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
WHERE m.bot_id = $1
AND m.created_at >= $2
ORDER BY m.created_at ASC
`
type ListMessagesSinceParams struct {
@@ -373,6 +397,8 @@ type ListMessagesSinceRow struct {
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
}
func (q *Queries) ListMessagesSince(ctx context.Context, arg ListMessagesSinceParams) ([]ListMessagesSinceRow, error) {
@@ -397,6 +423,8 @@ func (q *Queries) ListMessagesSince(ctx context.Context, arg ListMessagesSincePa
&i.Content,
&i.Metadata,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
); err != nil {
return nil, err
}
+1
View File
@@ -93,6 +93,7 @@ type ChannelIdentity struct {
ChannelType string `json:"channel_type"`
ChannelSubjectID string `json:"channel_subject_id"`
DisplayName pgtype.Text `json:"display_name"`
AvatarUrl pgtype.Text `json:"avatar_url"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`