Files
dashfront/AGENTS.md
2026-10-13 17:19:33 +02:00

33 KiB

AGENTS.md — Dashfront Developer & Agent Guide

Audience: AI Coding Agents & Pair-Programmers working on dashfront.
Workspace: /home/seb/src/dashfront
Last Updated: 2026-09-21


Table of Contents

  1. System Overview & Ecosystem Map
  2. Technology Stack & Key Libraries
  3. Directory Layout
  4. State Management Conventions
  5. Backend Communication & Authentication Rules
  6. Route & Navigation Architecture
  7. Developer Workflows & Commands
  8. Critical Agent Rules & Common Pitfalls
  9. Deep Dive: The Automats (react-automat)
  10. Deep Dive: Configuration Automats (Company, Category, Brand, Unit & POS Terminals)
  11. dashgui Component Library Integration
  12. Application Views & Route Hierarchy
  13. Media, Images & Document Pipelines
  14. Real-time SSE Signals & Invalidation
  15. Developer Tooling & Debugging
  16. Agent Cheatsheet & Code Recipes

1. System Overview & Ecosystem Map

dashfront is the React web client and Progressive Web App (PWA) for the Dash ERP/POS system. It is part of a multi-repository workspace under /home/seb/src/:

/home/seb/src/
├── dashfront/         # THIS REPO: Vite + React 19 web/PWA client (port 4209 HTTP, 4308 HTTPS)
├── dashback/          # Backend Express REST/SSE API server (port 4208)
├── dashdbschema/      # LibDashStore (MSSQL data layer, migrations, schema graph, API docs)
├── dashgui/           # Reusable custom UI component library (file:../dashgui)
└── automat/           # react-automat state management library (file:../automat or npm)

End-to-End Data & Execution Flow

# Machine-readable execution flow:
flow:
  - step: 1_client
    component: dashfront
    runtime: React 19 (PureComponent & Function Components)
    state_layers:
      automats: [artikelAutomat, articleSearchAutomat, articleIndexAutomat, deliveryEditorAutomat, authAutomat, sseAutomat, supplierAutomat, navigationAutomat, userSettingsAutomat, companyAutomat, categoryAutomat, brandAutomat, unitAutomat, posterminalAutomat, deliveryAutomat, quoteAutomat, orderAutomat, entityAutomat, customergroupAutomat, numberAutomat]
    transport: src/api (http(), named namespaces)
    egress:
      protocol: HTTP (fetch with credentials: "include") & SSE (/api/events)
      proxy: Vite dev server (/api -> http://localhost:4208)
      target: dashback

  - step: 2_api_gateway
    component: dashback
    runtime: Express 5 API server (src/api/routes/*)
    security:
      auth_middleware: Cookie auth middleware (validates JWT in HTTP-only "token" cookie)
      context_injection:
        user_auth_id: req.user.googleAuthId
        tenant_company_id: req.selectedCompanyId
    events: Dispatches real-time SSE mutation events to subscribed clients via /api/events
    egress:
      interface: In-process method calls (store.<namespace>.<method>())
      target: dashdbschema

  - step: 3_data_layer
    component: dashdbschema
    runtime: LibDashStore (src/store/*)
    storage: MSSQL connection pool, migrations, and SQL transactions

2. Technology Stack & Key Libraries

Technology Version / Spec Notes
Build & Dev Vite 8 (type: module) Dev server on 4209, HTTPS on 4308, proxies /api → http://localhost:4208
Framework React 19 (react, react-dom) Uses PureComponent (with Automats & dashgui) and modern function components
Routing react-router-dom v7 Configured in src/appRouter.jsx with HMR router preservation
UI & Theming MUI 9 (@mui/material, Emotion) Custom theme in src/theme/, base background #85b7ad in src/colors.js
Shared GUI dashgui (file:../dashgui) PanelTile, RecordList, Tile, SingleLineTextEdit, ElevatedPill
State Management react-automat Single state layer for all domain & configuration data (articles, categories, company, brands, units, POS terminals, session)
Notifications notistack useSnackbar() / <SnackbarProvider> in src/main.jsx
Media & Images @jsquash/avif, @jsquash/resize, thumbhash Client-side AVIF encoding and instant thumbnail hash generation
Documents pdfconvert-wasm In-browser PDF processing for supplier delivery invoices & receipts
Drag & Drop @shopify/draggable, sortablejs Category re-ordering, article assignments, nested tree nodes

3. Directory Layout

src/
├── api/                     # Backend communication layer
│   └── index.js             # Canonical API module (article, category, delivery, entity, …)
├── automats/                # react-automat state modules (fine-grained subscriptions)
│   ├── artikelAutomat.js    # Article cache, deduplicated loads, and reactive single-article state
│   ├── authAutomat.js       # Authentication state, session bootstrap, company selection
│   ├── companyAutomat.js    # Active company config (tax rates, root category, legal details)
│   ├── categoryAutomat.js   # Hierarchical category tree, breadcrumbs, and category articles
│   ├── brandAutomat.js      # Catalog brands / manufacturer list
│   ├── unitAutomat.js       # Units of measure (Stück, kg, Liter, ...)
│   ├── posterminalAutomat.js # POS terminal config and enabled categories
│   ├── deliveryEditorAutomat.js # Multi-line delivery receipt / invoice editor & draft state
│   ├── navigationAutomat.js # Remembers active paths (last delivery path, last article SKU)
│   ├── supplierAutomat.js   # Supplier list and supplier-article catalogs
│   ├── userSettingsAutomat.js # User preferences (viewer positions, layout settings)
│   └── index.js             # Barrel exports for all automats and helper selectors
├── components/              # Shared UI components
│   ├── AppShell.jsx         # Main application frame (top bar, sidebar, nav buttons)
│   ├── SectionLayout.jsx    # Secondary navigation header for sections (/artikel, /lieferung...)
│   ├── AuthBootstrap.jsx    # Session bootstrapper, Google One Tap, company setup gate
│   ├── LoginPage.jsx        # Google One Tap / credentials login interface
│   ├── UserMenu.jsx         # User avatar, company switcher dropdown, logout action
│   ├── BackendError.jsx     # Graceful error banner for backend communication failures
│   ├── article/             # Article tiles, editors, dialogs, photos, price tiers
│   ├── category/            # Category navigation, dialogs, and picker components
│   ├── manifest/            # Manifest / delivery line inspection widgets
│   ├── settings/            # Terminal, unit, and brand settings dialogs
│   └── tiles/               # Tile components extending dashgui base Tile
├── devtools/                # Dev-only debug tools
│   └── AutomatInspector.jsx # Docked overlay inspecting all registered window.__AUTOMATS__
├── pages/                   # Top-level view routes
│   ├── artikel/             # Article index, category browser, warehouse, SKU detail editor
│   ├── lieferung/           # Delivery list, new delivery editor, supplier manager, edit page
│   ├── auftrag/             # Quotes (Angebote) and orders (Bestellungen)
│   ├── kunde/               # Customer list, new customer, customer groups, edit page
│   └── infos/               # System and company information page
├── theme/                   # MUI theme definitions (light/dark palette, typography, components)
├── utils/                   # Helpers (apiShape.js, number formatters, notify.js, etc.)
├── appRouter.jsx            # react-router-dom route definitions
├── nav.js                   # Navigation items (NAV_ITEMS, SUB_NAV, badges, active path matchers)
├── colors.js                # Shared color constants (MAIN_BACKGROUND)
├── main.jsx                 # React root mount, providers, dev SW unregistration
└── App.jsx                  # Main router provider wrapper

4. State Management Conventions

In dashfront, two state management solutions coexist harmoniously:

  • Skill references: Read .agents/skills/automat/SKILL.md and .agents/skills/coding-style/SKILL.md (names src/automats/brandAutomat.js as the reference automat).
  • Lives outside the React lifecycle in module scope (src/automats/*.js).
  • Designed for React PureComponent to bypass unnecessary React reconciliations.
  • Pattern:
    import { PureComponent } from 'react';
    import { artikelAutomat, createArticleSelector, getArticle } from '../automats';
    
    class ArticleView extends PureComponent {
      constructor(props) {
        super(props);
        // 1. Synchronous read in constructor — zero blank flash!
        this.state = {
          article: getArticle(props.sku),
        };
      }
    
      componentDidMount() {
        // 2. Subscribe with fine-grained selector
        this.unsub = artikelAutomat.subscribe(this, (state) => ({
          article: createArticleSelector(this.props.sku)(state),
        }));
      }
    
      componentWillUnmount() {
        // 3. Always unsubscribe
        this.unsub?.();
      }
    
      render() {
        const { article } = this.state;
        if (!article) return <div>Lädt...</div>;
        return <div>{article.name}</div>;
      }
    }
    

B. Configuration Automats (src/automats/)

  • Company, hierarchical category tree, brand, posterminal, and unit state live in dedicated automats (companyAutomat, categoryAutomat, brandAutomat, unitAutomat, posterminalAutomat).
  • Company-scoped lists (article index, deliveries, quotes, orders, entities, customer groups, number sequences) live in list automats built by createListAutomat.
  • Reads use the same fine-grained subscribe/selector pattern as the domain automats.
  • Cross-automat coordination is done by subscribing to authAutomat: when it reaches authed with a selectedCompanyId, these automats load themselves and reset on anon (see §10).

C. No React Context for Data (src/api has no context layer)

  • There is no store/context provider in this app. Components import the automat or src/api namespace they need directly. There is deliberately no static contextType for data access.
  • Call the API through the namespace functions (article.getBySku(...), delivery.list()), and keep shared/cached state in an automat.
  • Barrel exports live in src/automats/index.js; src/main.jsx imports it for its side effects so every store is registered before the session bootstraps.

5. Backend Communication & Authentication Rules

Authentication & Cookies

  1. HTTP-only cookie: The session token is stored in an HTTP-only cookie (token).
  2. credentials: 'include': Every fetch request MUST set credentials: 'include'. The http() helper in src/api/index.js does this automatically.
  3. Never pass googleAuthId: The frontend NEVER passes googleAuthId in request bodies or query parameters. The backend middleware extracts the authenticated user directly from the cookie session!
  4. Session Company: Multi-tenancy is scoped to the user's selected company. When a user switches companies (PUT /api/auth/selected-company), the backend updates the cookie session. All subsequent calls operate on that company.

API Entry Point

Import API namespaces from src/api:

import { article, category, delivery, supplier, entity, company } from '../api';

// Examples:
const { article: data } = await article.getBySku('SKU-1001');
const { deliveries } = await delivery.list();
const { suppliers } = await supplier.list();

6. Route & Navigation Architecture

  • Main navigation sections are defined in src/nav.js:
    • /artikel — Articles overview, SKU editor, Warehouse stock
    • /kategorien/* — Drag-and-drop category tree
    • /lieferung — Inbound deliveries, New delivery editor, Suppliers
    • /auftrag — Quotes (/auftrag) and Orders (/auftrag/bestellung)
    • /kunde — Customers, Customer groups
    • /infos — System settings & company info
  • Router Singleton:
    • Defined in src/appRouter.jsx.
    • Preserved across Vite HMR via import.meta.hot.data.router to prevent mid-session resets when hot-reloading code.
  • Dynamic Badges:
    • DeliveryNavIcon and DeliveryNeuIcon in src/nav.js subscribe to deliveryEditorAutomat to show live uncommitted draft line badges in real time.

7. Developer Workflows & Commands

Run commands from the repository root /home/seb/src/dashfront:

# Start Vite development server (proxies /api -> http://localhost:4208)
npm run dev

# Start development server with local HTTPS (uses certs/key.pem and certs/cert.pem)
npm run dev:https

# Run full PWA production build + preview (to test service worker / offline caching)
npm run dev:pwa

# Generate local self-signed TLS certificates
npm run cert

# Production build
npm run build

# Preview production build
npm run preview

# Regenerate Automat Graph visualization (automat-graph.svg & automat-graph.dot)
npm run automat-graph

Note

When testing camera-based barcode scanning or Progressive Web App features on mobile devices or local network IP addresses, start the server using npm run dev:https. Web browsers require a secure context (HTTPS) to grant access to media devices and service workers.


8. Critical Agent Rules & Common Pitfalls

  1. Do not create dummy/mock backends: dashback runs locally at http://localhost:4208. All /api/* routes are handled by it.
  2. Keep dashgui links working: dashgui is imported via file:../dashgui. Vite has deduplication configured (dedupe: ['react', 'react-dom', ...] in vite.config.js) to avoid dual-instance React conflicts.
  3. Article Deletion Restriction: An article CANNOT be deleted if it has child variants (is_parent: 1 or childCount > 0). The backend returns HTTP 400.
  4. Prices and Multipliers:
    • Article prices are tiered by minmultiplier and customergroup_id.
    • Prices sent to the backend are net prices (net).
  5. Binary / Image Handling:
    • Image uploads convert source images into AVIF variants client-side.
    • Frontend components use thumbhash for instant blur placeholders while loading full images via /api/image/{fullHash} or /api/thumb/{fullHash}.
  6. No Hooks in PureComponents: Never call React hooks (useState, useEffect) inside PureComponent classes. Automats provide direct reactive subscription without hooks.
  7. Always Unsubscribe: Every automat.subscribe(this, ...) in componentDidMount() must have its cleanup callback called in componentWillUnmount().

9. Deep Dive: The Automats (react-automat)

All domain Automats are located in src/automats/. Each automat exposes an observable state container with explicit action methods:

1. artikelAutomat (src/automats/artikelAutomat.js)

  • Role: Cache and reactive distributor for article detail payloads (GET /api/article/:sku).
  • Inflight Deduplication: Uses an internal Map<string, Promise<object>> so concurrent UI tiles or navigation transitions requesting the same SKU share a single HTTP call.
  • Key Actions:
    • loadArticle(sku): Fetches if missing, resolves immediately if cached.
    • reloadArticle(sku): Silently re-fetches to update cache (used on SSE mutation events).
    • setArticle(article): Updates cache after mutation responses.
    • setArticleName(sku, name): Optimistic immediate rename.
    • clearArticle(sku) / clear(): Invalidates cache.
  • Helper Selectors: getArticle(sku), hasArticle(sku), createArticleSelector(sku), selectArticle(sku).

2. authAutomat (src/automats/authAutomat.js)

  • Role: Manages user authentication lifecycle and multi-tenant company selection.
  • State: { user: AuthUser | null, googleClientId: string | null, status: 'loading' | 'anon' | 'authed' }.
  • Consumed by other automats: The company, category, brand, unit, and posterminal automats subscribe to authAutomat and (re)load or reset on its state changes. authAutomat also emits lifecycle events via the registered setAuthEventDispatcher:
    • auth/sessionEstablished
    • auth/companyChanged
    • auth/loggedOut
  • Actions: bootstrapSession(session), switchCompany(companyId), logout().

3. deliveryEditorAutomat (src/automats/deliveryEditorAutomat.js)

  • Role: State engine for the multi-line inbound delivery receiver and invoice reconciler (src/pages/lieferung/neu.jsx).
  • Features:
    • Line items editor (lines, createEmptyLineitem).
    • Supplier article auto-matching via buildSupplierArticlesMap(articles) indexing by supplier SKU, internal SKU, and EANs.
    • PDF/Receipt attachments parsing with OCR integration.
    • Reactive draft indicators (provides draft counts for badges in src/nav.js).

4. supplierAutomat (src/automats/supplierAutomat.js)

  • Role: Caches supplier directory list and maps articles to their corresponding supplier catalogs (GET /api/supplier).

5. navigationAutomat (src/automats/navigationAutomat.js)

  • Role: Remembers last active subpaths and last visited article SKU. When a user navigates between the main sidebar sections (e.g. from /lieferung to /artikel and back), it restores the exact active SKU or delivery document instead of resetting to the root list.

6. userSettingsAutomat (src/automats/userSettingsAutomat.js)

  • Role: Stores client-side user layout preferences such as viewer panel coordinates and drawer positions.

7. sseAutomat (src/automats/sseAutomat.js)

  • Role: Owns the single EventSource for /api/events and fans signals out into the domain automats. Reconnects whenever the selected company changes; disconnects on logout.
  • Built-in handlers: category → categoryAutomat.loadTree() + invalidateAllCategoryViews(); articles → articleIndexAutomat.reload() + category-view invalidation; warehouse → warehouseAutomat.reload(); attributename / propertyname → attributeAutomat.load() / propertyAutomat.load(); supplier → supplierAutomat.reload().
  • Extension API:
    • sseAutomat.actions.on(event, handler) — register a handler for a named backend event. Returns an unsubscribe callback. Handlers registered while disconnected attach on the next connect.
    • sseAutomat.actions.watchArticle(sku, handler) — subscribe to article-<sku> for one SKU. Exactly one listener is bound per SKU while at least one caller is subscribed; the listener resolves its handler set at call time, so an unwatched SKU is a no-op.
    • invalidateArticle(sku) — reloads the article plus its keyed history/supplier views. Background refreshes stay silent.

8. Company-Scoped List Automats

Built with the shared src/automats/createListAutomat.js factory, which follows the brand/unit/warehouse pattern (status: idle | loading | ready | failed):

Automat Backs
articleIndexAutomat Article search index (GET /api/articleIndex), mapped to the recordset shape; also patched optimistically on rename
deliveryAutomat Delivery list
quoteAutomat / orderAutomat Quote / order lists
entityAutomat / customergroupAutomat Customer list and customer groups
numberAutomat Document number sequences

Each exposes load() (deduplicated), reload() (silent), replace(), ensureLoaded(), and reset(). They subscribe to authAutomat, so they load on authed with a selectedCompanyId and reset to idle on anon.

9. articleSearchAutomat (src/automats/articleSearchAutomat.js)

  • Role: Client-side search over the cached article index for the /artikel overview. search(target) returns { categoryFacets, totalCount, recordset, error }; the page subscribes to result instead of receiving a callback.

10. articleDetailAutomat (src/automats/articleDetailAutomat.js)

  • Role: Two KeyedAutomat stores keyed by SKU — articleHistoryAutomat (GET /api/article/{sku}/history, paginated client-side) and articleSupplierAutomat (GET /api/article/{sku}/supplier). Both reload automatically when sseAutomat reports an article-<sku> signal.

10. Deep Dive: Configuration Automats (Company, Category, Brand, Unit & POS Terminals)

The remaining static/relational/configuration state is also managed by react-automat. These automats live alongside the domain automats in src/automats/ and follow the same subscribe/selector pattern:

  1. companyAutomat (src/automats/companyAutomat.js): Active company configuration, tax rates (standard, reduced), root category ID, company legal details. Selectors: selectCompanyTaxrate(), selectCompanyReducedTaxrate(), selectCompanyRootCategoryId(), selectCompanyName(), …
  2. categoryAutomat (src/automats/categoryAutomat.js): Hierarchical category tree (id → node map), breadcrumbs, category navigation, article lists per category, and category/article mutations (createCategory, createArticle, deleteCategory, moveCategory).
  3. brandAutomat (src/automats/brandAutomat.js): Catalog brands / manufacturer list (load, upsert).
  4. posterminalAutomat (src/automats/posterminalAutomat.js): Registered point-of-sale hardware terminals and their enabled categories.
  5. unitAutomat (src/automats/unitAutomat.js): Allowed units of measure (Stück, kg, Liter, etc.).

Automatic Bootstrap via authAutomat Subscriptions

Each of these automats subscribes directly to authAutomat at module load and coordinates its own loading:

// e.g. src/automats/companyAutomat.js
authAutomat.subscribe((auth) => {
  const companyId = auth.user?.selectedCompanyId;
  if (auth.status === 'authed' && companyId) {
    void companyAutomat.actions.load();
  } else if (auth.status === 'anon') {
    companyAutomat.actions.reset();
  }
});

When the auth state becomes authed with a selectedCompanyId (on session bootstrap, login, or company switch), the company, brand, unit, and posterminal automats load automatically; on logout/anon they reset. categoryAutomat.loadTree() then reads the company's rootCategoryId from companyAutomat.

Automatic Debugging

All automats are observable in the AutomatInspector, which lists every automat registered in window.__AUTOMATS__ with live state, subscriber counts, and actions.


11. dashgui Component Library Integration

dashgui is a shared, high-performance UI library linked from file:../dashgui:

Core Components

  • PanelTile: Structured card container featuring standard header styling, action slots, collapsible state, and clean borders.
  • RecordList: High-performance list component optimized for large dataset rendering with custom row click, hover, and selection handlers.
  • Tile: Base container element for building responsive dashboard grids.
  • SingleLineTextEdit: Inline editable text field with debounced autosave, blur commit, and escape rollback.
  • ElevatedPill: Compact visual badges for status, tags, and category chips.

React 19 & Deduplication Warning

Because dashgui is symlinked from ../dashgui, it has its own node_modules. To prevent duplicate React, Emotion, or MUI instances from causing runtime context errors (Cannot read properties of null (reading 'useContext')), vite.config.js enforces dedupe:

resolve: {
  dedupe: [
    'react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime',
    'react-router', 'react-router-dom', '@emotion/react', '@emotion/styled',
    '@mui/material', '@mui/icons-material'
  ]
}

12. Application Views & Route Hierarchy

The application routing is defined in src/appRouter.jsx and styled with src/components/AppShell.jsx:

/
├── /artikel
│   ├── index              → ArtikelUebersichtPage (Search & filter grid)
│   ├── /kategorien/*      → ArtikelKategorienPage (Interactive category tree)
│   ├── /lager             → ArtikelLagerPage (Warehouse stock overview)
│   └── /:sku/:tab?        → ArtikelSkuPage (SKU detail: info, photos, prices, suppliers, warehouse)
├── /lieferung
│   ├── index              → LieferungListePage (Inbound delivery list)
│   ├── /neu               → LieferungNeuPage (Receipt editor & OCR reconciliation)
│   ├── /lieferanten       → LieferungLieferantenPage (Supplier directory)
│   └── /:deliveryId       → LieferungEditPage (Delivery inspection & editing)
├── /auftrag
│   ├── index              → AuftragAngebotPage (Quotes / Angebote)
│   ├── /neu               → AuftragAngebotNeuPage (Create quote)
│   ├── /:quoteId          → AuftragAngebotEditPage (Edit quote)
│   ├── /bestellung        → AuftragBestellungPage (Orders / Bestellungen)
│   ├── /bestellung/neu    → AuftragBestellungNeuPage (Create order)
│   └── /bestellung/:id    → AuftragBestellungEditPage (Edit order)
├── /kunde
│   ├── index              → KundeListePage (Customer directory)
│   ├── /neu               → KundeNeuPage (Create customer)
│   ├── /gruppen           → KundeGruppenPage (Customer groups & price tiers)
│   └── /:entityId         → KundeEditPage (Customer profile & address editor)
└── /infos                 → InfosPage (Company information & POS setup)

13. Media, Images & Document Pipelines

Client-Side AVIF Conversion

To minimize backend CPU usage and reduce bandwidth:

  • When a user selects or drops an article photo, the frontend processes the image in-browser using @jsquash/avif and @jsquash/resize.
  • Images are scaled to target variant dimensions and compressed into AVIF format before transmission to /api/article/:sku/photo.

ThumbHash Placeholders

  • For instant visual feedback without layout shift, article photos generate a 25-byte binary hash using thumbhash.
  • src/components/article/ThumbHashImage.jsx renders the blur preview instantly while the full image loads asynchronously from /api/thumb/{hash} or /api/image/{hash}.

PDF & Document Ingestion

  • src/pages/lieferung/neu.jsx utilizes pdfconvert-wasm to process supplier PDF delivery notes and invoices directly inside the browser.
  • Extracted pages are rendered to canvas, displayed for line-by-line inspection, and passed to OCR recognition to populate delivery line items.

14. Real-time SSE Signals & Invalidation

The frontend connects to the backend Server-Sent Events stream at /api/events:

  • Architecture: When mutations occur on dashback (whether triggered by this client, another terminal, or the POS), SSE events are broadcast with payload information (e.g. { type: 'article-update', sku: '1001' }).
  • Reactive Cache Refresh:
    • artikelAutomat.actions.reloadArticle(sku) re-fetches the updated article silently, updating subscribers without flicker.
    • Category updates trigger categoryAutomat tree/article reloads.
    • Delivery and order updates trigger automatic list reloads.

15. Developer Tooling & Debugging

AutomatInspector (src/devtools/AutomatInspector.jsx)

  • Docked overlay on the right side of the screen, active only in development mode (import.meta.env.DEV).
  • Auto-discovers all running automats registered in window.__AUTOMATS__.
  • Allows developers and agents to:
    • Inspect full state JSON trees in real time.
    • View subscriber counts and registered actions.
    • Trigger actions and test state changes without code modifications.

Vite API Proxy Logging

vite.config.js includes automatic proxy logging for all /api requests and responses. HTTP method, path, request payloads, response statuses, and timing are formatted directly in the Vite terminal.

TLS / HTTPS Development

For testing hardware barcode scanners, camera video feeds, and PWA offline modes:

npm run cert       # Generates local certs in ./certs/
npm run dev:https  # Runs Vite HTTPS server on port 4308

Automat Graph Visualization (automat-graph.svg & automat-graph.dot)

  • Visual topology diagram generated via npm run automat-graph (generate-automat-graph.js).
  • Modeled after schema-graph.svg in dashdbschema and api-graph.svg in dashback.
  • Visualizes 32 Automats across 12 domain clusters (Session & Real-Time, Catalog, Search, Properties, Purchasing, Sales, Inventory, Finance, POS, AI Workspace, Virtual Grids, System UI).
  • Color-coded badges for STATE (purple), ACTION (green), SELECT (blue), API (amber), SSE (rose), and HOOK (orange).
  • Traces 60 relational and dataflow links with dedicated arrival ports (in#), exit compass directions (e/w), and arc-fixed self-loops.

16. Agent Cheatsheet & Code Recipes

Recipe 1: Consuming an Automat in a React PureComponent

import { PureComponent } from 'react';
import { artikelAutomat, createArticleSelector, getArticle } from '../automats';

export class ArticleTitle extends PureComponent {
  constructor(props) {
    super(props);
    // 1. Read synchronously to avoid blank flash
    this.state = {
      article: getArticle(props.sku),
    };
  }

  componentDidMount() {
    // 2. Subscribe with fine-grained selector
    this.unsub = artikelAutomat.subscribe(this, (state) => ({
      article: createArticleSelector(this.props.sku)(state),
    }));
  }

  componentDidUpdate(prevProps) {
    // 3. Handle prop changes cleanly
    if (prevProps.sku !== this.props.sku) {
      this.setState({ article: getArticle(this.props.sku) });
      this.unsub?.();
      this.unsub = artikelAutomat.subscribe(this, (state) => ({
        article: createArticleSelector(this.props.sku)(state),
      }));
    }
  }

  componentWillUnmount() {
    // 4. Always cleanup
    this.unsub?.();
  }

  render() {
    const { article } = this.state;
    return <h1>{article?.name ?? 'Lädt...'}</h1>;
  }
}

Recipe 2: Calling the API and Notifying Errors

import { article } from '../api';
import { enqueueSnackbar } from 'notistack';
import { notifyError } from '../utils/notify';
import { artikelAutomat } from '../automats';

async function handleSavePrice(sku, netPrice) {
  try {
    const res = await article.updatePrice(sku, { net: netPrice });
    artikelAutomat.actions.setArticle(res.article);
    enqueueSnackbar('Preis erfolgreich aktualisiert', { variant: 'success' });
  } catch (err) {
    notifyError(err);
  }
}

Recipe 3: Calculating Gross Prices with Company Tax Rates

// Prices in the database and API are NET prices.
// Gross prices shown to end users must apply company tax rates from companyAutomat
// (selectCompanyTaxrate() / selectCompanyReducedTaxrate()):
export function calculateGrossPrice(netPrice, taxRatePercent) {
  const net = Number(netPrice) || 0;
  const rate = Number(taxRatePercent) || 0;
  return Math.round(net * (1 + rate / 100) * 100) / 100;
}