OctoMesh Data Refinery Studio (Angular)
Purpose
Developer guide for working in octo-frontend-refinery-studio — the main
Angular web application for OctoMesh. The Studio is a unified workspace for
three audiences:
- Developers — design Construction Kits (CK), configure data models,
build integrations
- Data owners — build dashboards (MeshBoards), define queries, manage
data pipelines
- End users — interactive dashboards, real-time visualizations, KPIs
This is NOT the old admin panel. octo-frontend-admin-panel is the
legacy interface. New frontend feature work belongs in Refinery Studio.
CRITICAL: where the app actually lives
The git repo root (C:\dev\meshmakers\octo-frontend-refinery-studio) is not
the npm project. The app package is one level down:
octo-frontend-refinery-studio/
└── src/
└── octo-mesh-refinery-studio/ ← the Angular app (package.json, codegen.yml, src/)
Run all npm/ng commands from src/octo-mesh-refinery-studio/. There is no
root-level package.json.
Tech Stack (verified from package.json)
| Piece |
Version |
Notes |
| Angular |
^21.2.4 |
Standalone components + signals; app- selector prefix |
| Apollo Angular |
^13.0.0 |
GraphQL client (@apollo/client ^4.1.6) |
| Kendo UI Angular |
23.2.0 |
@progress/kendo-angular-* component suite |
| RxJS |
~7.8.2 |
Reactive streams |
| TypeScript |
~5.9.3 |
Strict; ESLint via angular-eslint 21 |
| angular-oauth2-oidc |
^20.0.2 |
Auth, wrapped by @meshmakers/shared-auth |
Other notable deps: monaco-editor (YAML/code editing), dockview-angular
(dock layouts), cytoscape + dagre (graph views), cron-parser/cronstrue
(schedule UIs), tus-js-client (resumable uploads), @microsoft/signalr.
CK construction-kit terms: CK = schema (CkTypeDto, CkEnumDto,
CkRecordDto, CkAttributeDto); Rt = data instances (RtEntityDto with
rtId, ckTypeId, associations). Use rtCkTypeId (e.g.
OctoSdkDemo/Customer) for runtime queries, not fullName.
Commands (verified in package.json — run from src/octo-mesh-refinery-studio/)
| Command |
What it does |
Label |
npm install |
Install deps (resolves @meshmakers/* from local file: dist) |
Mutating (writes node_modules) |
npm start / ng serve |
Dev server at https://localhost:4200 |
Read-only |
npm run build |
ng lint && ng build (lint gate is built in) |
Read-only (build output) |
npm run build:skip-lint |
ng build without lint |
Read-only |
npm run watch |
ng build --watch --configuration development |
Read-only |
npm run lint / ng lint |
ESLint over the project |
Read-only |
ng lint --fix |
Auto-fix unused imports etc. |
Mutating (rewrites source) |
npm test |
ng test --watch=false --browsers=ChromeHeadlessCI |
Read-only |
npm run codegen |
Regenerate GraphQL types/services |
Mutating (rewrites generated .ts) |
npm start/npm run build are prefixed by a setup-license step
(scripts/setup-license.js) for the Kendo license — do not bypass it.
Lint/test discipline (from the repo CLAUDE.md — REQUIRED)
Always run the linter after every code change. CI fails on any lint
error. Common fixes: unused imports → ng lint --fix; intentionally unused
vars → prefix with _; missing types → add explicit annotations.
Pre-commit gate (run from src/octo-mesh-refinery-studio/):
ng lint && npm test -- --watch=false --browsers=ChromeHeadless && ng build --configuration development
If package.json changed (incl. via npm install), regenerate the lock file
before committing: rm -f package-lock.json && npm install (CI runs
npm install and needs them in sync).
Multi-Tenant Routing
Routes follow the /:tenantId/... pattern. Each tenant gets an isolated
Apollo client pointing at that tenant's GraphQL endpoint. Feature areas are
lazy-loaded via *.routes.ts:
repository/ — Runtime Browser, CK Browser, Auto-Increment, Fixup Scripts,
Events, Query Builder, Archives
reporting/ — Report Explorer (folder/file tree)
identity/ — users, roles, groups, OAuth clients, identity providers
communication/ — adapters, pools, applications, data flows
general/, bot/, development/, ui-management/
When adding a feature, register its routes under the relevant parent
*.routes.ts with a loadChildren import and a breadcrumb data entry.
OctoGraphQlDataSource Pattern (list views)
The primary list/grid is ListViewComponent (mm-list-view) from
@meshmakers/shared-ui. Back it with a directive that extends
OctoGraphQlDataSource<T> (from @meshmakers/octo-ui). Verified sketch,
condensed from tenants/communication/adapters/data-sources/adapters-data-source.directive.ts:
import { Directive, forwardRef, inject } from "@angular/core";
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { OctoGraphQlDataSource } from '@meshmakers/octo-ui';
import { DataSourceBase, FetchDataOptions, FetchResultTyped, ListViewComponent } from '@meshmakers/shared-ui';
import { GraphQL } from '@meshmakers/octo-services';
import { GetSystemCommunicationAdaptersDtoGQL, GetSystemCommunicationAdaptersQueryDto } from '../../../../graphQL/getSystemCommunicationAdapters';
// Derive the item type from the generated query type (no hand-written DTOs)
type Item = NonNullable<NonNullable<NonNullable<GetSystemCommunicationAdaptersQueryDto['runtime']>['systemCommunicationAdapter']>['items']>[number];
export type AdapterDto = NonNullable<Item>;
@Directive({
selector: "[appAdaptersDataSource]",
exportAs: 'appAdaptersDataSource',
providers: [{ provide: DataSourceBase, useExisting: forwardRef(() => AdaptersDataSourceDirective) }]
})
export class AdaptersDataSourceDirective extends OctoGraphQlDataSource<AdapterDto> {
private readonly gql = inject(GetSystemCommunicationAdaptersDtoGQL);
constructor() {
super(inject(ListViewComponent));
this.searchFilterAttributePaths = ['name']; // fields the text box searches
}
public override fetchData(options: FetchDataOptions): Observable<FetchResultTyped<AdapterDto> | null> {
const variables = {
first: options.state.take,
after: GraphQL.offsetToCursor(options.state.skip ?? 0),
sortOrder: this.getSortDefinitions(options.state),
fieldFilter: this.getFieldFilterDefinitions(options.state),
searchFilter: this.getSearchFilterDefinitions(options.textSearch)
};
return this.gql.fetch({ variables, fetchPolicy: "network-only" }).pipe(map(result =>
new FetchResultTyped<AdapterDto>(
result.data?.runtime?.systemCommunicationAdapter?.items?.filter(i => i !== null) as AdapterDto[] || [],
result.data?.runtime?.systemCommunicationAdapter?.totalCount ?? 0
)));
}
}
Key points:
- The base class supplies
getSortDefinitions, getFieldFilterDefinitions,
getSearchFilterDefinitions — use them; do not hand-roll Kendo state parsing.
- Always
fetchPolicy: "network-only" for live list data.
- Derive DTO types from the generated query type; never duplicate the shape.
- Wire it on the template via the directive selector and
exportAs:
<mm-list-view appAdaptersDataSource #dir="appAdaptersDataSource" ...>.
- Copy ID context menu is REQUIRED on every list/detail view showing Rt
entities (submenu: RtId, CkTypeId, RtCkTypeId, RtEntityId). The GraphQL query
must select
constructionKitType { ckTypeId { fullName } }.
For the full new-list-component checklist (folder layout, routes, mm-list-view
inputs, Copy-ID implementation), read
references/data-source-and-components.md.
GraphQL Code Generation Workflow
GraphQL operations live in src/app/graphQL/*.graphql. After editing or adding
one, run npm run codegen. Config is codegen.yml (verified):
- Generated types get the
Dto suffix (typesSuffix: Dto) →
RtEntityDto, CkTypeDto, GetSystemCommunicationAdaptersQueryDto, etc.
near-operation-file preset → one generated .ts per .graphql operation,
with shared base types in globalTypes.ts.
- An injectable Apollo Angular service is generated per operation
(
...DtoGQL, e.g. GetSystemCommunicationAdaptersDtoGQL) — inject it with
inject(...).
possibleTypes.ts (fragment matcher) and scalars: { DateTime: Date } are
emitted too.
Never edit generated .ts by hand — edit the .graphql, regenerate. The
generated GraphQL folder is excluded from ESLint. Ensure schema.graphql is
current before generating.
LCARS Theme System
The Studio uses a Star-Trek-LCARS-inspired theme built from the Octo Brand
Manual. src/styles.scss is the single source of truth for theme tokens,
global LCARS layout classes, and Kendo overrides.
Two token tiers:
- Brand tokens (theme-invariant) —
--octo-mint #64ceb9, --neo-cyan
#00a8dc, --royal-violet #6c4da8, --toffee #da9162, --bubblegum
#ec658f, etc. Use these for decorative accents (header bar, footer ribbon).
- Semantic theme tokens (
--theme-*) — --theme-bg-app,
--theme-bg-surface, --theme-text-primary, --theme-text-secondary,
--theme-text-accent, --theme-border-subtle, --theme-glow-primary,
--theme-status-success/warning/error/info, --theme-chart-1..8. These have
dark defaults and light overrides; use them for anything that must adapt to
dark/light mode.
Dark is default; light auto-applies on prefers-color-scheme: light unless the
user forces a theme via the AppBar toggle (ThemeService writes
<html data-theme="…">, persisted in localStorage key
octo-theme-preference).
Do / Do-not (from repo CLAUDE.md)
- Do use
var(--theme-bg-*), var(--theme-text-*), var(--theme-border-*)
for theme-dependent values, and var(--octo-mint) etc. for brand accents.
- Do use
color-mix(in srgb, var(--brand) X%, transparent) for alpha
derivations.
- Do NOT redeclare brand color SCSS vars at the top of a component's SCSS —
styles.scss owns them.
- Do NOT duplicate the global LCARS layout classes
(
.lcars-page-header, .lcars-content-panel, .lcars-footer, .footer-bar,
etc.) in component SCSS — they are global. Component SCSS should hold only the
container class (background gradient), responsive padding, and component
::ng-deep overrides.
- Do NOT use pure black — the darkest background is Deep Sea
#07172b.
- Every page-level component MUST use the standard LCARS layout (header /
content panel / footer). Library components stay theme-agnostic; LCARS styling
is the host app's job.
For the full token catalog, page-layout HTML/SCSS template, and component-author
conventions, read references/lcars-theme.md.
Shared Libraries — octo-frontend-libraries
The @meshmakers/* packages are developed in the separate
octo-frontend-libraries repo and consumed here, not via an npm-link
script. In package.json they are file: references into the sibling repo's
built dist:
"@meshmakers/octo-ui": "file:../../../octo-frontend-libraries/src/frontend-libraries/dist/meshmakers/octo-ui"
(CI/Docker swaps these file: refs for registry versions before install.)
| Library |
Provides |
@meshmakers/shared-auth |
OAuth2/OIDC (AuthorizeGuard, AuthorizeService) |
@meshmakers/shared-services |
messages, breadcrumbs, CommandItem, TreeItemDataTyped |
@meshmakers/shared-ui |
ListViewComponent, DataSourceBase, FetchResultTyped, dialogs |
@meshmakers/octo-services |
GraphQL utilities, OctoErrorLink |
@meshmakers/octo-ui |
PropertyGridComponent, OctoGraphQlDataSource, Runtime Browser |
@meshmakers/octo-process-diagrams |
process diagram / symbol editor |
@meshmakers/octo-meshboard |
dashboard widgets (KPI, Gauge, Chart, …) |
To change a shared library, edit and build it in octo-frontend-libraries
(per-library script, e.g. npm run build:octo-ui, which runs ng lint && ng build), then re-run npm install here to pick up the updated dist/. Clear
the Angular cache if stale: npx ng cache clean. Keep @angular/* versions
aligned across both repos or npm install hits ERESOLVE peer conflicts.
Backend for local UI dev
The Studio needs running OctoMesh services. To stand up a meshtest tenant
with sample data (commands run via octo-cli, which must be on PATH):
octo-cli -c Create -tid meshtest -db meshtest # create tenant (Mutating)
./om_importck.ps1 -configuration Debug # import sample CKs
./om_importrt_sample_general.ps1 # optional runtime data
./om_importrt_sample_simulation.ps1 # optional simulation feed
For building/starting the backend services and infrastructure, defer to the
octo-devtools skill.
Common Pitfalls (from the repo CLAUDE.md)
- Running npm/ng from the repo root — there is no package.json there; use
src/octo-mesh-refinery-studio/.
- Editing generated GraphQL
.ts files by hand instead of the .graphql
source + npm run codegen.
- Forgetting
npm run codegen after touching a .graphql file (build then
references a missing/old ...DtoGQL).
- Skipping
ng lint — CI fails on any lint error; unused imports and untyped
vars are the usual culprits.
- Hand-writing DTO interfaces instead of deriving from generated query types.
- Duplicating global LCARS classes or brand color vars in component SCSS.
- Mismatched
@angular/* versions between this repo and
octo-frontend-libraries → ERESOLVE on install.
- Omitting the Copy-ID context menu (and its
constructionKitType query field)
on Rt entity list/detail views.
References
references/data-source-and-components.md — new list-component checklist,
mm-list-view inputs, OctoGraphQlDataSource details, Copy-ID context menu,
CK detail-inline conventions.
references/lcars-theme.md — brand + semantic token catalog, page-layout
HTML/SCSS template, light-theme tokens, Kendo overrides, component-author
conventions.
1---2name: refinery-studio3description: Guides Angular development on the OctoMesh Data Refinery Studio (octo-frontend-refinery-studio) — the main web app for CK model design, dashboards, queries, pipelines, and visualizations (distinct from the older admin panel). Covers the tech stack, multi-tenant /:tenantId/ routing, the OctoGraphQlDataSource list-view pattern, the GraphQL codegen workflow, the LCARS theme token system, the link to octo-frontend-libraries, and the lint/test/build commands. Trigger on: refinery studio, data refinery, OctoMesh frontend, Angular component work, mm-list-view, OctoGraphQlDataSource, data source directive, GraphQL codegen frontend, npm run codegen, LCARS theme, theme tokens, Kendo UI, Apollo Angular, tenant routing, octo-frontend-libraries.4---56# OctoMesh Data Refinery Studio (Angular)78## Purpose910Developer guide for working in **`octo-frontend-refinery-studio`** — the main11Angular web application for OctoMesh. The Studio is a unified workspace for12three audiences:1314- **Developers** — design Construction Kits (CK), configure data models,15 build integrations16- **Data owners** — build dashboards (MeshBoards), define queries, manage17 data pipelines18- **End users** — interactive dashboards, real-time visualizations, KPIs1920**This is NOT the old admin panel.** `octo-frontend-admin-panel` is the21legacy interface. New frontend feature work belongs in Refinery Studio.2223## CRITICAL: where the app actually lives2425The git repo root (`C:\dev\meshmakers\octo-frontend-refinery-studio`) is **not**26the npm project. The app package is one level down:2728```29octo-frontend-refinery-studio/30└── src/31 └── octo-mesh-refinery-studio/ ← the Angular app (package.json, codegen.yml, src/)32```3334**Run all npm/ng commands from `src/octo-mesh-refinery-studio/`.** There is no35root-level `package.json`.3637## Tech Stack (verified from package.json)3839| Piece | Version | Notes |40|-------|---------|-------|41| Angular | `^21.2.4` | Standalone components + signals; `app-` selector prefix |42| Apollo Angular | `^13.0.0` | GraphQL client (`@apollo/client ^4.1.6`) |43| Kendo UI Angular | `23.2.0` | `@progress/kendo-angular-*` component suite |44| RxJS | `~7.8.2` | Reactive streams |45| TypeScript | `~5.9.3` | Strict; ESLint via `angular-eslint 21` |46| angular-oauth2-oidc | `^20.0.2` | Auth, wrapped by `@meshmakers/shared-auth` |4748Other notable deps: `monaco-editor` (YAML/code editing), `dockview-angular`49(dock layouts), `cytoscape` + `dagre` (graph views), `cron-parser`/`cronstrue`50(schedule UIs), `tus-js-client` (resumable uploads), `@microsoft/signalr`.5152CK construction-kit terms: **CK** = schema (`CkTypeDto`, `CkEnumDto`,53`CkRecordDto`, `CkAttributeDto`); **Rt** = data instances (`RtEntityDto` with54`rtId`, `ckTypeId`, associations). Use `rtCkTypeId` (e.g.55`OctoSdkDemo/Customer`) for runtime queries, **not** `fullName`.5657## Commands (verified in package.json — run from `src/octo-mesh-refinery-studio/`)5859| Command | What it does | Label |60|---------|--------------|-------|61| `npm install` | Install deps (resolves `@meshmakers/*` from local `file:` dist) | Mutating (writes node_modules) |62| `npm start` / `ng serve` | Dev server at `https://localhost:4200` | Read-only |63| `npm run build` | `ng lint && ng build` (lint gate is built in) | Read-only (build output) |64| `npm run build:skip-lint` | `ng build` without lint | Read-only |65| `npm run watch` | `ng build --watch --configuration development` | Read-only |66| `npm run lint` / `ng lint` | ESLint over the project | Read-only |67| `ng lint --fix` | Auto-fix unused imports etc. | Mutating (rewrites source) |68| `npm test` | `ng test --watch=false --browsers=ChromeHeadlessCI` | Read-only |69| `npm run codegen` | Regenerate GraphQL types/services | Mutating (rewrites generated `.ts`) |7071`npm start`/`npm run build` are prefixed by a `setup-license` step72(`scripts/setup-license.js`) for the Kendo license — do not bypass it.7374### Lint/test discipline (from the repo CLAUDE.md — REQUIRED)7576> **Always run the linter after every code change.** CI fails on any lint77> error. Common fixes: unused imports → `ng lint --fix`; intentionally unused78> vars → prefix with `_`; missing types → add explicit annotations.7980Pre-commit gate (run from `src/octo-mesh-refinery-studio/`):8182```bash83ng lint && npm test -- --watch=false --browsers=ChromeHeadless && ng build --configuration development84```8586If `package.json` changed (incl. via `npm install`), regenerate the lock file87before committing: `rm -f package-lock.json && npm install` (CI runs88`npm install` and needs them in sync).8990## Multi-Tenant Routing9192Routes follow the **`/:tenantId/...`** pattern. Each tenant gets an isolated93Apollo client pointing at that tenant's GraphQL endpoint. Feature areas are94lazy-loaded via `*.routes.ts`:9596- `repository/` — Runtime Browser, CK Browser, Auto-Increment, Fixup Scripts,97 Events, Query Builder, Archives98- `reporting/` — Report Explorer (folder/file tree)99- `identity/` — users, roles, groups, OAuth clients, identity providers100- `communication/` — adapters, pools, applications, data flows101- `general/`, `bot/`, `development/`, `ui-management/`102103When adding a feature, register its routes under the relevant parent104`*.routes.ts` with a `loadChildren` import and a `breadcrumb` data entry.105106## OctoGraphQlDataSource Pattern (list views)107108The primary list/grid is `ListViewComponent` (`mm-list-view`) from109`@meshmakers/shared-ui`. Back it with a **directive** that extends110`OctoGraphQlDataSource<T>` (from `@meshmakers/octo-ui`). Verified sketch,111condensed from `tenants/communication/adapters/data-sources/adapters-data-source.directive.ts`:112113```typescript114import { Directive, forwardRef, inject } from "@angular/core";115import { Observable } from 'rxjs';116import { map } from 'rxjs/operators';117import { OctoGraphQlDataSource } from '@meshmakers/octo-ui';118import { DataSourceBase, FetchDataOptions, FetchResultTyped, ListViewComponent } from '@meshmakers/shared-ui';119import { GraphQL } from '@meshmakers/octo-services';120import { GetSystemCommunicationAdaptersDtoGQL, GetSystemCommunicationAdaptersQueryDto } from '../../../../graphQL/getSystemCommunicationAdapters';121122// Derive the item type from the generated query type (no hand-written DTOs)123type Item = NonNullable<NonNullable<NonNullable<GetSystemCommunicationAdaptersQueryDto['runtime']>['systemCommunicationAdapter']>['items']>[number];124export type AdapterDto = NonNullable<Item>;125126@Directive({127 selector: "[appAdaptersDataSource]",128 exportAs: 'appAdaptersDataSource',129 providers: [{ provide: DataSourceBase, useExisting: forwardRef(() => AdaptersDataSourceDirective) }]130})131export class AdaptersDataSourceDirective extends OctoGraphQlDataSource<AdapterDto> {132 private readonly gql = inject(GetSystemCommunicationAdaptersDtoGQL);133134 constructor() {135 super(inject(ListViewComponent));136 this.searchFilterAttributePaths = ['name']; // fields the text box searches137 }138139 public override fetchData(options: FetchDataOptions): Observable<FetchResultTyped<AdapterDto> | null> {140 const variables = {141 first: options.state.take,142 after: GraphQL.offsetToCursor(options.state.skip ?? 0),143 sortOrder: this.getSortDefinitions(options.state),144 fieldFilter: this.getFieldFilterDefinitions(options.state),145 searchFilter: this.getSearchFilterDefinitions(options.textSearch)146 };147 return this.gql.fetch({ variables, fetchPolicy: "network-only" }).pipe(map(result =>148 new FetchResultTyped<AdapterDto>(149 result.data?.runtime?.systemCommunicationAdapter?.items?.filter(i => i !== null) as AdapterDto[] || [],150 result.data?.runtime?.systemCommunicationAdapter?.totalCount ?? 0151 )));152 }153}154```155156Key points:157- The base class supplies `getSortDefinitions`, `getFieldFilterDefinitions`,158 `getSearchFilterDefinitions` — use them; do not hand-roll Kendo state parsing.159- Always `fetchPolicy: "network-only"` for live list data.160- Derive DTO types from the **generated** query type; never duplicate the shape.161- Wire it on the template via the directive selector and `exportAs`:162 `<mm-list-view appAdaptersDataSource #dir="appAdaptersDataSource" ...>`.163- **Copy ID context menu** is REQUIRED on every list/detail view showing Rt164 entities (submenu: RtId, CkTypeId, RtCkTypeId, RtEntityId). The GraphQL query165 must select `constructionKitType { ckTypeId { fullName } }`.166167For the full new-list-component checklist (folder layout, routes, `mm-list-view`168inputs, Copy-ID implementation), read169`references/data-source-and-components.md`.170171## GraphQL Code Generation Workflow172173GraphQL operations live in `src/app/graphQL/*.graphql`. After editing or adding174one, run `npm run codegen`. Config is `codegen.yml` (verified):175176- Generated types get the **`Dto`** suffix (`typesSuffix: Dto`) →177 `RtEntityDto`, `CkTypeDto`, `GetSystemCommunicationAdaptersQueryDto`, etc.178- `near-operation-file` preset → one generated `.ts` per `.graphql` operation,179 with shared base types in `globalTypes.ts`.180- An injectable Apollo Angular service is generated per operation181 (`...DtoGQL`, e.g. `GetSystemCommunicationAdaptersDtoGQL`) — inject it with182 `inject(...)`.183- `possibleTypes.ts` (fragment matcher) and `scalars: { DateTime: Date }` are184 emitted too.185186**Never edit generated `.ts` by hand** — edit the `.graphql`, regenerate. The187generated GraphQL folder is excluded from ESLint. Ensure `schema.graphql` is188current before generating.189190## LCARS Theme System191192The Studio uses a Star-Trek-LCARS-inspired theme built from the Octo Brand193Manual. **`src/styles.scss` is the single source of truth** for theme tokens,194global LCARS layout classes, and Kendo overrides.195196Two token tiers:197198- **Brand tokens (theme-invariant)** — `--octo-mint` `#64ceb9`, `--neo-cyan`199 `#00a8dc`, `--royal-violet` `#6c4da8`, `--toffee` `#da9162`, `--bubblegum`200 `#ec658f`, etc. Use these for decorative accents (header bar, footer ribbon).201- **Semantic theme tokens (`--theme-*`)** — `--theme-bg-app`,202 `--theme-bg-surface`, `--theme-text-primary`, `--theme-text-secondary`,203 `--theme-text-accent`, `--theme-border-subtle`, `--theme-glow-primary`,204 `--theme-status-success/warning/error/info`, `--theme-chart-1..8`. These have205 dark defaults and light overrides; use them for anything that must adapt to206 dark/light mode.207208Dark is default; light auto-applies on `prefers-color-scheme: light` unless the209user forces a theme via the AppBar toggle (`ThemeService` writes210`<html data-theme="…">`, persisted in localStorage key211`octo-theme-preference`).212213### Do / Do-not (from repo CLAUDE.md)214215- **Do** use `var(--theme-bg-*)`, `var(--theme-text-*)`, `var(--theme-border-*)`216 for theme-dependent values, and `var(--octo-mint)` etc. for brand accents.217- **Do** use `color-mix(in srgb, var(--brand) X%, transparent)` for alpha218 derivations.219- **Do NOT** redeclare brand color SCSS vars at the top of a component's SCSS —220 `styles.scss` owns them.221- **Do NOT** duplicate the global LCARS layout classes222 (`.lcars-page-header`, `.lcars-content-panel`, `.lcars-footer`, `.footer-bar`,223 etc.) in component SCSS — they are global. Component SCSS should hold only the224 container class (background gradient), responsive padding, and component225 `::ng-deep` overrides.226- **Do NOT** use pure black — the darkest background is Deep Sea `#07172b`.227- Every page-level component MUST use the standard LCARS layout (header /228 content panel / footer). Library components stay theme-agnostic; LCARS styling229 is the host app's job.230231For the full token catalog, page-layout HTML/SCSS template, and component-author232conventions, read `references/lcars-theme.md`.233234## Shared Libraries — `octo-frontend-libraries`235236The `@meshmakers/*` packages are developed in the **separate**237`octo-frontend-libraries` repo and consumed here, **not** via an npm-link238script. In `package.json` they are `file:` references into the sibling repo's239built dist:240241```242"@meshmakers/octo-ui": "file:../../../octo-frontend-libraries/src/frontend-libraries/dist/meshmakers/octo-ui"243```244245(CI/Docker swaps these `file:` refs for registry versions before install.)246247| Library | Provides |248|---------|----------|249| `@meshmakers/shared-auth` | OAuth2/OIDC (`AuthorizeGuard`, `AuthorizeService`) |250| `@meshmakers/shared-services` | messages, breadcrumbs, `CommandItem`, `TreeItemDataTyped` |251| `@meshmakers/shared-ui` | `ListViewComponent`, `DataSourceBase`, `FetchResultTyped`, dialogs |252| `@meshmakers/octo-services` | `GraphQL` utilities, `OctoErrorLink` |253| `@meshmakers/octo-ui` | `PropertyGridComponent`, `OctoGraphQlDataSource`, Runtime Browser |254| `@meshmakers/octo-process-diagrams` | process diagram / symbol editor |255| `@meshmakers/octo-meshboard` | dashboard widgets (KPI, Gauge, Chart, …) |256257**To change a shared library**, edit and build it in `octo-frontend-libraries`258(per-library script, e.g. `npm run build:octo-ui`, which runs `ng lint && ng259build`), then re-run `npm install` here to pick up the updated `dist/`. Clear260the Angular cache if stale: `npx ng cache clean`. Keep `@angular/*` versions261aligned across both repos or `npm install` hits `ERESOLVE` peer conflicts.262263## Backend for local UI dev264265The Studio needs running OctoMesh services. To stand up a `meshtest` tenant266with sample data (commands run via octo-cli, which must be on PATH):267268```powershell269octo-cli -c Create -tid meshtest -db meshtest # create tenant (Mutating)270./om_importck.ps1 -configuration Debug # import sample CKs271./om_importrt_sample_general.ps1 # optional runtime data272./om_importrt_sample_simulation.ps1 # optional simulation feed273```274275For building/starting the backend services and infrastructure, defer to the276`octo-devtools` skill.277278## Common Pitfalls (from the repo CLAUDE.md)279280- Running npm/ng from the repo root — there is no package.json there; use281 `src/octo-mesh-refinery-studio/`.282- Editing generated GraphQL `.ts` files by hand instead of the `.graphql`283 source + `npm run codegen`.284- Forgetting `npm run codegen` after touching a `.graphql` file (build then285 references a missing/old `...DtoGQL`).286- Skipping `ng lint` — CI fails on any lint error; unused imports and untyped287 vars are the usual culprits.288- Hand-writing DTO interfaces instead of deriving from generated query types.289- Duplicating global LCARS classes or brand color vars in component SCSS.290- Mismatched `@angular/*` versions between this repo and291 `octo-frontend-libraries` → `ERESOLVE` on install.292- Omitting the Copy-ID context menu (and its `constructionKitType` query field)293 on Rt entity list/detail views.294295## References296297- `references/data-source-and-components.md` — new list-component checklist,298 `mm-list-view` inputs, OctoGraphQlDataSource details, Copy-ID context menu,299 CK detail-inline conventions.300- `references/lcars-theme.md` — brand + semantic token catalog, page-layout301 HTML/SCSS template, light-theme tokens, Kendo overrides, component-author302 conventions.