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:
master
2026-03-30 17:24:39 +03:00
parent ae5059aa1c
commit 8931fc7c0c
21 changed files with 9649 additions and 324 deletions

View File

@@ -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)
);