Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
{
|
||||
"doc": "01-extension-points",
|
||||
"agent": "1/10",
|
||||
"generated_for": "support-auto",
|
||||
"related_docs": [
|
||||
"docs/support-auto/01-inventory.md",
|
||||
"docs/admin-roles-support/11-support-api-contract.json",
|
||||
"docs/admin-roles-support/12-support-backend.md",
|
||||
"docs/admin-roles-support/13-support-ratings.md",
|
||||
"docs/admin-roles-support/14-support-staff-ui.md",
|
||||
"docs/plan-permissions/01-feature-keys.json"
|
||||
],
|
||||
"ai_admin_settings_paths": {
|
||||
"web_ui": {
|
||||
"route": "/admin/settings",
|
||||
"file": "apps/web/src/routes/admin/settings/+page.svelte",
|
||||
"tab": "ai",
|
||||
"label": "AI roles",
|
||||
"roles_shown": ["processing", "vectorization", "docs_api", "support"]
|
||||
},
|
||||
"web_client": {
|
||||
"platform_settings": "apps/web/src/lib/admin-platform-settings.ts",
|
||||
"ai_roles": "apps/web/src/lib/admin-ai-roles.ts",
|
||||
"symbols": [
|
||||
"loadPlatformAdminSettings",
|
||||
"savePlatformAdminSettings",
|
||||
"saveAIRoles",
|
||||
"extractAIRoles",
|
||||
"testAIRole",
|
||||
"AI_ROLES",
|
||||
"AI_ROLE_META.support"
|
||||
],
|
||||
"api": {
|
||||
"get_put": "GET|PUT /api/admin/settings",
|
||||
"payload_key": "ai_roles",
|
||||
"role_probe_expected": "POST /api/admin/settings/ai-roles/{role}/test",
|
||||
"role_probe_status": "client_optional_404_skipped_not_mounted"
|
||||
}
|
||||
},
|
||||
"api": {
|
||||
"handlers": "apps/api/internal/httpapi/admin_settings_handlers.go",
|
||||
"symbols": ["handleGetAdminSettings", "handlePutAdminSettings"],
|
||||
"auth": ["RequireSession", "RequirePlatformAdmin"],
|
||||
"mount": "apps/api/internal/httpapi/server.go"
|
||||
},
|
||||
"platformsettings": {
|
||||
"package": "apps/api/internal/platformsettings",
|
||||
"role_constants": {
|
||||
"file": "apps/api/internal/platformsettings/types.go",
|
||||
"AIRoleProcessing": "processing",
|
||||
"AIRoleVectorization": "vectorization",
|
||||
"AIRoleDocsAPI": "docs_api",
|
||||
"AIRoleSupport": "support",
|
||||
"AIRoles": ["processing", "vectorization", "docs_api", "support"]
|
||||
},
|
||||
"symbols": [
|
||||
{
|
||||
"name": "ValidAIRole",
|
||||
"path": "apps/api/internal/platformsettings/ai_configs.go",
|
||||
"line": 30
|
||||
},
|
||||
{
|
||||
"name": "publicAIConfigs",
|
||||
"path": "apps/api/internal/platformsettings/ai_configs.go",
|
||||
"line": 39,
|
||||
"sym": "sym:descrybe-v2:apps/api/internal/platformsettings/ai_configs.go:39:publicAIConfigs"
|
||||
},
|
||||
{
|
||||
"name": "patchAIConfigs",
|
||||
"path": "apps/api/internal/platformsettings/ai_configs.go",
|
||||
"line": 116
|
||||
},
|
||||
{
|
||||
"name": "ResolveAIConfig",
|
||||
"path": "apps/api/internal/platformsettings/ai_configs.go",
|
||||
"line": 270
|
||||
}
|
||||
],
|
||||
"storage_note": "JSON in platform company_settings (SystemCompanyID); no dedicated AI roles table"
|
||||
},
|
||||
"aiprovider": {
|
||||
"file": "apps/api/internal/aiprovider/roles.go",
|
||||
"RoleSupport": "support",
|
||||
"symbols": [
|
||||
{
|
||||
"name": "ResolveCompleterForRole",
|
||||
"path": "apps/api/internal/aiprovider/roles.go",
|
||||
"line": 44,
|
||||
"sym": "sym:descrybe-v2:apps/api/internal/aiprovider/roles.go:44:ResolveCompleterForRole",
|
||||
"note": "May resolve RoleSupport when slot configured; ticket auto-reply must still gate via TryAutoReplyLLM"
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_for_tickets": {
|
||||
"docs_ask": {
|
||||
"component": "apps/web/src/lib/components/docs/DocsAskGuide.svelte",
|
||||
"guide": "apps/web/src/lib/docs-guide",
|
||||
"rule": "rule-based only; never AIRoleDocsAPI or AIRoleSupport"
|
||||
},
|
||||
"tenant_ai_test": {
|
||||
"path": "POST /integrations/ai/test",
|
||||
"handler": "handleTestAIIntegration",
|
||||
"note": "company BYOK probe, not platform ai_roles"
|
||||
}
|
||||
}
|
||||
},
|
||||
"support_desk_inventory": {
|
||||
"schema": [
|
||||
"apps/api/sql/schema/025_support_center.sql",
|
||||
"apps/api/sql/schema/027_capabilities_support_perf.sql",
|
||||
"apps/api/sql/schema/029_staff_roles.sql",
|
||||
"apps/api/sql/schema/030_support_desk.sql"
|
||||
],
|
||||
"service_package": "apps/api/internal/support",
|
||||
"key_symbols": [
|
||||
{
|
||||
"name": "Create",
|
||||
"path": "apps/api/internal/support/tickets.go",
|
||||
"line": 252,
|
||||
"hook_note": "Post-create extension for content auto-reply; must not call Completer directly"
|
||||
},
|
||||
{
|
||||
"name": "ReplyAsUser",
|
||||
"path": "apps/api/internal/support/tickets.go",
|
||||
"line": 306
|
||||
},
|
||||
{
|
||||
"name": "ReplyAsAgent",
|
||||
"path": "apps/api/internal/support/tickets.go",
|
||||
"line": 369,
|
||||
"hook_note": "Human-only; draft-assist UI should call TryAutoReplyLLM separately"
|
||||
},
|
||||
{
|
||||
"name": "GetAdmin",
|
||||
"path": "apps/api/internal/support/tickets.go",
|
||||
"line": 198,
|
||||
"sym": "sym:descrybe-v2:apps/api/internal/support/tickets.go:198:GetAdmin",
|
||||
"hook_note": "Richer staff detail / CSAT attach point"
|
||||
},
|
||||
{
|
||||
"name": "TryAutoReplyLLM",
|
||||
"path": "apps/api/internal/support/ai_auto_reply.go",
|
||||
"line": 18,
|
||||
"sym": "sym:descrybe-v2:apps/api/internal/support/ai_auto_reply.go:18:TryAutoReplyLLM",
|
||||
"status": "stub_refuses",
|
||||
"error": "ErrAIAutoReplyDisabled"
|
||||
},
|
||||
{
|
||||
"name": "SubmitCSAT",
|
||||
"path": "apps/api/internal/support/ratings.go",
|
||||
"line": 18
|
||||
},
|
||||
{
|
||||
"name": "AggregateCSAT",
|
||||
"path": "apps/api/internal/support/ratings.go",
|
||||
"line": 78
|
||||
},
|
||||
{
|
||||
"name": "Claim",
|
||||
"path": "apps/api/internal/support/desk.go",
|
||||
"line": 108
|
||||
},
|
||||
{
|
||||
"name": "ResolveStaffAccess",
|
||||
"path": "apps/api/internal/auth/staff.go",
|
||||
"line": 64
|
||||
}
|
||||
],
|
||||
"http_routes": {
|
||||
"customer_prefix": "/api/support",
|
||||
"staff_prefix": "/api/admin/support",
|
||||
"staff_middleware": "RequireSupportDesk",
|
||||
"admin_only_examples": [
|
||||
"GET /api/admin/support/csat",
|
||||
"PUT /api/admin/support/agents/{id}",
|
||||
"GET|PUT /api/admin/settings"
|
||||
]
|
||||
},
|
||||
"web": {
|
||||
"customer": [
|
||||
"apps/web/src/routes/support/+page.svelte",
|
||||
"apps/web/src/routes/support/new/+page.svelte",
|
||||
"apps/web/src/routes/support/[ticketId]/+page.svelte"
|
||||
],
|
||||
"staff": [
|
||||
"apps/web/src/routes/admin/support/+page.svelte",
|
||||
"apps/web/src/routes/admin/support/[id]/+page.svelte"
|
||||
],
|
||||
"clients": [
|
||||
"apps/web/src/lib/support/api.ts",
|
||||
"apps/web/src/lib/support/admin-api.ts",
|
||||
"apps/web/src/lib/support/types.ts"
|
||||
]
|
||||
},
|
||||
"plan_permission_keys": {
|
||||
"section": "support",
|
||||
"keys": [
|
||||
"support.center",
|
||||
"support.ticket_create",
|
||||
"support.ticket_thread"
|
||||
],
|
||||
"shell": ["shell.support_notifications"],
|
||||
"defaults": "ON for all public plans per docs/plan-permissions/06-defaults-matrix",
|
||||
"missing_for_auto_reply": [
|
||||
"no support.auto_reply key",
|
||||
"no support.ai_assist key",
|
||||
"CSAT not a separate feature key"
|
||||
]
|
||||
}
|
||||
},
|
||||
"extension_points": {
|
||||
"richer_ticket_detail": [
|
||||
{
|
||||
"id": "staff_get_payload",
|
||||
"target": "GetAdmin / handleAdminGetSupportTicket",
|
||||
"path": "apps/api/internal/support/tickets.go",
|
||||
"opportunity": "Already joins company/requester/assignee + messages + attachCSAT; expose resolved_by, richer org context"
|
||||
},
|
||||
{
|
||||
"id": "admin_client_types",
|
||||
"target": "SupportTicket in admin-api.ts",
|
||||
"path": "apps/web/src/lib/support/admin-api.ts",
|
||||
"gap": "Omits csat / csat_eligible / resolved_by_user_id despite API capability"
|
||||
},
|
||||
{
|
||||
"id": "staff_detail_ui",
|
||||
"target": "admin/support/[id]/+page.svelte",
|
||||
"gap": "Shows subject, category, priority, company, thread, claim/assign — no CSAT panel, no linked resources, no attachments"
|
||||
},
|
||||
{
|
||||
"id": "csat_aggregate_ui",
|
||||
"target": "GET /api/admin/support/csat",
|
||||
"gap": "API exists; no admin UI page/widget"
|
||||
},
|
||||
{
|
||||
"id": "schema_extensions",
|
||||
"note": "No attachments/metadata/product_id columns; author_role=system available for bot messages; csat_token_* unused"
|
||||
}
|
||||
],
|
||||
"auto_response_from_question_content": [
|
||||
{
|
||||
"id": "post_create_hook",
|
||||
"preferred_insert": "after successful Create commit (or async job enqueued from handleCreateSupportTicket)",
|
||||
"inputs": ["CreateInput.subject", "CreateInput.body", "CreateInput.category"],
|
||||
"pattern_reuse": "DocsAskGuide / docs-guide decision tree (rule-based, no LLM)",
|
||||
"output": "insert support_messages author_role=system OR ReplyAsAgent-equivalent with system author"
|
||||
},
|
||||
{
|
||||
"id": "post_user_reply_hook",
|
||||
"target": "ReplyAsUser",
|
||||
"note": "Same matcher for follow-ups; reopen already sets status=open"
|
||||
},
|
||||
{
|
||||
"id": "missing_today",
|
||||
"items": [
|
||||
"no FAQ/canned reply store",
|
||||
"no keyword classifier",
|
||||
"no system first-response writer"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ai_fallback_when_auto_fails": [
|
||||
{
|
||||
"id": "sole_llm_gate",
|
||||
"target": "TryAutoReplyLLM",
|
||||
"path": "apps/api/internal/support/ai_auto_reply.go",
|
||||
"line": 18,
|
||||
"current": "returns ErrAIAutoReplyDisabled",
|
||||
"intended_deps": [
|
||||
"platformsettings.AIRoleSupport / ResolveAIConfig",
|
||||
"aiprovider.ResolveCompleterForRole(..., RoleSupport)"
|
||||
],
|
||||
"contract": "Create/ReplyAsUser/ReplyAsAgent must not call Completer; route AI through this function"
|
||||
},
|
||||
{
|
||||
"id": "config_prerequisite",
|
||||
"path": "/admin/settings ai_roles.support",
|
||||
"fields": ["provider", "base_url", "model", "api_key", "enabled"],
|
||||
"note": "Slot configurable today; product still needs explicit enable beyond stub"
|
||||
},
|
||||
{
|
||||
"id": "suggested_flow",
|
||||
"steps": [
|
||||
"rule/FAQ matcher on question content",
|
||||
"on miss or low confidence → TryAutoReplyLLM",
|
||||
"on LLM refuse/error → leave open for staff claim (no silent drop)",
|
||||
"optional: draft-only for agent UI vs auto-post system message"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "do_not",
|
||||
"items": [
|
||||
"wire DocsAskGuide to AIRoleSupport",
|
||||
"use AIRoleDocsAPI for tickets",
|
||||
"call ResolveCompleterForRole from ReplyAsAgent"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gaps_summary": {
|
||||
"ai_admin": "paths exist and support role is first-class",
|
||||
"auto_reply": "stub only; no content matcher; no enable flag/job",
|
||||
"staff_detail": "basic thread UI; CSAT/org depth/attachments missing in staff client",
|
||||
"plan_keys": "tenant support.* only; no auto-reply entitlements"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user