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:
2026-08-09 22:47:43 +02:00
commit 8580c996c3
1285 changed files with 325780 additions and 0 deletions
+306
View File
@@ -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"
}
}