Platforms
A Platform is the multi-tenant unit for the Analytics section. Picking one
narrows every downstream surface — Discover, Visualize, Alerting, Anomaly
Detection, Semantic Search, Cortex AI, OSD Dashboards list, Notifications
channels — to that platform’s associated_indexes and injects its
custom_knowledge into Cortex’s system prompt.
Platforms are stored in logrite-ai-service’s SQLite (platforms table)
alongside conversations, so they survive the same Coolify Redeploys the
bind-mount runbook covers. The legacy hardcoded domain presets
(Universal, Worksoft CTM) still ship for built-in coverage; user
platforms are merged on top via /api/v1/domains.
Anatomy of a Platform
Section titled “Anatomy of a Platform”| Field | Purpose |
|---|---|
name | Display label in the selector |
key | URL-safe identifier (auto-derived from name) |
description | Subtitle shown on the Platforms page |
associated_indexes[] | The visibility allow-list. Drives index dropdowns, monitor filters, dashboard scope, semantic search fan-out. Supports glob patterns (ctm*). |
custom_knowledge | Free-form Markdown injected into Cortex AI’s system prompt when the platform is the active domain |
suggested_prompts[] | Starter prompts shown at the bottom of a new Cortex chat |
members[] | Empty = everyone in the owning workspace. Non-empty = restricted to those sub values + the creator, still within that workspace |
workspace_id | The workspace that owns the platform (since 2026-10-01). Never another workspace’s to see |
| documents | Files uploaded to the platform (see Documents). Not a column: their own tables |
Workspace isolation (2026-10-01)
Section titled “Workspace isolation (2026-10-01)”Before this date a platform had no owner: GET /api/v1/domains answered without a
login and listed every customer’s platforms with their index names; a platform’s
custom_knowledge reached the prompt of anyone who named its key; and a platform with an
empty members list granted its indexes to every chat user on the estate.
Now every platform belongs to the workspace that created it, and one function
(services/platform/scope.ts → visibleTo) decides who sees it — every route, the chat
handler’s index allowance, the system prompt and the follow-up suggestions all call it:
- visible only inside its workspace; inside it,
membersnarrows as before; - a platform created before isolation (empty
workspace_id) is visible to its creator only, since nobody else can be shown to have owned it; - a caller with no workspace in their token sees nothing;
- another workspace’s platform answers 404, never 403, so its existence is not disclosed.
GET /api/v1/domains now requires a login. Platforms are available to every
workspace; there is no plan gate.
Documents — what Cortex answers from
Section titled “Documents — what Cortex answers from”Upload runbooks, product docs, exported logs and similar files to a platform. When a user picks that platform in the Cortex composer, the passages that best match each question are added to Cortex’s prompt, with the document name to cite.
| Formats | PDF, Word, Excel, PowerPoint, text, Markdown, logs, code, JSON, CSV — the same extractor as chat attachments, with the same secret redaction |
| Not accepted | Images (turning one into text is a paid vision call per file) |
| Limits | 25 MB per file, 200 documents per platform |
| Storage | platform_documents + platform_chunks (~1,200-char overlapping passages) in the ai-service SQLite, indexed with FTS5 (Porter stemming, BM25) |
| Isolation | Every passage carries the workspace as well as the platform, and every search filters on both |
| Prompt framing | Excerpts are framed as reference material, not instructions — a customer document cannot steer Cortex |
# upload one filecurl -X POST "https://aiservice.logrite.ai/api/v1/domains/platforms/<key>/documents" \ -H "Authorization: Bearer <JWT>" \ -H "X-Filename: runbook.pdf" \ --data-binary @runbook.pdf
curl "https://aiservice.logrite.ai/api/v1/domains/platforms/<key>/documents" -H "Authorization: Bearer <JWT>"curl -X DELETE ".../platforms/<key>/documents/<docId>" -H "Authorization: Bearer <JWT>"Deleting a platform deletes its documents and passages.
Creating a Platform — three paths
Section titled “Creating a Platform — three paths”- Open
/platformsdirectly (the sidebar item is hidden for now), or Settings → Add-ons → Your platforms → Create a platform, then New Platform - Fill in the form, pick indexes, paste knowledge, save — then open it again and add Documents (drop files or choose them)
- The selector at the top-right of the Analytics layout picks it up on
the next render (Platforms.jsx now refreshes the Redux cache after
every CRUD so you don’t need to reload — see commit
7b572097)
B. REST API
Section titled “B. REST API”curl -X POST https://aiservice.logrite.ai/api/v1/domains/platforms \ -H "Authorization: Bearer <JWT>" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme Salesforce", "description": "Acme Corp Salesforce automation", "associated_indexes": ["sf_acme_*", "log-analytics-acme"], "custom_knowledge": "Acme uses Worksoft Certify against...", "suggested_prompts": ["Show failed Salesforce tests", "..."], "members": [] }'C. Promoting a built-in preset
Section titled “C. Promoting a built-in preset”The shipped Worksoft CTM preset is hardcoded in
logrite-ai-service/src/config/domainPresets.ts with prioritizedIndexes
of ctm* and continuoustestingmanager*. It carries terminology,
field guides, and tool guidance — but on a cluster without ctm*
indexes, picking it produces zero results.
To make it useful you can promote it to a real platform with indexed data. See Worksoft CTM — turning the preset into a platform below.
Active Platform — what changes per surface
Section titled “Active Platform — what changes per surface”| Surface | Behaviour when a Platform is active |
|---|---|
| Analytics header banner | Slim blue strip: “Scoped to {name} — indexes, dashboards, monitors and Cortex AI are narrowed to this platform” with a Clear-scope button |
| Discover / Visualize / Index Patterns | Index dropdown shows only associated_indexes |
| Alerting (Monitors + Alerts) | Lists filter to monitors whose inputs[].search.indices overlap the allow-list (glob-aware) |
| Anomaly Detection | Index picker narrowed |
OSD Dashboards list (/analytics/dashboards) | Walks dashboard → visualization → index-pattern refs; hides dashboards whose chain doesn’t intersect the allow-list. Scope banner shows “N of M dashboards” |
| Semantic Search | Fan-out limited to allow-list |
| Cortex AI | Index dropdown narrowed; if you also pick the same key in the chat’s Domain selector, custom_knowledge is injected into the system prompt and suggested_prompts populate the empty state |
| Notifications → Channels | Rows filtered to channels mapped to the active Platform (or marked Global). Each row carries a Manage Platforms action (FiLayers icon) that opens the per-channel mapping editor |
Per-platform Notification mappings
Section titled “Per-platform Notification mappings”Channels / email senders / recipient groups live in the OS Notifications
plugin which has no extension point for tenant tagging. The mapping is
kept in logrite-ai-service SQLite via a single junction table
platform_entity_map(platform_key, entity_type, entity_id, …) and the
endpoints under /api/v1/domains/platforms/:key/entities/:type.
Empty mapping = global (back-compat default — visible to every platform). Add a mapping → channel becomes restricted to the listed platforms only.
See the design doc for the full schema + route surface (Option B).
Worksoft CTM — turning the preset into a platform
Section titled “Worksoft CTM — turning the preset into a platform”The repository ships scripts to make the built-in Worksoft preset operational on a fresh cluster.
1. Generate synthetic CTM data
Section titled “1. Generate synthetic CTM data”# Direct OS admin path (needed because logrite_app_role is read-only)OS_ADMIN_URL=http://localhost:9200 \OS_ADMIN_USER=admin \OS_ADMIN_PASS="$(docker inspect <os-container> --format '{{range .Config.Env}}{{println .}}{{end}}' | grep OPENSEARCH_INITIAL_ADMIN_PASSWORD | sed 's/.*=//')" \node opensearch/scripts/generate-ctm-logs.js --count=200This pre-creates ctm_test_results and ctm_events (200 executions,
~3.5k events) populated with the Meridian Consulting Group Salesforce
template — 8 suites × 2–4 processes, three runner machines, change-impact
triggers from Deployd Radar.
2. Create the dashboards
Section titled “2. Create the dashboards”node opensearch/scripts/create-ctm-dashboards.jsWires two dashboards to the seeded indexes:
- CTM Test Results Overview — pass/fail, execution times, per-process breakdown
- CTM Error & Event Monitoring — error categories, exception types, event timeline
3. Create the platform
Section titled “3. Create the platform”curl -X POST https://aiservice.logrite.ai/api/v1/domains/platforms \ -H "Authorization: Bearer <JWT>" \ -H "Content-Type: application/json" \ -d '{ "name": "Worksoft CTM", "description": "Worksoft Certify + CTM automation on Meridian Salesforce", "icon": "layers", "associated_indexes": ["ctm_test_results", "ctm_events"], "custom_knowledge": "...see preset for the full Markdown body...", "suggested_prompts": [ "Show failed test executions in the last 24h", "Which processes have the most step failures?", "Aggregate executions by MachineName and surface the worst-performing agent" ], "members": [] }'4. Verify
Section titled “4. Verify”- Open
/platforms— the new platform shows alongside the built-in preset chip - Open any
/analytics/*page — the top-right Platform selector listsWorksoft CTM - Pick it → blue scope banner appears + Discover dropdown narrows to the two CTM indexes
- Open Cortex AI → pick
Worksoft CTMin the Domain selector → ask one of the suggested prompts → it queries the seeded data with the platform’s terminology in context