feat: add monitoring marked articles and retention updates
Frontend CI / Frontend (push) Successful in 7m47s
Backend CI / Backend (push) Successful in 19m26s

This commit is contained in:
2026-06-17 12:48:41 +08:00
parent 9ed857e159
commit 31c4dd9358
40 changed files with 2373 additions and 488 deletions
@@ -18,6 +18,11 @@ type monitoringPublishedAlias struct {
PublishRecordID *int64
ArticleTitle string
PublishPlatform string
OriginalURL string
NormalizedURL string
SourceType string
SourceID int64
SourcePriority int
Ambiguous bool
}
@@ -29,17 +34,51 @@ type monitoringAliasQuerier interface {
func loadMonitoringPublishedAliasIndex(ctx context.Context, q monitoringAliasQuerier, tenantID int64) (monitoringPublishedAliasIndex, error) {
rows, err := q.Query(ctx, `
WITH alias_sources AS (
SELECT
article_id,
publish_record_id,
COALESCE(article_title_snapshot, '未命名文章') AS article_title,
COALESCE(publish_platform_name_snapshot, '已发布内容') AS publish_platform,
original_url,
normalized_url,
'published_article' AS source_type,
article_id AS source_id,
1 AS source_priority,
updated_at AS sort_updated_at,
id AS sort_id
FROM monitoring_article_url_aliases
WHERE tenant_id = $1
AND confidence = 'high'
UNION ALL
SELECT
NULL AS article_id,
NULL AS publish_record_id,
COALESCE(NULLIF(article_title, ''), '未命名文章') AS article_title,
COALESCE(NULLIF(publish_platform, ''), '外部文章') AS publish_platform,
original_url,
normalized_url,
'manual_mark' AS source_type,
id AS source_id,
2 AS source_priority,
updated_at AS sort_updated_at,
id AS sort_id
FROM monitoring_user_marked_articles
WHERE tenant_id = $1
AND expires_at > NOW()
)
SELECT
article_id,
publish_record_id,
COALESCE(article_title_snapshot, '未命名文章') AS article_title,
COALESCE(publish_platform_name_snapshot, '已发布内容') AS publish_platform,
article_title,
publish_platform,
original_url,
normalized_url
FROM monitoring_article_url_aliases
WHERE tenant_id = $1
AND confidence = 'high'
ORDER BY updated_at DESC, id DESC
normalized_url,
source_type,
source_id,
source_priority
FROM alias_sources
ORDER BY source_priority ASC, sort_updated_at DESC, sort_id DESC
`, tenantID)
if err != nil {
return nil, responseInternalAliasLookupError()
@@ -52,13 +91,36 @@ func loadMonitoringPublishedAliasIndex(ctx context.Context, q monitoringAliasQue
var originalURL string
var normalizedURL string
var publishRecordID sql.NullInt64
if scanErr := rows.Scan(&item.ArticleID, &publishRecordID, &item.ArticleTitle, &item.PublishPlatform, &originalURL, &normalizedURL); scanErr != nil {
var articleID sql.NullInt64
if scanErr := rows.Scan(
&articleID,
&publishRecordID,
&item.ArticleTitle,
&item.PublishPlatform,
&originalURL,
&normalizedURL,
&item.SourceType,
&item.SourceID,
&item.SourcePriority,
); scanErr != nil {
return nil, responseInternalAliasScanError()
}
if articleID.Valid {
item.ArticleID = articleID.Int64
}
item.PublishRecordID = nullableInt64Value(publishRecordID)
item.OriginalURL = originalURL
item.NormalizedURL = normalizedURL
for _, key := range monitoringCitationCandidateKeys(originalURL, normalizedURL) {
existing, exists := index[key]
if exists && existing.ArticleID != item.ArticleID {
if exists && existing.SourcePriority < item.SourcePriority {
continue
}
if exists && item.SourcePriority < existing.SourcePriority {
index[key] = item
continue
}
if exists && (existing.SourceType != item.SourceType || existing.SourceID != item.SourceID) {
existing.Ambiguous = true
index[key] = existing
continue