Add unified Stella Assistant: mascot + search + AI chat as one
Merge three disconnected help surfaces (Stella mascot, Ctrl+K search, Advisory AI chat) into one unified assistant. Mascot is the face, search is its memory, AI chat is its voice. Backend: - DB schema (060/061): tips, greetings, glossary, tours, user_state tables with 189 tips + 101 greetings seed data - REST API: GET tips/glossary/tours, GET/PUT user-state with longest-prefix route matching and locale fallback - Admin endpoints: CRUD for tips, glossary, tours (SetupAdmin policy) Frontend: - StellaAssistantService: unified mode management (tips/search/chat), API-backed tips with static fallback, i18n integration - Three-mode mascot component: tips, inline search, embedded chat - StellaGlossaryDirective: DB-backed tooltip annotations for domain terms - Admin tip editor: CRUD for tips/glossary/tours in Console Admin - Tour player: step-through guided tours with element highlighting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
-- SPRINT_20260329_007 / Unified Stella Assistant
|
||||
-- DB-backed contextual tips, glossary, tours, and user state for the Stella mascot.
|
||||
-- Replaces hardcoded English-only tips with locale-aware, admin-editable content.
|
||||
|
||||
CREATE SCHEMA IF NOT EXISTS platform;
|
||||
|
||||
-- ─── Tips: page/tab-level contextual help ───────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS platform.assistant_tips (
|
||||
tip_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
route_pattern TEXT NOT NULL,
|
||||
context_trigger TEXT,
|
||||
locale VARCHAR(10) NOT NULL DEFAULT 'en-US',
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
title TEXT NOT NULL,
|
||||
body TEXT NOT NULL,
|
||||
action_label TEXT,
|
||||
action_route TEXT,
|
||||
learn_more_url TEXT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
product_version VARCHAR(32),
|
||||
tenant_id VARCHAR(128) NOT NULL DEFAULT '_system',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
created_by VARCHAR(256) NOT NULL DEFAULT 'system',
|
||||
|
||||
CONSTRAINT ux_assistant_tips_route_ctx_locale_order
|
||||
UNIQUE (tenant_id, route_pattern, context_trigger, locale, sort_order)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_assistant_tips_route_locale
|
||||
ON platform.assistant_tips (route_pattern, locale)
|
||||
WHERE is_active;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_assistant_tips_context
|
||||
ON platform.assistant_tips (context_trigger)
|
||||
WHERE context_trigger IS NOT NULL AND is_active;
|
||||
|
||||
-- ─── Greetings: per-page greeting text ──────────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS platform.assistant_greetings (
|
||||
greeting_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
route_pattern TEXT NOT NULL,
|
||||
locale VARCHAR(10) NOT NULL DEFAULT 'en-US',
|
||||
greeting_text TEXT NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
tenant_id VARCHAR(128) NOT NULL DEFAULT '_system',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT ux_assistant_greetings_route_locale
|
||||
UNIQUE (tenant_id, route_pattern, locale)
|
||||
);
|
||||
|
||||
-- ─── Glossary: domain term definitions ──────────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS platform.assistant_glossary (
|
||||
term_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
term VARCHAR(128) NOT NULL,
|
||||
locale VARCHAR(10) NOT NULL DEFAULT 'en-US',
|
||||
definition TEXT NOT NULL,
|
||||
extended_help TEXT,
|
||||
related_terms TEXT[] NOT NULL DEFAULT '{}',
|
||||
related_routes TEXT[] NOT NULL DEFAULT '{}',
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
tenant_id VARCHAR(128) NOT NULL DEFAULT '_system',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT ux_assistant_glossary_term_locale
|
||||
UNIQUE (tenant_id, term, locale)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_assistant_glossary_locale
|
||||
ON platform.assistant_glossary (locale)
|
||||
WHERE is_active;
|
||||
|
||||
-- ─── Tours: guided walkthroughs ─────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS platform.assistant_tours (
|
||||
tour_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tour_key VARCHAR(128) NOT NULL,
|
||||
locale VARCHAR(10) NOT NULL DEFAULT 'en-US',
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
steps JSONB NOT NULL DEFAULT '[]',
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
tenant_id VARCHAR(128) NOT NULL DEFAULT '_system',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT ux_assistant_tours_key_locale
|
||||
UNIQUE (tenant_id, tour_key, locale)
|
||||
);
|
||||
|
||||
-- ─── User state: per-user mascot preferences ───────────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS platform.assistant_user_state (
|
||||
user_id VARCHAR(256) NOT NULL,
|
||||
tenant_id VARCHAR(128) NOT NULL,
|
||||
seen_routes TEXT[] NOT NULL DEFAULT '{}',
|
||||
completed_tours TEXT[] NOT NULL DEFAULT '{}',
|
||||
tip_positions JSONB NOT NULL DEFAULT '{}',
|
||||
dismissed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
last_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
PRIMARY KEY (user_id, tenant_id)
|
||||
);
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user