feat: Introduce AI Brand Monitoring System V5 technical design document

- Added comprehensive technical design document for AI Brand Monitoring System V5, outlining system architecture, data models, sampling strategies, and monitoring protocols.
- Key changes include a shift to a sampling-based trend monitoring approach, updated data collection and storage strategies, and new metrics for performance evaluation.
- Implemented migration scripts to support the flattening of brand questions and versioning of question texts, ensuring historical data integrity and version control.
This commit is contained in:
2026-04-09 14:43:20 +08:00
parent 41f8e0621e
commit 36451a613d
18 changed files with 2709 additions and 234 deletions
@@ -1,12 +1,12 @@
CREATE TABLE brand_questions (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id),
brand_id BIGINT NOT NULL REFERENCES brands(id),
keyword_id BIGINT NOT NULL REFERENCES brand_keywords(id),
current_version_id BIGINT,
status VARCHAR(20) NOT NULL DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id),
brand_id BIGINT NOT NULL REFERENCES brands(id),
keyword_id BIGINT NOT NULL REFERENCES brand_keywords(id),
question_text TEXT NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
CREATE INDEX idx_brand_questions_keyword ON brand_questions(keyword_id);
@@ -1 +1 @@
DROP TABLE IF EXISTS brand_question_versions;
-- No-op: question versioning was removed during development.
@@ -1,11 +1 @@
CREATE TABLE brand_question_versions (
id BIGSERIAL PRIMARY KEY,
question_id BIGINT NOT NULL REFERENCES brand_questions(id),
question_text TEXT NOT NULL,
question_hash VARCHAR(64) NOT NULL,
version_no INT NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uk_question_version_no UNIQUE (question_id, version_no)
);
CREATE INDEX idx_question_hash ON brand_question_versions(question_hash);
-- No-op: question versioning was removed during development.
@@ -0,0 +1,37 @@
ALTER TABLE brand_questions
ADD COLUMN IF NOT EXISTS current_version_id BIGINT;
CREATE TABLE IF NOT EXISTS brand_question_versions (
id BIGSERIAL PRIMARY KEY,
question_id BIGINT NOT NULL REFERENCES brand_questions(id),
question_text TEXT NOT NULL,
question_hash VARCHAR(64) NOT NULL,
version_no INT NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uk_question_version_no UNIQUE (question_id, version_no)
);
CREATE INDEX IF NOT EXISTS idx_question_hash ON brand_question_versions(question_hash);
INSERT INTO brand_question_versions (question_id, question_text, question_hash, version_no, is_active)
SELECT q.id,
q.question_text,
md5(q.question_text),
1,
true
FROM brand_questions q
WHERE NOT EXISTS (
SELECT 1
FROM brand_question_versions v
WHERE v.question_id = q.id
);
UPDATE brand_questions q
SET current_version_id = v.id
FROM brand_question_versions v
WHERE v.question_id = q.id
AND v.version_no = 1;
ALTER TABLE brand_questions
DROP COLUMN IF EXISTS question_text;
@@ -0,0 +1,29 @@
ALTER TABLE brand_questions
ADD COLUMN IF NOT EXISTS question_text TEXT;
UPDATE brand_questions q
SET question_text = COALESCE(
(
SELECT v.question_text
FROM brand_question_versions v
WHERE v.id = q.current_version_id
LIMIT 1
),
(
SELECT v.question_text
FROM brand_question_versions v
WHERE v.question_id = q.id
ORDER BY v.version_no DESC, v.id DESC
LIMIT 1
),
''
)
WHERE q.question_text IS NULL;
ALTER TABLE brand_questions
ALTER COLUMN question_text SET NOT NULL;
ALTER TABLE brand_questions
DROP COLUMN IF EXISTS current_version_id;
DROP TABLE IF EXISTS brand_question_versions;