PT EN
Back to site

Workspaces: DATTABI dashboards and context filtering

Overview

Each DATTA workspace groups a set of enabled features, a list of linked panels and a list of contexts (domains/databases). This delivery adds two capabilities to the workspace:

  1. DATTABI dashboards in the manager and in the menu — the BI dashboards created in DATTABI now appear in the panel catalog, can be linked to a workspace through the manager and become buttons in the workspace's group in the side menu.
  2. Contexts filtering the features' data — when opening a context-aware feature from a workspace's group, the shell propagates the workspace's contexts to the feature, which starts filtering its data by those contexts.

Problem

  • DATTABI dashboards lived isolated in the the DATTABI screen page; there was no way to expose them as a shortcut inside a workspace's menu or to reuse them alongside the other features (chat, panel, investigation, screening).
  • A workspace can have several contexts, but the features opened from it showed all data from all contexts. The user had to filter the domain manually on each screen, gaining nothing from the workspace grouping.

Solution

  • The panel catalog (GET /api/config/panels) now includes, besides the native and canvas panels, each workspace's DATTABI dashboards, obtained via a service-to-service (S2S) call to the dattabi-service.
  • The workspace manager (/configurar/workspaces) shows those dashboards in the Link existing action, and the side menu renders as buttons the dashboards whose panelRef is persisted (opening the DATTABI screen). The persistence of the dashboard link via panelRef has a known backend limitation — see Known limitations.
  • The shell propagates the workspace's contexts via the ?domain=ctx1,ctx2 querystring when opening a context-aware feature, and each feature reads that parameter to filter/pre-select its data.

How it works (architecture + data flow)

Item 2 — DATTABI dashboards in the catalog, in the manager and in the menu

Backend (panel catalog). The config-service's panel catalog API serves GET /api/config/panels — a flattened catalog of the platform panels visible to the user (see Visibility by members). Besides the native (native-view) and canvas panels of each workspace, it now aggregates the DATTABI dashboards:

  • For each workspace, it makes an S2S call to the dattabi-service at GET /api/dattabi/dashboards?workspaceId=<id> using WebClient.
  • The per-workspace calls run in parallel, with concurrency 6 (Flux.fromIterable(workspaces).flatMap(this::dattabiDashboards, 6), following the Project Guidelines §19.
  • Each call is best-effort: a 6s timeout and an onErrorResume that returns an empty list, so that the unavailability of one workspace's dashboards does not bring down the whole catalog.
  • Each non-archived dashboard becomes a catalog entry in the format:
json
  {
    "workspaceId": "<id-do-workspace>",
    "workspaceName": "<nome>",
    "panelId": "<dashboardId>",
    "title": "<titulo>",
    "description": "<opcional>",
    "kind": "dattabi-dashboard",
    "dashboardId": "<dashboardId>",
    "url": "/dattabi.html?dashId=<dashboardId>",
    "native": false
  }

.

Backend (source of the dashboards). The dattabi-service exposes GET /api/dattabi/dashboards?workspaceId=<id>. The endpoint requires DATTABI_VIEW, lists the workspace's dashboards (parameter includeArchived=false by default) and, defensively, returns an empty list when workspaceId is missing/blank.

Frontend (manager). In the workspace manager (screens/settings-workspaces.html, Panels tab → Link existing), the catalog is loaded and filtered into the list of linkable options:

js
// screens/settings-workspaces.html
const options = catalog.filter(
  c => c.workspaceId !== selected.id || c.kind === 'dattabi-dashboard'
);

That is: canvas panels remain linkable only from other workspaces (the workspace's own already appear), but DATTABI dashboards (kind === 'dattabi-dashboard') are linkable from any workspace, including its own. The selection is saved as panelRef via PUT /api/config/workspaces/{id}/panel-refs (screens/settings-workspaces.html).

Since those links are references (panelRef), they appear in the list's Linked panels section, with the generic Linked badge and the Open button (which calls openRef → opens /dattabi.html?dashId=<id> in a new tab) (screens/settings-workspaces.html). The BI Dashboard badge and the Open dashboard button (screens/settings-workspaces.html) are used only for panels owned by the workspace whose config.kind is already dattabi-dashboard — a path distinct from the panelRef link.

Frontend (side menu). The shell (compiled/index.js) loads /api/config/workspaces and /api/config/panels in parallel with Promise.all (index.js:746-756) and indexes the catalog by the workspaceId::panelId key. When building each workspace's group, it resolves the panelRefs in the catalog and renders those of type dattabi-dashboard as buttons:

js
// index.js:2105-2107
const dashRefs = (ws.panelRefs || [])
  .map(r => panelCatalog[r.workspaceId + '::' + r.panelId])
  .filter(p => p && p.kind === 'dattabi-dashboard');

Clicking the button opens /dattabi.html?dashId=<dashboardId> in a new tab (index.js:2117-2126).

Item 9 — The workspace's contexts filter the features

Propagation in the shell. The shell keeps a panelDomain state (index.js:705). When clicking a feature inside a workspace's group, it sets panelDomain to the workspace's contexts joined by comma and navigates to the feature:

js
// index.js:2115
onClick: () => { setPanelDomain((ws.contexts || []).join(',')); navigateTo(fk); setSidebarOpen(false); }

When the feature is rendered as an iframe, the shell adds the domain parameter to the src only if the feature is context-aware and there is a panelDomain:

js
// index.js:2602
src: WS_CONTEXT_AWARE.has(key) && panelDomain
  ? src + (src.includes('?') ? '&' : '?') + 'domain=' + encodeURIComponent(panelDomain)
  : src,

The set of context-aware features is fixed (index.js:639-642):

js
var WS_CONTEXT_AWARE = new Set([
  'dashboard', 'chat', 'investigate', 'upload', 'analytics',
  'triagem-lote', 'regras-triagem'
]);

Consumption in the features. Each feature reads ?domain from the URL and uses the contexts to filter its data:

  • Panel/Processes (dashboard), Chat (chat), Investigation (investigate), Upload (upload) and Cases (analytics) already read ?domain and now filter/use the workspace's contexts. Since 2026-09-28 Investigation is DATTA Investigation, the Chat in deep-research mode: the scope comes from the workspace selector on its own bar, as in the Chat.
  • Rules (regras-triagem): filters the rules by the workspace's first context; without ?domain it shows Todos (compiled/regras_triagem.js:788-791):
js
  const wsCtx = (() => { try {
    return (new URLSearchParams(window.location.search).get('domain') || '').split(',')[0].trim();
  } catch (e) { return ''; } })();
  const [contexto, setContexto] = useState(wsCtx || 'Todos');
  • Batch Screening (triagem-lote): pre-selects only the workspace's contexts (the intersection with the available contexts); without ?domain it selects all, keeping the default behavior (compiled/triagem_lote.js:132-137):
js
  const ws = (new URLSearchParams(window.location.search).get('domain') || '')
    .split(',').map(s => s.trim()).filter(Boolean);
  const wsValid = ws.filter(c => ctxs.includes(c));
  setSelectedContexts(wsValid.length ? wsValid : ctxs);

APIs / contracts

GET /api/config/panels (config-service)

A flattened catalog of the platform panels visible to the user (public workspaces + the ones they are a member of; an admin sees all — see Visibility by members). Response: an array of objects. DATTABI dashboard entries have kind: "dattabi-dashboard" with dashboardId and url (see the format above). Permission: PANEL_VIEW or CONFIG_VIEW (any-of).

GET /api/dattabi/dashboards?workspaceId=<id> (dattabi-service)

Lists a workspace's dashboards. Parameters:

ParameterTypeDefaultDescription
workspaceIdstring—Required (semantically); empty → []
includeArchivedbooleanfalseIncludes archived dashboards

Permission: DATTABI_VIEW. Called S2S by the config-service.

PUT /api/config/workspaces/{id}/panel-refs (config-service)

Sets the list of existing panels linked to the workspace. Body:

json
{ "panelRefs": [ { "workspaceId": "<id>", "panelId": "<id>" } ] }

Permission: CONFIG_EDIT. The service validates each reference: it accepts only a native panel (panel catalog API) or an existing canvas panel in another workspace (store.find(workspaceId).panels()); any other reference returns 400 Bad Request with {"error":"Painel referenciado não existe: ..."}. In addition, it silently discards references whose workspaceId is that of the workspace itself.

Attention (current gap): DATTABI dashboards come from the catalog via S2S and are not persisted Workspace.Panel — so the current setPanelRefs does not recognize them as a valid reference (it rejects those from another workspace with 400 and discards the workspace's own). See Known limitations.


RBAC / permissions

ActionRequired permissionWhere it is checked
Read the panel catalogPANEL_VIEW or CONFIG_VIEWpanel catalog API — @RequirePermission via declared-permission check (Mono return, reactive branch). The SecurityWebFilterChain only requires .authenticated() for this GET.
List a workspace's dashboardsDATTABI_VIEWdashboards API — @RequirePermission via declared-permission check (Mono return). The dattabi-service filter only requires .authenticated() on /api/dattabi/**.
Link panels/dashboards to the workspaceCONFIG_EDITDouble layer: the security filter requires CONFIG_EDIT or ROLE_ADMIN on every PUT /api/config/**, and the declared CONFIG_EDIT permission is checked again when linking panels.
Change a workspace (name, features, contexts, panels, links)CONFIG_EDIT and level Pode editar or higher in the workspaceCONFIG_EDIT through the declared permission; the member's level by the configuration service, on every route (see Member permission levels).
Manage members and delete the workspaceCONFIG_EDIT and level Pode gerenciar membros in the workspaceSame.
List registered users (picking the member)CONFIG_EDITGET /api/config/workspaces/usuarios-cadastrados — declared permission (Mono return).

Note on the enforcement point. On these three endpoints the granular permission check runs in the declared-permission check (datta-common), which only enforces when the method returns Mono/Flux (the reactive branch, via ReactiveSecurityContextHolder). The three methods return Mono, so the annotation applies. For blocking-return methods in WebFlux the aspect does not block (empty thread-local) and authorization falls back to the SecurityWebFilterChain — which is why the config mutations also have the per-permission path-matcher in the SecurityConfig.

The config-service's S2S call to the dattabi-service uses an internal JWT (InternalJwtProvider) issued with the DATTABI_VIEW and ADMIN authorities, satisfying both the dattabi-service filter's .authenticated() and the @RequirePermission("DATTABI_VIEW") checked by the aspect. The frontend is just a visual hint; the security barrier remains in the backend (Project Guidelines §13).

Visibility by members (scope, Project Guidelines §13)

Holding CONFIG_VIEW or PANEL_VIEW authorizes reading workspaces, not reading every workspace. On top of the permission, every access goes through the membership scope (WorkspaceAccess, config-service):

WhoWhat they see
Administrator (ADMIN/SYSTEM_ADMIN) and internal services (S2S)Every workspace
Any authenticated user with a read permissionPublic workspaces: those with no members (the case of the Processos and Assistência Social seeds) and those whose members are all platform administrators
A user listed in the Members tab, and the workspace ownerThe restricted workspaces they belong to, plus the public ones

An administrator on the list does not restrict (decision of 2026-09-27). The platform administrator already sees every workspace; listing them as a member gives nobody access, and before this it only closed the workspace to the rest of the platform — which is what happened to "Processo Trabalhista" and "Contratos", whose only member was the admin user. A workspace becomes restricted when it has at least one member who is not an administrator.

The config-service is the one that knows whether a member is an administrator: when the member is added, it looks the user up in the user registry (the same user graph the token comes from) and stores the adminPlataforma flag in the member record itself. The flag is reconciled when the service starts and every minute, which is how data already stored — like the two workspaces above — and role promotions and demotions reach the rule without anyone editing the workspace. A demotion takes up to that interval (plus the bpmn-service's 60 s cache) to restrict again. With the user registry unavailable, no flag changes.

The SAME decision applies everywhere that filters by workspace: the config-service applies it to the workspace list and to the panel catalog; the bpmn-service reads the same JSON, with the same flag, and applies the same rule (VisibilidadeWorkspace, in datta-common); the graph-data-service and the chat-service ask for the workspace (or the list) with the user's token and receive the decision already made.

A member is stored by the registered user's e-mail: the API rejects (400) an identifier that matches no user — before, any text was stored and closed the workspace without giving access to anyone — and also one that matches more than one user (one user's e-mail and another's login): there is no silent choice. When comparing with the token, the backend accepts the user's e-mail and id (older records may carry the id), case-insensitively — never the login, which the token does not carry.

The administrator flag follows the same rule: a member counts as an administrator only when all users it gives access to — by id or by e-mail — are administrators. A member stored by someone's login gives access to no one and counts as regular, instead of inheriting the role of the login's owner.

A restricted workspace the user does not belong to returns 404, not 403: confirming that the resource exists would already be a leak (the user would learn the names/ids of other teams' confidential workspaces). That is why the message in the interface is deliberately ambiguous — "Workspace not found or no access". The denial is recorded in the audit trail as AUTHZ.PERMISSION_DENIED with permission=WORKSPACE_MEMBERSHIP.

The scope applies to all workspace routes, not just reads: updating, deleting, or touching the panels, contexts and members of an invisible workspace also returns 404, even with CONFIG_EDIT. The validation behind the Link existing action (PUT .../panel-refs) is scoped as well: a panel from an invisible workspace is rejected exactly like a non-existent id, with the same message — otherwise the difference between the two responses would reveal, by trial and error, which restricted workspaces exist. And the panel catalog (GET /api/config/panels) flattens only the visible workspaces — without that, the titles of a restricted workspace's panels and dashboards would leak through the gallery and the home popover. The platform's native panels are offered to everyone in the full catalog, but the gallery and the home popover only show a native panel linked to a workspace the user can see — and the catalog lists, in contextosDeOrigem, only the contexts of the workspaces the user can see (whoever edits the configuration sees all of them).

Practical consequence. As long as a workspace's Members tab is empty — or holds only platform administrators — it stays visible to the whole platform. To restrict a workspace, just add the first member who is not an administrator: from then on it disappears for anyone not on the list (the owner and administrators excepted). Removing the last such member makes it public again — the screen warns beforehand, both ways.

Member permission levels

Seeing the workspace is decided by the visibility above; changing it is decided by each member's level, enforced by the configuration service on every change route (since 2026-09-29 — before, the level was stored and never checked):

WhoWhat they can change
Member Pode visualizar (viewer)Nothing: sees the workspace, its panels, contexts and members
Member Pode editar (editor)Name, description, features, contexts, panels and links
Member Pode gerenciar membros (owner)Everything the editor changes, plus adding, changing the level of and removing members, and deleting the workspace
The workspace owner (its creator) and a platform administratorEverything, whether or not they are on the member list
Someone who is not a member, in a public workspaceThe same as before: CONFIG_EDIT is enough (a public workspace has no manager)
  • The level never changes who sees the workspace. A member's level never takes visibility away from another member: every member sees the workspace. The owner and a platform administrator always see it. Only someone who manages members can take a person off the list, and that person stops seeing the workspace if it is still restricted. Removing the last non-administrator member makes it public again. Someone who manages members can also delete the workspace, and the deletion is permanent: no one sees it anymore, not even an administrator.
  • An insufficient level answers 403 with a sentence saying what is missing (the workspace is already visible to the caller, so there is nothing to hide) and records the denial in the audit trail (AUTHZ.PERMISSION_DENIED, permission=WORKSPACE_EDIT or WORKSPACE_MANAGE_MEMBERS).
  • The platform permission still applies on top: without CONFIG_EDIT, no level changes anything.
  • The level is checked again at write time, against the workspace as it stands: someone demoted (or removed) while their own change was on its way gets 403 (or 404, if they no longer see the workspace) and nothing is stored.
  • The same user in more than one entry gets the highest level. The stored level wins even when the permissions stored on the member say more; only an old record without a level is read from the permissions. An unknown level counts as Pode visualizar, and the API rejects (400) storing a level other than viewer, editor or owner. The permissions stored on the member always come from the level.
  • Members stored before 2026-09-29. The add-member dialog opened with Pode visualizar already chosen, and the level counted for nothing: the member edited with CONFIG_EDIT. By the user's decision (2026-09-29), every member stored as "Pode visualizar" when this version first starts is promoted ONCE to "Pode editar" — including those added through the API without the role field, which the old server stored as viewer. The promotion runs a single time at config-service start-up, logs how many members were promoted in each workspace and writes the marker promocao-viewer-editor.json next to workspaces.json (it survives restarts and rollbacks); it does not touch the owner, "Pode editar", "Pode gerenciar membros" or platform administrators, and does not change who sees the workspace. Whoever is added as "Pode visualizar" after it stays read-only. Unreadable marker: the promotion does not run and logs a warning. At service start-up, a migration aligns the stored permissions with the level and logs (workspace.member.reconciliado) every member whose permissions said more than the level — that is the list to reclassify. To give editing back, the owner, someone who manages members or a platform administrator changes the level in the Membros tab (or PUT /api/config/workspaces/{id}/members/{userId} with role). In a workspace with no active owner — the ones created by the installation have the owner Sistema — only a platform administrator can do it.
  • The screen hides what your level does not allow — no Editar and Excluir, no saving, no creating or removing panels, no Adicionar membro — and says, at the top of the workspace, what your level is.

Auditing

  • Panel linking uses the existing workspace mutation flow (PUT .../panel-refs), covered by the config-service's configuration mutation auditing.
  • Creating/changing/archiving dashboards in DATTABI follows the dattabi-service's own auditing (versioning via dashboards versions service and copilot cache invalidation on save/archive/delete). The read (GET /api/dattabi/dashboards) does not generate a mutation event.

Cache

  • The per-workspace dashboard listing is queried on every assembly of the panel catalog. The GET /api/dattabi/dashboards read path relies on the DATTABI repository; the catalog itself does not add its own Valkey layer — the S2S call is parallelized and protected by timeout/best-effort.
  • DATTABI keeps its own per-dashboard narrative and suggestion caches, invalidated on save/archive/delete (dashboards API).

Observability (OTel)

Backend and frontend are already instrumented by the platform standard (Project Guidelines §11):

  • The HTTP calls of GET /api/config/panels, GET /api/dattabi/dashboards and PUT .../panel-refs generate inbound spans (controllers) and the config-service's S2S call to the dattabi-service generates an HTTP client span, all exported to the otel-v1-apm-span-* indices.
  • The shell (the index.html page) loads the OTel browser SDK and propagates traceparent on the fetch() calls to /api/config/workspaces and /api/config/panels.

How to use (user step by step)

The side menu shows the active workspace

With a workspace active (chosen on the card at the top of the menu), the side menu shows only the work features checked in it — Rules, Batch Triage, Upload, Explore Data, DATTA Extract, DATTA BPM, DATTA BI and the other features in the Features tab catalog. Switching workspace switches the list.

The same filter applies to the cards of the Features screen. Of the 25 catalog features, 14 have no menu item of their own — Knowledge Catalog, Lineage, Cases, Alerts, Notebook, Agents, Governance and others — and are only reachable through Features. DATTA Investigation got its own item, right below Chat, on 2026-09-28. With the workspace active, Features shows only the checked ones (and says which workspace the filter comes from, with the Gerenciar workspaces shortcut); unchecked ones disappear from the menu and from Features. Process Panel and PJ Onboarding are panels: they show in the Panels gallery when linked to the workspace in the manager's Painéis tab, not in the menu nor in Features.

The safeguards, all in force at once:

  • The platform always shows: Chat, System, DATTA Captain, Documentation, the profile, Panels, Features and the workspace switcher (the card at the top) do not depend on the workspace. They are platform, not team work — and filtering System could lock the administrator out of their own configuration.
  • Chat is always visible (decision of 2026-09-29): it is the door to the DATTA Captain and the assistant, and a workspace that unchecked it removed from the menu the entry through which anything is asked of the platform. So it left the Funcionalidades tab. The chat key stored in older workspaces is dropped from the list when the configuration service starts (and the API accepts and discards it, with no 400); a workspace whose only checked feature was Chat ends up with none checked — and shows the whole menu, by the rule below. Chat's scoping by the active workspace (the workspace's contexts) stays the same.
  • "All workspaces" shows everything: with no active workspace, nothing is filtered.
  • A workspace with no feature checked shows everything: "nothing checked" means "not configured", not "hide everything". The same holds while the workspace list has not arrived yet (or the call failed).
  • A feature the catalog does not know always shows: a new screen never disappears from the menu for lack of registration.
  • Permissions still apply on top: the workspace filter only hides, it never grants. The menu does not hide items by the person's role: an item checked in the workspace shows for every member, and whoever lacks the permission is stopped by the backend when opening the screen. Likewise, hiding an item from the menu does not block access through a link. Access is always decided by the backend, by permission.

A group (DATTA Extract, DATTA BPM, DATTA BI) shows when at least one of its features is checked, and shows only the checked ones. In the worst case — a workspace with a single feature that has no menu item, such as the Knowledge Catalog — the menu keeps Panels, Features, Documentation, System and the workspace switcher card, and the checked feature is in Features; never a dead end.

History. The menu was filtered like this on 2026-08-23 and was reverted the same day: without safeguards, a workspace with few features left the menu with two items, without System and without a way to switch workspaces. The filter came back on 2026-09-27 with the safeguards above, and a test that renders the menu for every possible workspace keeps that case from returning — and requires every checked feature to show in the menu or in Features.

To choose what each workspace shows, use the Features tab of the management screen.

Members and visibility

The Members tab shows, before the list:

  • the workspace's visibility — Public (every user with read access sees it) or Restricted (only the owner, the members and the platform administrators);
  • the owner, who always sees the workspace, even when not on the list. A workspace created by the installation shows the owner System.

Each member shows the name and e-mail from the user registry; a platform administrator is identified as such ("does not restrict the workspace").

To add one:

  1. Click Adicionar membro.
  2. Pick the user from the list — it starts on Selecione um usuário…, shows each person's name, login and e-mail (and flags platform administrators), and leaves out whoever is already a member. The list is the platform's registered users and comes to whoever has CONFIG_EDIT, without requiring the user-management permission. In an installation with more than 2000 users, the dialog shows a Buscar por nome, login ou e-mail field: the list brings only the first ones in alphabetical order, and the search reaches the others.
  3. Pick the permission level (see Member permission levels) and confirm.

Only someone already registered on the platform can become a member: adding looks the user up in the registry and rejects (400) what it does not find, saying that the person is not a registered user and that only registered users can be workspace members. With the user registry down, adding answers (503) that it could not be checked, that the member was not added, and that it is worth trying again shortly; if the user list does not load, the screen says why and offers Tentar novamente instead of a text field the server would reject. So a collaborator who will sign in through Microsoft or Google can only be added after their first login — that login is what creates the registration. Creating a local user with the same e-mail beforehand is not a shortcut: the platform then rejects the Microsoft/Google login into an account created by another sign-in method.

An identifier that matches more than one user is rejected too — in the real registry, admin is one user's e-mail and another user's login. The screen's list sends each person's unique identifier, so picking from the list avoids this; it is the case of whoever calls the API directly.

With the workspace public, the screen warns beforehand that the first member who is not an administrator makes it restricted — the button becomes Adicionar e restringir. Adding an administrator does not change the visibility, and the screen says so. When removing the last member who restricts it, the screen warns that the workspace becomes visible to everyone again, and the button becomes Remover e tornar público.

The workspace name accepts up to 120 characters and the description up to 500 — the screen limits the fields and the API rejects (400) anything longer.

Every save on the screen — features, contexts, panels, links and members — updates the side menu and the active workspace's scope right away, without reloading the page. Switching tab or workspace with unsaved changes in Features or in Data Contexts asks first what to do (keep editing, discard or save now).

  1. Go to Configure → Workspaces (/configurar/workspaces).
  2. Select the desired workspace and open the Panels tab.
  3. Click Link existing.
  4. In the list, check the DATTABI dashboards (and/or the panels from other workspaces) you want to display and confirm. The dashboards appear with their origin indication; those of the workspace itself can also be selected in the UI.
  5. The persisted links appear in the Linked panels section with the Linked badge and the Open button.

Current limitation: the setPanelRefs backend does not yet recognize DATTABI dashboards as a valid reference (it rejects those from another workspace with 400 and discards the workspace's own). Until the backend accepts kind == 'dattabi-dashboard', this link may not persist and the menu shortcut does not materialize. See Known limitations.

Open a dashboard from the menu

  1. In the side menu, expand the workspace's group.
  2. The dashboards whose panelRef is effectively persisted appear as buttons (with the dashboard's title) — see the limitation above.
  3. Click to open the dashboard (/dattabi.html?dashId=<id>) in a new tab.

Use the workspace's contexts to filter data

  1. Set the workspace's contexts in the manager's contexts tab. A context deleted in SistemaContextos leaves every workspace that listed it on its own; if an old name is still stored, the screen drops it on save and says how many it dropped.
  2. In the side menu, expand the workspace's group and click a feature.
  3. The applied scope depends on the feature:
    • Chat takes you to a dedicated screen scoped to the workspace: search (Pesquisa and Investigação) considers only the workspace's contexts, resolved server-side from the workspace id with the user's identity, and the context names appear dimmed next to the mode selector. The reach includes the rule contexts linked to the workspace's ones (the "Conectado a" of the contexts tab — the CLT of a labour context): a question about the domain's law finds the law. And the workspace bounds the question: when the classifier only sees contexts outside it, the answer comes from the workspace's contexts, without sending the user to another context.
    • Panel (dashboard), Upload and Batch Screening receive the workspace's contexts via ?domain= and open already filtered (Batch Screening comes with the contexts pre-selected).

How to operate (admin)

  • Dashboard discovery depends on the dattabi-service being reachable by the config-service at the URL configured in datta.dattabi-service.url (default http://dattabi-service:8210). If unavailable, the panel catalog keeps responding, just without the dashboard entries (graceful degradation, logged at the debug level).
  • The internal JWT used in the S2S call requires datta.jwt.secret/JWT_SECRET populated in the config-service; without a valid secret, the Authorization header is not sent and the dattabi-service may refuse the read.
  • The DATTABI_VIEW permission must be mapped to the roles that need to see the dashboards, and CONFIG_EDIT to the roles that administer the workspace's links.

Known limitations

  • Partial context coverage: only the features in WS_CONTEXT_AWARE (dashboard, upload, triagem-lote) consume ?domain. Chat has its own scope (dedicated chat-ws view, resolved server-side from the workspace id). DATTA Investigation uses the same workspace selector as the Chat, on its own bar. Rules, Lineage, Notebook, Explore Data and Catalog do not yet filter by the workspace's context — an extension planned for the future (Rules is keyed by legal context — CPC/CDC/CPP — and opens on "Todos", not on the workspace's data contexts).
  • Linking a DATTABI dashboard via panelRef does not persist today: the manager's UI allows checking DATTABI dashboards (including the workspace's own), but the current setPanelRefs only accepts references to native panels or to existing canvas panels in another workspace. DATTABI dashboards come from the catalog via S2S and are not persisted Workspace.Panel, so:
    • a reference to another workspace's dashboard is rejected with 400 ("Painel referenciado não existe");
    • a reference to the workspace's own dashboard is silently discarded.

The side menu (index.js:2105-2107) only renders a dashboard when the corresponding panelRef has effectively been persisted and resolves in the catalog by the workspaceId::panelId key. Until the backend recognizes DATTABI dashboards as a valid reference (e.g.: accepting kind == 'dattabi-dashboard' in the validation), the menu shortcut via panelRefs does not materialize in a stable way — a pending extension.

  • The ?domain propagation happens when navigating from the workspace's group; when accessing the feature by another path (without a workspace), the context filter is not applied automatically.
  • The menu filter is a hint, not a barrier: hiding a feature from the menu and from the Features screen does not prevent opening it through a link — what blocks it is the permission, in the backend.
  • A member must be registered first. Adding a member requires a user that already exists in the registry (and answers 503, saying nothing was stored, with the registry down). Whoever signs in through Microsoft or Google can only be added after the first login; pre-registering a local user with the same e-mail does not help, because the external provider's login is rejected into an account created by another method. Accepting the e-mail of someone who has not signed in yet was weighed and dropped on 2026-09-29: the "member = registered user" rule stays.
  • User list with a cap. The picking list brings up to 2000 users, sorted by name; in a larger installation, the dialog offers a server-side search by name, login or e-mail that reaches whoever was left out of the list.
  • Who sees the users' e-mails. The picking list (name, login, e-mail and the administrator flag) comes to anyone with CONFIG_EDIT, even without managing members of any workspace (decision of 2026-09-29): whoever has CONFIG_EDIT can create a workspace and be its owner, and a public workspace has no manager, so requiring "manages some workspace" would restrict no one in practice. Someone with only CONFIG_VIEW does not get the list, and the screen does not ask for it.

Each workspace group in the side menu has a "Panels" item that opens the panel gallery scoped to that workspace (?workspaceId=<id>). The gallery replaces the old listing of individual dashboards with a grid of ~3.5-inch cards (336px @96dpi), each with a "screenshot" of the panel:

The gallery shows only published panels: DATTA BI dashboards (kind == 'dattabi-dashboard'), the native panels linked to the workspace through the manager (see below) and linked panels (panelRefs). Canvas (declarative) panels come in once they are published — only published sets them apart, as with any other type. (They used to be filtered out by kind !== 'canvas', back when there was no canvas publish step; there is one now, and the filter is gone.)

Native panel: linked through the workspace manager

A native panel is not added to a workspace on its own. Since 2026-09-27 (product owner decision: "the process panel must not be linked on its own, it must be linked through the workspace manager") whoever links a native panel to a workspace is the manager, in the Painéis tab → Vincular existentes (Nativo group). The data context type (tipoContexto) only says which context each panel reads:

Context type the panel readsNative cardScreen opened
processo_judicialPainel de Processostriage panel (view dashboard), anchored on :Processo/processoNumero
custom with an anchor (identificadorLabel + identificadorProperty in the registration)Painel de \<type value\> — e.g. Painel de Contratos (painel-contrato)the same triage panel (view dashboard), reading the context anchor (:Contrato/contratoId)
dossie_cadastralPainel de Onboarding PJ and Pendências de Compliancelist of PJ dossiers by CNPJ (view kyb-onboarding) and certificate pending items (view compliance-pendencias)
other types (and custom without an anchor)none—
  • The catalog offers, the manager links. The panel catalog offers every native panel of the installation — the fixed ones and the anchor ones of each anchored custom context — and each native entry says which workspaces linked it (workspaceIds, which comes only from the links stored in panelRefs with workspaceId == "native") and which registered contexts it reads (contextosDeOrigem; for whoever does not edit the configuration, only those of the workspaces they can see). The workspace gallery and the home panels popover show only the linked ones — the gallery route does not even return a native panel that no visible workspace linked.
  • Saving the contexts does not link a panel. After saving contexts that offer a native panel the workspace does not link yet, the Contextos de Dados tab suggests: "Para ver o Painel de Processos neste workspace, ligue-o na aba Painéis" ("To see the Painel de Processos in this workspace, link it in the Painéis tab") — with a button that goes to the tab.
  • Linking to a workspace without the context the panel reads is allowed. When the panel is ticked, the manager warns under the checkbox what it will show in that workspace — by the same rule as the screen the panel opens — and saving goes on as usual:
    • Triage panel (the Painel de Processos and the anchor panels): it is one screen, which reads any anchored context of the workspace. With no anchored context the warning is "Este workspace não tem contexto do tipo Processo Judicial; o painel abrirá sem registros" ("This workspace has no context of type Processo Judicial; the panel will open with no records"; an anchor panel names the context it reads). With an anchored context of another type the panel opens with that context's records, and the warning says so: "…; o painel mostrará os registros de Contratos, com o título "Painel de Contratos"" ("the panel will show the records of Contratos, titled Painel de Contratos"). A workspace whose contexts declare no type (older installation) gets no warning: without a type there is no way to state what the panel will show. Ticking the Painel de Processos and an anchor panel together raises the warning that they are the same screen — two cards with the same content.
    • Dossier panels (Onboarding PJ and Pendências de Compliance): they are not filtered by the workspace. They open on the workspace's dossier when it is the workspace's only context; otherwise, on the first dossier registered in the installation — and the warning names it: "…este painel não é filtrado pelo workspace: ele abrirá com os dossiês de FEBRABAN" ("this panel is not filtered by the workspace: it will open with FEBRABAN's dossiers"). "No records" only when the installation has no dossier context.
  • No platform startup links or swaps a native link, and none deletes what the manager linked. Until 2026-09-27 the link was decided by the context type: added or swapped when the workspace's contexts were saved and reconciled at every startup, and a new installation's seed already stored it. None of that exists anymore.
  • Removal of the links the manager did not make. The manager records every native panel it links in the file paineis-nativos-manuais.json, next to workspaces.json (the manuais list: workspace, panel and when), before storing the link — if the record cannot be written, neither is the link, and the screen shows the error. At every startup the configuration service removes from the workspaces the native links that are not in that list: on the first startup with the change, all of them (Painel de Processos, Onboarding PJ, Pendências de Compliance and anchor panels); afterwards, only what an earlier version of the platform linked again by type (a rollback, or a release built from a branch without the change). What was removed stays in removidos (workspace, name, panels and when) — the data to link them again through the Painéis tab.
    • If the removal fails, the log warns, the record lists in naoRemovidos what stayed, and the next startup tries again.
    • Unreadable record: no startup removes anything, and the log warns with the file path. Deleting the file restarts the policy — the next startup removes every native link, including the ones linked through the manager.
    • Limit: a link made in the manager while an earlier version is running does not enter the record and is removed on the next startup of this version (the log says which). And a recorded link that an earlier version deleted is not linked again on its own — the log warns to link it again through the Painéis tab.
  • Dossier features: once per workspace. A workspace that groups a registration dossier context receives the vertical's features once (kyb-onboarding, compliance-pendencias, upload, rules and batch triage, explore, chat, catalog), added to the ones the admin enabled. If the admin removes any of them later, it does not come back on restart or release — until 2026-09-29 it came back on every startup. The record of what was already handled is the file upgrades-de-boot-aplicados.json, next to workspaces.json (the same one used for the "Painel de Processos" canvas, described in the Panels guide). On the first startup with this rule, workspaces that already group a dossier are only recorded, unchanged; a workspace associated with a dossier later receives the features on the next startup, once. Unreadable record: no startup adds anything, and the log warns. A workspace that cannot be saved (full volume, disk failure) is taken out of the record and tried again on the next startup, without blocking the others; if even the record cannot be corrected, the log names the workspace left without the features. A rollback to a previous version adds them again on every startup.
  • The card's title and description come from the catalog, not from the page: the dossier card no longer inherits the text "Triagem e auditoria de processos judiciais".
  • The registration dossier card requires the KYB_VIEW permission — the same one that hides the "Onboarding PJ" side-menu entry. The catalog does not return the entry to whoever lacks it, so the card disappears from every surface at once instead of opening with a 403.

custom context with an anchor: the same triage panel, with the context's data

The triage panel (view dashboard) is not the ":Processo panel": it reads the context anchor — the label and identifying property the registration declares (identificadorLabel/identificadorProperty, exposed by GET /api/config/domain/list). In a processo_judicial context the anchor is :Processo/processoNumero; in a custom context such as Contratos it is :Contrato/contratoId. Only the data shown changes:

  • Same layout and same actions — counters, filters, server-paginated list, detail with report/rules/history, re-run triage, assign to a person (forward), assign to a BPM model, export PDF, download the PDFs as ZIP, delete with a justification and "Continue in Chat". What only exists in the judicial domain stays out elsewhere: the CNJ number-range type filter/column, the final decision / appeal admissibility blocks and the Generate appeal action.
  • Terms and title come from the anchor: "Contratos", column "Contrato", "Identificador do contrato", "Excluir contrato", breadcrumb "Painel de Contratos". The card title is Painel de <type value> (the registration's tipoContextoValor; failing that, the context name).
  • Parties and classification: outside the judicial domain a party is any :Empresa/:Pessoa linked to the anchor (the edge the context's NER emits, e.g. PARTE_CELEBRA_CONTRATO, with its papel), the name is what the NER stored (razaoSocial/nome) and the classification column shows the conventional tipo<Label> property (tipoContrato) or the titulo.
  • Backend: GET /api/processos/dashboard, DELETE /api/processos and the ZIP document listing query the anchor node (graph-data-service resolves the pair from the registration; outside the safe identifier form the judicial default applies). The response carries ancora: {label, property}.

What a context needs to offer the card is to declare the anchor in its registration (tipoContexto=custom + identificadorLabel + identificadorProperty) and to have documents whose NER emits the anchor node linked to the document; for the card to show up in a workspace, link it in the manager's Painéis tab. A custom context without an anchor offers no native card — there is nothing for the screen to query. The declarative "Contratos" panel that existed until 2026-09-16 (a property table, without triage) was removed along with the script that created it; the native card replaces it.

Each card has a "screenshot" of the panel:

  • DATTA BI dashboard: uses the thumbnail from GET /api/dattabi/dashboards/{id}/thumbnail.png, which prioritizes the real screenshot captured in the browser: when an editor opens/saves/publishes the dashboard, dattabi.js composes a faithful PNG (real pixels of the ECharts canvases + KPI/table texts) and sends it via PUT .../thumbnail; the backend persists it in Neo4j and caches it in Valkey. The synthetic server-side render remained only as a fallback for dashboards never opened. ("Live" rendering via a BI iframe was tried and reverted — loading the whole app per card was too heavy/slow for a thumbnail.)
  • Native panel ("Painel de Processos", "Painel de Onboarding PJ" or another native panel linked to the workspace): uses a "live" thumbnail — a non-interactive iframe of the real panel, loaded in the embedded shell (/index.html?view=<view>&embed=1&domain=<workspace contexts>, which hides the sidebar and the top bar), scaled (logical width 1280, transform: scale, cropped at the top), lazy (IntersectionObserver) + responsive scaling (ResizeObserver), sandbox="allow-scripts allow-same-origin", pointer-events: none. There is no server-side screenshot renderer for natives — the live thumbnail is the 100% client-side, on-prem approach. (Until the screens were migrated to fragments the target was the standalone page /dashboard.html; it no longer exists, and the shell view replaced it.)
  • Canvas panel (declarative, built in the Panel Builder): the same "live" thumbnail as the native one, pointing at /index.html?view=painel&ws=…&panel=…&mode=view&embed=1. The embed=1 hides the toolbar (pb-embed) and implies viewOnly, so what shows up in the thumbnail is the finished panel, never the builder.

A thumbnail always comes from loading the panel in the background, and every finished panel has one — whether it is a platform panel (native or declarative) or a DATTABI dashboard. What differs between the types is only where the result stops: the platform panel renders the iframe straight into the card, while DATTABI stores the PNG on the server because opening the whole BI app per card would be too heavy to repeat on every load of the gallery.

The builder shows up on no surface of the gallery — not in the thumbnail (embed=1 hides it) and not in the breadcrumb (see below). It is an internal tool; the gallery shows panels, not the tool that assembles them. The DATTABI capture is queued by datta-thumb-regen.js (one hidden iframe at a time, ?thumb=1, a cap on captures and a per-capture timeout), shared with the DATTA BI Gallery.

When clicking a card:

  • BI dashboard → opens the DATTABI screen locked in view-only mode (?view=dattabi&mode=view&dashId=<id>; see DATTABI — User Guide §15.2). The dashId travels in the query string, not as an internal navigation parameter, because that is where DATTABI reads it from.
  • Native panel → navigates to the native view of the context type (dashboard for judicial process, kyb-onboarding for registration dossier), already filtered by the workspace's contexts, without reloading the application.
  • Canvas panel → opens the panel in view mode (?view=painel&mode=view&ws=…&panel=…), with "Abrir no construtor" as a separate action — the gallery never enters the builder on its own.

Every card is a link: Ctrl/Cmd+click opens it in a new tab, and the keyboard reaches it without extra ARIA. The breadcrumb reflects the path actually taken (Painéis › panel), not the item's position in the menu — without that, the dossier panel would open as "Investigação › Onboarding PJ", which is right for someone who arrived from the menu and wrong for someone who clicked the card.

The builder does not show up in the URL either. The view is called painel, not panel-builder: the view id is visible in the address bar, and naming an internal tool there — to someone who merely opened a panel from the gallery — contradicts the very rule that keeps it out of the breadcrumb. There is a single view for viewing and editing; what changes is mode=view, not the screen. The old id (?view=panel-builder&…) remains as an alias, so links already saved keep working.

On a declarative panel opened as a viewer, the leaf of the breadcrumb is the panel title, never "Construtor de Painéis": DATTA › Painéis › Onboarding PJ — Pendências. The trigger is mode=view in the URL, not the navigation origin — origin is screen state and disappears on reload, and the card's deep-link is precisely a fresh load. The title comes from what the screen itself publishes (BREADCRUMB_SET). Inside the builder (no mode=view) the breadcrumb names it again, and the title becomes an extra level telling which panel is open: DATTA › Painéis › Construtor de Painéis › Onboarding PJ — Pendências.

External URLs possibly configured on a panel go through validation (safePanelUrl: only http(s)/relative) before window.open — blocking javascript:/data: (Project Guidelines §2).

  • The "Panel" item (the dashboard view = "Painel de Processos") was removed from the per-workspace feature list in the side menu, for being redundant with the "Panels" gallery — that panel remains accessible through the gallery's NATIVE card. The dashboard view remains routable (the ?view=dashboard deeplink keeps working).
  • The panel builder (the Panel Manager under Configure › Contexts) was kept — the "Panels" gallery/menu just does not expose the builder.

Multiple panel selection + panels popover on the home

This section covers two capabilities complementary to the panel catalog described above:

  1. Linking multiple existing panels to a workspace in a single operation (multi-selection), by reference — without duplicating the panel definition.
  2. Panels popover on the home (chat): the button next to the send-query control no longer navigates blindly to the cases panel and now opens a popover that lists the panels ready for consumption (a native panel only when it is linked to the active workspace).

On the manager's Panels tab (/configurar/workspaces), the Link existing button opens an M3 dialog with checkboxes — the user checks several catalog panels (GET /api/config/panels) at once and confirms. The selection state is a set (Set) initialized with the already-persisted links, so opening the dialog again shows what is already linked (screens/settings-workspaces.html).

The options offered are the flattened catalog, filtered like this (screens/settings-workspaces.html):

js
const options = catalog.filter(
  c => c.workspaceId !== selected.id || c.kind === 'dattabi-dashboard'
);

That is: canvas panels from other workspaces (the workspace's own already appears by itself in the workspace's panel list) plus the DATTABI dashboards (kind === 'dattabi-dashboard') from any workspace, including its own, and every native panel of the installation (Nativo group, first in the list). Each option shows the title and the origin (Plataforma for natives, or the source workspace's name). A ticked native panel gets, under the checkbox, the warning of what it will show in that workspace — "o painel abrirá sem registros" (no records), the records of another anchored context, or the dossiers of another context — and it is only a warning: saving is still allowed.

Confirmation persists the full list of references via PUT /api/config/workspaces/{id}/panel-refs. The links appear in the Linked panels section, each with an origin badge — Platform for native panels, Linked for the rest — and the Open (opens the source panel) and Remove link actions (screens/settings-workspaces.html). The workspace's card counter in the listing sums own + linked panels: (w.panels || []).length + (w.panelRefs || []).length (screens/settings-workspaces.html).

Reference, not copy. The link points to the source panel — editing the panel in the owning workspace is reflected in all that link it; removing the link does not delete the source panel (CA-2). The source of truth remains single.

Backend validation (setPanelRefs)

The workspaces API validates, deduplicates and normalizes the list before writing. Current rules:

  • Dedupe by the workspaceId::panelId key (repeated refs are discarded).
  • Refs with null workspaceId/panelId are ignored.
  • Redundant self-reference: a canvas panel of the workspace itself already appears by itself, so a ref to it is silently discarded.
  • Accepts: a native panel (panel catalog API), a canvas panel from any workspace visible to the user, or any reference to an existing and visible workspace (knownWorkspace — includes "native" and the store's workspaces that pass WorkspaceAccess.canSee; an invisible workspace is rejected with the same message as a non-existent id, so it cannot become an existence oracle). This covers the DATTABI dashboards (which come from the S2S catalog and are not Workspace.Panel): they are accepted through the existence of the source workspace and resolved in the menu/gallery via GET /api/config/panels.
  • Rejects only when the ref is not native, not canvas and the source workspace does not exist: 400 Bad Request with {"error":"Painel referenciado não existe: <ws>/<panel>"} (CA-4).

Note (evolution vs. the earlier section). The "Known limitations" section further above (inherited from the delivery of the DATTABI dashboards in the workspace) describes a gap in which refs to a DATTABI dashboard were rejected/discarded. The current setPanelRefs is more permissive: it validates the ref by the existence of the source workspace, so DATTABI dashboards from other workspaces and from the workspace itself are accepted as references; refs that do not resolve in the catalog are gracefully ignored at render time (they break neither the catalog nor the menu).

Permission: CONFIG_EDIT, in a double layer — a path-matcher in the SecurityConfig (pathMatchers(PUT,"/api/config/**").hasAnyAuthority("CONFIG_EDIT","ROLE_ADMIN")) plus @RequirePermission("CONFIG_EDIT") on the method (which returns Mono, the declared-permission check's reactive branch).

Panels popover on the home (chat)

On the home (chat), the button next to the send-query control became a popover toggle (the same visual pattern as the JDBC agents picker). The first click opens the popover and loads the catalog only once (lazy); clicking an item closes the popover and navigates to the chosen panel (CA-3).

The catalog comes from GET /api/config/panels and is filtered, on the home, to only panels ready for consumption — platform natives and published BI dashboards (chat.js:367-372):

js
fetch(API + '/api/config/panels')
  .then(r => r.ok ? r.json() : [])
  .then(d => setPanelsList((Array.isArray(d) ? d : [])
    .filter(p => p && (p.native || p.kind === 'dattabi-dashboard'))))
  .catch(() => setPanelsList([]));

Why canvas stays out of the home (a scope adjustment, user feedback on 2026-06-11): canvas panels are under construction in the builder and are accessed through the Panel/Workspace Managers — including them on the home duplicated the "Painel de Processos" entry (seeded canvas vs. native) and exposed a link to the builder on the home.

A native panel only when linked (decision of 2026-09-27). The popover shows a native panel in the Plataforma group only when it is linked to the active workspace (the entry's workspaceIds, as in the gallery); under Todos os workspaces it shows the natives linked to some workspace you can see — the gallery route does not return a native panel nobody linked. Before, every native panel of the installation showed up there for any user, in any workspace: a member of "Assistência Social" only saw the Painel de Processos and another workspace's contracts panel, and clicking opened the panel with their own workspace's scope.

Each item shows the panel's title and origin. States in pt-BR: "Carregando painéis..." (loading) and "Nenhum painel disponível para o seu usuário." (empty). If the fetch fails, the list falls back to empty — the popover degrades to the friendly empty state, without a raw error (Project Guidelines §5).

Click routing (chat.js:openPanelEntry, chat.js:384-403):

  • Native (p.native): navigates within the shell itself (SPA) via window.parent.postMessage({type:'NAVIGATE_TO', payload: p.view || 'dashboard'}).
  • BI dashboard (kind === 'dattabi-dashboard'): opens p.url (/dattabi.html?dashId=<id>) in a new tab, after passing through safePanelUrl.
  • Canvas (does not appear on the home today, but the routing exists): ?view=painel&ws=<ws>&panel=<panel>&mode=view in a new tab.

URL safety. URLs coming from the panel config go through safePanelUrl, which only accepts http/https (or relative) — blocking javascript:/data: writable by anyone with CONFIG_EDIT (Project Guidelines §2).

The PANEL_VIEW permission

Reading the catalog and opening panels in view mode now accept the dedicated PANEL_VIEW permission (Config category, registered in the central Permission catalog) or CONFIG_VIEW — any-of semantics via @RequirePermission({"PANEL_VIEW", "CONFIG_VIEW"}) (the annotation was extended to accept String[]). This avoids requiring CONFIG_VIEW (admin-leaning) from a regular user just to see/consume panels.

Current any-of gates:

EndpointAny-of permission
GET /api/config/panels (panel catalog API)PANEL_VIEW \
GET /api/config/workspaces/{id} (workspaces API)PANEL_VIEW \
POST /api/config/panel/{domain}/aggregate and .../preview (panels data API)PANEL_VIEW \

For the panel data endpoints (aggregate/preview), which are rendering reads despite being POST (parameters only in the body), there is a dedicated matcher in the SecurityConfig before the mutation gate, so that PANEL_VIEW unlocks the read without granting write.

PANEL_VIEW is mapped to the default roles ADVANCED_USER, ANALISTA and READ_ONLY (RolePermissions + BuiltInRoleSync). Non-admin users need to log in again for the JWT to carry the new permission.

How to use (step by step)

How the sidebar reflects the active workspace:

The menu shows the features of the selected workspace, and switching the workspace on the card at the top replaces the list. There is no hub and no workspace listing in the navigation: the card is the control.

Always visible, whatever the workspace: Chat, Painéis, DATTA Captain, Documentação, Sistema and the profile. Those are platform, not team work — and filtering the Sistema hub could lock the administrator out of the configuration itself.

A group whose entire contents are disabled does not appear. While no workspace is resolved yet — during loading, if the call fails, or if the user has access to none — the menu shows everything: an empty menu would have neither a way out nor an explanation.

To choose what each workspace shows, use the Features tab of the management screen.

Create a workspace:

  1. Open SistemaWorkspaces.
  2. Click Novo workspace, at the top of the list on the left.
  3. Fill in the name (required) and a description (optional), then confirm with Criar workspace.

The workspace is created empty and is selected right away: the tabs on the right — Features, Data Contexts, Panels and Members — are where it gets its content. While it has no members it is public to anyone who can see the screen; once it gets its first member, it only shows up for members and the owner.

Requires the CONFIG_EDIT permission.

Create a panel of the workspace's own:

  1. Select the workspace and open the Panels tab.
  2. Click Novo painel, fill in the title and confirm with Criar e abrir.

The panel is created empty and opens in the panel builder in another tab, where the widgets and the data source are defined. This differs from Vincular existentes, which only brings a panel that already exists elsewhere into this workspace — linking neither copies nor duplicates it.

Link several panels at once:

  1. Go to Configure → Workspaces and select the workspace.
  2. On the Panels tab, click Link existing.
  3. Check, with the checkboxes, all the desired panels (BI dashboards and/or panels from other workspaces) and confirm.
  4. They appear in Linked panels with the origin badge (Platform/Linked) and the Open and Remove link actions.
  5. Removing the link removes only the reference — the source panel remains.

Discover and open panels from the home:

  1. On the home (chat), click the button next to the send-query control.
  2. The Panels popover lists the accessible panels: the BI dashboards and the native panels linked to the active workspace.
  3. Click an item to open the chosen panel.