Add monitoring service and database schema

- Implement monitoring service with heartbeat, lease tasks, resume tasks, and task result handling.
- Create monitoring time utilities for business date calculations.
- Add unit tests for date window resolution and business day handling.
- Define database schema for monitoring-related tables including quotas, daily reports, and task management.
- Establish migration scripts for creating and dropping monitoring tables.
This commit is contained in:
2026-04-12 09:56:18 +08:00
parent 9b4dd09780
commit 6066f43a7d
67 changed files with 16312 additions and 125 deletions
+326
View File
@@ -403,6 +403,183 @@ export interface PublisherPluginPingResponse {
plugin_installation_id?: number | null;
}
export interface MonitoringLocalPlatformState {
ai_platform_id: string;
connected: boolean;
accessible: boolean;
detected_at?: string | null;
reason_code?: string | null;
reason_message?: string | null;
message?: string | null;
}
export interface MonitoringPluginPingResponse {
installed: boolean;
version?: string;
capabilities?: Array<"ping" | "detect" | "heartbeat" | "lease" | "background">;
installation_key?: string;
plugin_installation_id?: number | null;
}
export interface MonitoringHeartbeatPlatformPayload {
ai_platform_id: string;
access_status?: string | null;
connected?: boolean | null;
accessible?: boolean | null;
detected_at?: string | null;
reason_code?: string | null;
reason_message?: string | null;
}
export interface MonitoringHeartbeatPayload {
platforms: MonitoringHeartbeatPlatformPayload[];
}
export interface MonitoringHeartbeatResponse {
installation_id: number;
business_date: string;
updated_platform_count: number;
reconciled_skipped_task_count: number;
}
export interface MonitoringHeartbeatSyncResult {
success: boolean;
source: "remote" | "local";
platform_states: MonitoringLocalPlatformState[];
heartbeat?: MonitoringHeartbeatResponse | null;
message?: string | null;
}
export interface MonitoringLeaseTasksPayload {
limit?: number;
ai_platform_ids?: string[];
}
export interface MonitoringResumeTasksPayload {
ai_platform_ids?: string[];
}
export interface MonitoringLeaseTask {
task_id: number;
brand_id: number;
question_id: number;
question_hash: string;
question_text: string;
ai_platform_id: string;
platform_name: string;
collector_type: string;
run_mode: string;
trigger_source: string;
business_date: string;
lease_token: string;
lease_expires_at: string;
}
export interface MonitoringLeaseTasksResponse {
business_date: string;
lease_count: number;
tasks: MonitoringLeaseTask[];
}
export interface MonitoringResumeTasksResponse {
business_date: string;
resume_count: number;
tasks: MonitoringLeaseTask[];
}
export interface MonitoringCycleResult {
success: boolean;
leased_task_count: number;
processed_task_count: number;
failed_task_count: number;
skipped_task_count: number;
message?: string | null;
}
export interface MonitoringCycleKickoffResponse {
accepted: boolean;
status: "started" | "already_running";
message?: string | null;
}
export interface MonitoringSourceItem {
url: string;
title?: string | null;
site_name?: string | null;
site_key?: string | null;
normalized_url?: string | null;
host?: string | null;
registrable_domain?: string | null;
subdomain?: string | null;
suffix?: string | null;
article_id?: number | null;
publish_record_id?: number | null;
resolution_status?: string | null;
resolution_confidence?: string | null;
}
export interface MonitoringTaskResultPayload {
lease_token: string;
status: "succeeded" | "failed";
provider_model?: string | null;
provider_request_id?: string | null;
request_id?: string | null;
answer?: string | null;
raw_response_json?: Record<string, JsonValue>;
citations?: MonitoringSourceItem[];
search_results?: MonitoringSourceItem[];
brand_mentioned?: boolean | null;
brand_mention_position?: string | null;
first_recommended?: boolean | null;
sentiment_label?: string | null;
matched_brand_terms?: string[];
error_message?: string | null;
completed_at?: string | null;
}
export interface MonitoringTaskResultResponse {
task_id: number;
run_id?: number | null;
task_status: string;
citation_source_count: number;
content_citation_count: number;
}
export interface MonitoringSkipTaskPayload {
lease_token: string;
skip_reason?: string | null;
error_message?: string | null;
completed_at?: string | null;
}
export interface MonitoringSkipTaskResponse {
task_id: number;
task_status: string;
skip_reason: string;
completed_at?: string | null;
}
export interface MonitoringRuntimeStateSnapshot {
installation_key: string;
plugin_installation_id: number | null;
api_base_url: string | null;
monitoring_last_heartbeat_at: string | null;
monitoring_last_heartbeat_status: string | null;
monitoring_last_cycle_at: string | null;
monitoring_last_cycle_status: string | null;
monitoring_platforms: Array<
MonitoringLocalPlatformState & {
platform_name: string;
short_name: string;
accent_color: string;
home_url: string;
login_url: string | null;
access_requirement: "login_required" | "anonymous_allowed";
cookie_domains: string[];
}
>;
}
export interface RegisterPluginInstallationRequest {
installation_key: string;
installation_name: string;
@@ -538,6 +715,155 @@ export interface Competitor {
created_at: string;
}
export interface MonitoringOverview {
collection_mode: string;
mention_rate: number | null;
top1_mention_rate: number | null;
first_recommend_rate: number | null;
positive_mention_rate: number | null;
citation_rate: number | null;
desired_sample_count: number;
planned_sample_count: number;
actual_sample_count: number;
coverage_rate: number | null;
confidence_level: string;
last_sampled_at: string | null;
last_trigger_source: string | null;
prev_snapshot_mention_rate: number | null;
prev_snapshot_top1_mention_rate: number | null;
prev_snapshot_first_recommend_rate: number | null;
prev_snapshot_positive_mention_rate: number | null;
}
export interface MonitoringPlatformBreakdownItem {
ai_platform_id: string;
platform_name: string;
mention_rate: number | null;
top1_mention_rate: number | null;
platform_sample_status: string;
actual_sample_count: number;
last_sampled_at: string | null;
}
export interface MonitoringTimeBucket {
date: string;
sample_status: string;
metric_value: number | null;
mention_rate: number | null;
top1_mention_rate: number | null;
first_recommend_rate: number | null;
positive_mention_rate: number | null;
citation_rate: number | null;
planned_sample_count: number;
actual_sample_count: number;
coverage_rate: number | null;
trigger_source: string | null;
snapshot_updated_at: string | null;
}
export interface MonitoringHotQuestion {
question_id: number;
question_hash: string;
question_text: string;
mention_rate: number | null;
last_sampled_at: string | null;
}
export interface MonitoringCitationRankingItem {
ai_platform_id: string;
platform_name: string;
sample_status: string;
cited_answer_count: number;
cited_article_count: number;
citation_rate: number | null;
}
export interface MonitoringCitedArticle {
article_id: number;
article_title: string;
publish_platform: string;
citation_count: number;
citation_rate: number | null;
}
export interface MonitoringDashboardCompositeResponse {
overview: MonitoringOverview;
platform_breakdown: MonitoringPlatformBreakdownItem[];
brand_time_buckets: MonitoringTimeBucket[];
hot_questions: MonitoringHotQuestion[];
citation_ranking: MonitoringCitationRankingItem[];
cited_articles: MonitoringCitedArticle[];
}
export interface MonitoringQuestionDetailCitation {
cited_url: string;
cited_title: string | null;
site_name: string;
site_key: string;
favicon_url: string;
article_id: number | null;
article_title?: string | null;
resolution_status: string;
resolution_confidence: string;
}
export interface MonitoringQuestionDetailPlatform {
ai_platform_id: string;
platform_name: string;
sample_status: string;
run_id: number | null;
sampled_at: string | null;
provider_model: string | null;
answer_text: string | null;
brand_mentioned: boolean | null;
brand_mention_position: string | null;
citations: MonitoringQuestionDetailCitation[];
}
export interface MonitoringQuestionCitationAnalysisItem {
ai_platform_id: string;
platform_name: string;
site_name: string;
site_key: string;
site_domain: string;
citation_count: number;
citation_rate: number | null;
content_citation_count: number;
}
export interface MonitoringQuestionContentCitation {
article_id: number;
article_title: string;
publish_platform: string;
ai_platform_id: string;
platform_name: string;
citation_count: number;
citation_rate: number | null;
}
export interface MonitoringQuestionDetailResponse {
question_id: number;
question_hash: string;
question_text: string;
time_window: {
date_from: string;
date_to: string;
};
platforms: MonitoringQuestionDetailPlatform[];
citation_analysis: MonitoringQuestionCitationAnalysisItem[];
content_citations: MonitoringQuestionContentCitation[];
}
export interface MonitoringCollectNowResponse {
collection_mode: string;
refreshed_task_count: number;
created_task_count?: number;
leased_task_count: number;
completed_task_count: number;
has_effective_snapshot: boolean;
message: string;
}
export interface KnowledgeGroup {
id: number;
name: string;