Token导航 LogoToken导航TokenDH.com
待分类external-servicegithub未标认证来源可访问许可证需确认审计提醒

microtech-graphqlmicrotech GraphQL 文档

Agent Skill

用于辅助 API 设计、接口文档、请求响应结构和服务集成说明。它适合让 Agent 梳理 endpoint、生成 OpenAPI 草稿、检查字段命名、整理错误码或辅助前后端联调。使用时需要确认真实业务语义、鉴权方式、分页和错误处理规则;涉及生成接口文档时,应避免凭空补字段,最好从现有代码、schema 或接口样例中提取事实。

总安装

504

周安装

21

GitHub Stars

4

下载量

168
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:microtech-graphql(microtech GraphQL 文档)
来源仓库:https://github.com/microtech-gmbh/microtech-skills
仓库路径:skills/microtech-graphql
安装命令:
npx skills add https://github.com/microtech-gmbh/microtech-skills --skill microtech-graphql
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/microtech-gmbh/microtech-skills --skill microtech-graphql

简介

用于 GraphQL API 设计与集成说明辅助。

  • 适合梳理 endpoint、生成 OpenAPI 草稿或检查字段命名。
  • 通过 GitHub 安装,需结合现有 schema 和业务语义使用。
  • 生成接口文档时应避免凭空补字段,优先提取真实样例。
  • microtech-graphql 属于待分类类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

microtech GraphQL - Skill-Referenz

Kompakte Referenz fuer die GraphQL-Schnittstelle des microtech ERP. Optimiert fuer Query-Generierung ueber einen MCP-Server mit graphql_query-Tool.

ASCII: Dieses Dokument verwendet ae/oe/ue/ss statt Umlaute.
WICHTIG - Introspection: NIEMALS das vollstaendige Schema abrufen (__schema). Stattdessen gezielt einzelne Typen abfragen. Siehe references/introspection-guide.md.
Feldkataloge: Fuer detaillierte Feldlisten pro Tabelle siehe references/feldkatalog-*.md.
Erweiterte Themen: Fuer Archiv-Funktionen, externe Bearbeitung, Berechtigungen, Cross-Table-Patterns siehe references/vorgaenge-erweitert.md.
Mutation-Patterns: Fuer Optimistic Locking, rowCopy, ifNotExists, Deep Nesting, Massenoperationen siehe references/mutation-patterns.md.
Query-Patterns: Fuer keyFilter-Details, Arithmetik, skip-Wert, erweitertes @onNull, Schema-Metadaten siehe references/erweiterte-query-patterns.md.
Adressen-Verwaltung: Praxisbeispiele fuer Adressen, Anschriften und Ansprechpartner (lesen, anlegen, aendern, loeschen) mit verschachtelten Links, Optimistic Locking, rowCopy, Massenoperationen und assign-Parametern in references/adressen-verwaltung.md. Bei Adress-Aufgaben dort zuerst nachschlagen!
Parametertabellen: Konfigurations- und Parametertabellen auslesen (Vorgangsarten, Zahlungsbedingungen, Steuerschluessel, Einheiten, Versandarten, Waehrungen, Mahnstufen, Projektstatus u.v.m.) in references/parametertabellen.md. Bei Fragen zur mandantenspezifischen Konfiguration dort nachschlagen!
Workflow-Beispiele: 17 vollstaendige Szenarien (Rechnung erstellen, Vorgang wandeln, Storno, Lagerbestand u.v.m.) in references/workflow-beispiele.md. Bei komplexen Aufgaben dort zuerst nachschlagen!

Kritische Regeln (Top 9)

  1. keyFilter-First: Bei JEDEM Filter zuerst pruefen, ob ein passender by...-Index existiert und keyFilter verwenden. Erst wenn kein passender Index vorhanden ist, auf fastFilter oder slowFilter zurueckfallen. Siehe Abschnitt 5 fuer den verbindlichen Workflow.
  2. @oneOf-Regel: Pro Filterobjekt nur EIN Operator. Mehrere Bedingungen mit and/or kombinieren.
  3. fnPost/fnReverse/fnConvert nur in rowRead-Kontext (nicht rowModify!), immer in mutation.
  4. rowSave vor fnPost - ohne rowSave sind Positionen nicht gespeichert und werden nicht gebucht.
  5. Nach rowSave nicht mehr schreiben im selben Block - fuehrt zu Laufzeitfehler und Rollback.
  6. Leere Belegnummer = Operation fehlgeschlagen - immer fldBelegNr in fn...-Rueckgaben pruefen.
  7. Prozessketten-Integritaet - NIEMALS fn-Funktionen durch manuelle Operationen ersetzen! ERP-Prozessfunktionen (fnPost, fnReverse, fnConvert, fnMoveToArchive) sind die EINZIGE korrekte Art, den Belegstatus zu veraendern. Sie sichern die Prozesskette (z.B. Angebot → AB → Lieferschein → Rechnung), verknuepfen Belege, aktualisieren Lagerbestaende, erzeugen Buchungssaetze und fuehren Plausibilitaetspruefungen durch. Wenn eine fn-Funktion fehlschlaegt, STOPPEN und den Nutzer informieren - KEINEN Workaround versuchen.
  8. NIEMALS rowNew als Ersatz fuer fnConvert - ein manuell angelegter Folgebeleg hat KEINE Verknuepfung zum Vorgaenger. Die Prozesskette ist unterbrochen, Mengen werden nicht korrekt gefuehrt, Lieferstatus wird nicht aktualisiert. Stattdessen: Fehlerursache klaeren (Wandlungspfad nicht konfiguriert, Beleg bereits archiviert, etc.) und Nutzer fragen.
  9. NIEMALS rowDelete als Ersatz fuer fnReverse - eine Loesung per rowDelete umgeht die Storno-Logik: keine Storno-Belegnummer, keine Gegenbuchungen, keine Lagerkorrektur, kein Audit-Trail. Stattdessen: fnReverse verwenden, bei Fehler Nutzer informieren.

Arbeitsweise: So bearbeitest du Nutzeranfragen

Schritt 1: Anfrage klassifizieren

  • Lesen/Suchenquery (Daten anzeigen, suchen, auflisten, zaehlen)
  • Schreiben/Aendernmutation (anlegen, aendern, loeschen, buchen, wandeln)
  • Unbekannte Felder/Tabelle → Erst Introspection (references/introspection-guide.md)
Source of Truth: Bei Unsicherheit ueber Feldnamen, Schreibbarkeit oder verfuegbare Operationen IMMER die Live-API per Introspection pruefen. Dokumentierte Feldlisten koennen veraltet sein - die API ist die einzig zuverlaessige Quelle.

Schritt 2: Tabelle identifizieren

  • Nutze die Tabelle aus "Schnellreferenz" unten
  • Bei Unsicherheit: Introspection oder Nutzer fragen

Schritt 3: Reference-Dateien konsultieren

BEVOR du eine Query oder Mutation baust: Pruefe ob ein passendes Beispiel oder Detail-Wissen existiert.

  • Komplexe Aufgabe? → Zuerst references/workflow-beispiele.md durchsuchen (17 Szenarien)
  • Feldnamen unklar? → Passenden references/feldkatalog-*.md lesen
  • Filter-Logik?references/erweiterte-query-patterns.md (keyFilter, Arithmetik, Datums-Filter)
  • Adressen/Anschriften/Ansprechpartner?references/adressen-verwaltung.md (verschachtelte Links, rowReAnsNr, assign-Parameter, Massenoperationen)
  • Mutation-Pattern?references/mutation-patterns.md (Optimistic Locking, rowCopy, Deep Nesting)
  • Vorgangsfunktionen?references/vorgaenge-erweitert.md (Archiv, externe Bearbeitung)
  • Parametertabellen/Konfiguration?references/parametertabellen.md (Vorgangsarten, Steuerschluessel, Zahlungsbedingungen, Einheiten, Versandarten, Waehrungen, Mahnstufen, Projektstatus, Dokumentenarten u.v.m.)
  • Introspection noetig?references/introspection-guide.md (Typ-Namenskonventionen)
Nicht raten - nachschlagen! Die Reference-Dateien enthalten getestete, korrekte Beispiele. Lieber 30 Sekunden lesen als eine fehlerhafte Query bauen.

Schritt 4a: Query bauen (Lesen)

  1. Filter-Strategie (keyFilter-First!):

- Gibt es einen by...-Index fuer das Suchfeld? → keyFilter verwenden - Kein Index? → fastFilter (einfache Gleichheit auf fld...) - Komplex? → slowFilter (Arithmetik, in, fn...)

  1. Query mit graphql_query-Tool ausfuehren
  2. Ergebnis dem Nutzer verstaendlich praesentieren

Schritt 4b: Mutation bauen (Schreiben)

  1. Operation waehlen:

- Neuer Datensatz → rowNew (ggf. mit assignAddress/assignProduct) - Aendern → rowModify - Buchen/Stornieren/Wandeln → rowRead + fnPost/fnReverse/fnConvert - Loeschen → rowDelete (aber NICHT als Ersatz fuer fnReverse!)

  1. @acquireLocks pruefen: Bei Multi-Tabellen-Mutations immer angeben
  2. Speicher-Strategie: rowSave vs. rowSaveAndModify - bei Vorgaengen mit Positionen immer rowSaveAndModify + inneres rowSave vor fnPost
  3. Mutation ausfuehren und Ergebnis pruefen (leere Belegnummer = fehlgeschlagen!)

Schritt 5: Ergebnis verifizieren

  • Query: Kamen Daten zurueck? Paginierung noetig (hasNextPage)?
  • Mutation: fldBelegNr pruefen - leer bedeutet die Operation ist fehlgeschlagen
  • Fehler: Abschnitt "Troubleshooting" pruefen, Nutzer informieren
  • Nie stillschweigend Fehler ignorieren - immer dem Nutzer mitteilen was passiert ist

Typische Nutzer-Szenarien

Nutzer sagt...Du machst...
"Zeig mir Artikel X"querytblProductsrowRead mit keyFilter
"Alle Kunden aus PLZ 5xxxx"querytblAddresseslnkPostalAddresses → slowFilter auf fldPLZ
"Erstell eine Rechnung fuer Kunde 10000"mutation mit @acquireLockstblTransactionsrowNew + rowSave + fnPost
"Wandle Angebot 12345 in AB"mutationtblTransactionsrowRead + fnConvert
"Wieviele Artikel haben wir?"querytblProductsconRead(first: 100) → paginieren + hasNextPage
"Storniere Rechnung 67890"mutationtblTransactionsrowRead + fnReverse
"Zeig mir Adresse 10000 mit Anschriften und Ansprechpartnern"querytblAddresseslnkPostalAddresseslnkContactPeople → siehe references/adressen-verwaltung.md
"Leg einen neuen Kunden / Lieferanten / Interesenten an mit Anschrift und Ansprechpartner"mutation → verschachtelt: rowNew + rowSave + lnkPostalAddresses + lnkContactPeople → siehe references/adressen-verwaltung.md
"Welche Vorgangsarten gibt es?"querytblTransactionTypesrowsRead → siehe references/parametertabellen.md
"Welche Zahlungsbedingungen sind konfiguriert?"querytblPaymentTermsrowsRead → siehe references/parametertabellen.md
"Zeig mir die Steuerschluessel"querytblValueAddedTaxTypesrowsRead → siehe references/parametertabellen.md
"Welche Einheiten/Waehrungen gibt es?"querytblUnitsOfMeasure/tblCurrencies → siehe references/parametertabellen.md

Schnellreferenz

Wichtigste Tabellen

GraphQL-TabelleBeschreibungSchreibbar
tblAddressesAdressenja
tblPostalAddressesAnschriftenja
tblContactPeopleAnsprechpartnerja
tblContactsKontakteja
tblProductsArtikelja
tblProductGroupsWarengruppenja
tblSuppliersArtikel-Lieferantenja
tblTransactionsVorgaengeja
tblTransactionItemsVorgangspositionenja (verschachtelt in tblTransactions)
tblTransactionsArchiveArchiv Vorgaengeja
tblProjectsProjekteja
tblDocumentsDokumenteja
tblCalendarKalenderja
tblWarehousesLagerja
tblClientMandant (Einzeldatensatz)ja
tblOpenItemsOffene Postennein
tblInventoryLagerbestaendenein
tblUsersBenutzernein
Parametertabellen
tblTransactionTypesVorgangsarten (Wandlungskette, Buchungsparameter)nein
tblPostingParametersBuchungsparameternein
tblUnitsOfMeasureMengeneinheiten (UN/ECE-Codes fuer E-Rechnung)nein
tblValueAddedTaxTypesSteuerschluessel mit Saetzen und DATEV-Zuordnungnein
tblPaymentTermsZahlungsbedingungennein
tblCurrenciesFremdwaehrungen mit Wechselkursennein
tblShippingTypesVersandartennein
tblAddressStatusesAdressstatus mit Nummernkreisennein
tblSalutationsAnredennein
tblDunningLevelsMahnstufennein
tblPaymentMethodsZahlungsartennein
tblProjectTypesProjektartennein
tblProjectStatesProjektstatus (Workflow)nein
tblDocumentTypesDokumentenarten (DMS)nein
tblDocumentStatesDokumentenstatus (Workflow)nein
tblCommunicationTypesKommunikationsartennein

Haeufigste Patterns (Copy-Paste-fertig)

# LESEN - Einzelner Datensatz
query { tblProducts { rowRead(kf1ArtNr: { string: "LUTSCHER" }) { fldArtNr fldSuchBeg fldBez1(as: DISPLAY_TEXT) } } }

# LESEN - Liste mit Filter
query { tblProducts { rowsRead(slowFilter: { gt: [{field: fldVk0_Preis}, {value: 0}] }) { fldArtNr fldVk0_Preis(as: TEXT) } } }

# LESEN - Paginiert
query ($after: String) { tblProducts { conRead(first: 10, after: $after) { edges { node { fldArtNr } cursor } pageInfo { hasNextPage endCursor } } } }

# SCHREIBEN - Neuer Datensatz
mutation { tblProducts { rowNew { fldArtNr(set: { string: "NEU-001" }) fldBez1(set: { text: "Bezeichnung" } as: DISPLAY_TEXT) } } }

# SCHREIBEN - Datensatz aendern
mutation { tblProducts { rowModify(kf1ArtNr: { string: "LUTSCHER" }) { fldBez1(set: { text: "Neuer Name" } as: DISPLAY_TEXT) } } }

# SCHREIBEN - Vorgang anlegen + buchen
mutation @acquireLocks(forWriting: [tblTransactions, tblTransactionItems], forReading: [tblAddresses, tblProducts]) {
  tblTransactions {
    rowNew(assignAddress: { kf1AdrNr: { text: "10000" } }) {
      fldArt(set: { text: "Rechnung I" })
      rowSaveAndModify {
        fldBelegNr
        tblTransactionItems {
          rowNew(assignProduct: { kf1ArtNr: { text: "LUTSCHER" } }) { fldMge(set: { float: 10 }) }
        }
        rowSave { fnPost { fldBelegNr } }   # rowSave VOR fnPost!
      }
    }
  }
}

1. Grundstruktur

Tabellenzugriff

Alle Operationen beginnen mit tbl... auf oberster Ebene:

query {
  tblProducts { ... }       # Artikel
  tblAddresses { ... }      # Adressen
  tblTransactions { ... }   # Vorgaenge
}

Leseoperationen

FeldBeschreibungRueckgabe
rowRead(...)Einzelnen Datensatz lesenRow oder null
rowsRead(...)Liste lesen[Row]
conRead(...)Paginierte Liste (Relay Connection)Connection

Einzeldatensatz-Tabellen

tblClient braucht keine Suchparameter:

query { tblClient { rowRead { fldMandNr fldMandTyp } } }

2. Datensatzauswahl

exactMatch - Exakte Suche

rowRead(exactMatch: { byNr: { kf1ArtNr: { string: "PROD-001" } } })

Verschachtelte Schluesselfelder

rowRead(exactMatch: {
  byArtNrLagNr: {
    kf1ArtNr: { string: "LUTSCHER"
      kf2LagNr: { string: "HAUPT" }
    }
  }
})

Verkuerzte Schreibweisen

# Statt:
rowRead(exactMatch: { byNr: { kf1ArtNr: { string: "LUTSCHER" } } })
# Kurz (impliziert exactMatch + byNr):
rowRead(kf1ArtNr: { string: "LUTSCHER" })

# Bereich:
rowsRead(kf1ArtNr: { from: { string: "0" }, to: { string: "12000" } })

Weitere Sucharten

# Naechster Treffer
rowRead(nearestMatch: { byNr: { kf1ArtNr: { string: "PROD-000" } } })

# Aktueller Benutzer
tblUsers { rowRead(using: current) { fldAnmNa } }

# Bereich mit exklusiver Obergrenze
rowsRead(allBetween: { byNr: { kf1ArtNr: { from: { string: "A" }, to: { string: "Z" }, toExclusive: true } } })

3. Datenfelder und Ausgabeformate

Praefix-System

PraefixBedeutungBeispiel
tbl...TabelletblProducts
fld...DatenfeldfldArtNr, fldPreis
kf...Schluesselfeldkf1ArtNr, kf2LagNr
by...SortierfolgebyNr, bySuchBeg
row...Verweis auf verknuepften DatensatzrowWgrNr
lnk...Verlinkung zu DatentabellelnkInventory
aco...BetragsgruppeacoEPr, acoGPreis
img...BildfeldimgBild
fn...FunktionfnPost, fnIsCustomer
_...System-Feld_if, _string

as-Parameter - Ausgabeformat

fldPreis                    # Standardformat
fldPreis(as: TEXT)          # "99,95 EUR" (lokalisiert)
fldPreis(as: FLOAT)         # 99.95
fldPreis(as: STRING)        # Roher String
fldPreis(as: INT)           # Ganzzahl
fldPreis(as: DISPLAY_TEXT)  # Anzeigeformat (auch fuer RTF-Felder → Klartext)
fldGueltigAb(as: TEXT)      # "24.12.2023" (lokalisiert)
fldGspKz(as: BOOLEAN)       # true/false

Gemeinsame Felder (in fast allen Tabellen)

# Identifikation
fldID                       # Automatische ID
fldModifyLSN / fldInsertLSN # Versionierung (BigInt)

# Audit-Trail
fldErstDat / fldErstBzr     # Erstellungsdatum / -benutzer
fldAendDat / fldAendBzr     # Aenderungsdatum / -benutzer

# Sperren
fldGspKz                    # Gesperrt-Kennzeichen (Boolean)
fldGspDat / fldGspInfo      # Sperrdatum / -information
fldGspGrp                   # Gesperrtgruppe

# Freitext
fldInfo                     # Informationsfeld
fldMemo                     # Memo-Feld
fldQuickInfo                # QuickInfo

4. Verknuepfungen

Verweise (row...) - Einzelner verknuepfter Datensatz

tblProducts {
  rowsRead {
    fldArtNr
    fldWgrNr                  # Fremdschluessel-Wert
    rowWgrNr { fldBez }       # Verknuepfte Warengruppe
    rowEinh { fldKuBez }      # Verknuepfte Einheit
  }
}

Verlinkungen (lnk...) - Liste verknuepfter Datensaetze

WICHTIG: by.../using... gehoeren auf rowsRead INNERHALB des Links, NICHT auf lnk...:

# RICHTIG:
lnkInventory {
  rowsRead(byArtNrLagNrArtBDat: { usingArtNr: {} }) { fldLagNr fldMge }
}

# FALSCH:
lnkInventory(byArtNrLagNrArtBDat: { usingArtNr: {} }) {
  rowsRead { ... }
}

Verschachtelte Tabellen (tbl... innerhalb Row)

tblClient {
  rowRead {
    fldMandNr
    tblBnkVb { rowsRead { fldNr fldIBAN } }
  }
}

5. Filter

VERBINDLICHER WORKFLOW: keyFilter-First

BEVOR du einen Filter schreibst, fuehre IMMER diese Schritte aus:

  1. Sortierfolgen ermitteln: Pruefe per Introspection, welche by...-Sortierfolgen die Tabelle hat: {__type(name: "{SingularName}SlowAnyFields") {enumValues {name}}} WICHTIG: Der Enum-Name verwendet den Singular-Namen der Entitaet, NICHT den Tabellennamen! Beispiele: ProductSlowAnyFields, TransactionSlowAnyFields, AddressSlowAnyFields. Sonderfaelle: CalendarEntrySlowAnyFields, AccountSlowAnyFields, BillOfMaterialsEntrySlowAnyFields, InventoryEntrySlowAnyFields. Gleiches Muster gilt fuer {SingularName}FastAnyFields. Die by...-Parameter findest du auf den rowsRead/conRead-Argumenten. Alternativ: Probiere rowsRead(allBetween: {by und schau welche Vorschlaege die API akzeptiert.
  2. keyFilter pruefen: Gibt es eine by...-Sortierfolge, die das gewuenschte Filterfeld als kf...-Schluessel enthaelt? → keyFilter verwenden! # Beispiel: Laender ohne Staatsangehoerigkeitsnummer # byStaatsNr existiert mit kf1StaatsNr → keyFilter nutzen! rowsRead(allBetween: {byStaatsNr: {keyFilter: {isNull: {field: kf1StaatsNr}}}})
  3. Fallback: Nur wenn KEIN passender by...-Index existiert:

- fastFilter fuer einfache Vergleiche auf fld...-Felder - slowFilter NUR fuer Arithmetik, in-Operator, fn...-Funktionen

NIEMALS direkt slowFilter verwenden, ohne vorher keyFilter geprueft zu haben!

Drei Filtertypen

FilterPerformanceBesonderheiten
keyFilterAm schnellstenFilter auf kf...-Felder innerhalb by... - IMMER bevorzugen!
fastFilterSchnell (DB-seitig)Nur einfache Vergleiche auf fld...
slowFilterLangsam (App-seitig)Arithmetik, in-Operator, fn... - nur als letzter Ausweg

Vergleichsoperatoren

{ eq: [{field: fldStatus}, {value: 1}] }       # gleich
{ ne: [{field: fldStatus}, {value: 0}] }       # ungleich
{ gt: [{field: fldMge}, {value: 0}] }          # groesser
{ lt: [{field: fldMge}, {value: 100}] }        # kleiner
{ ge: [{field: fldMge}, {value: 1}] }          # groesser-gleich
{ le: [{field: fldMge}, {value: 99}] }         # kleiner-gleich
{ isNull: { field: fldAuftrNr } }              # NULL-Pruefung
{ isNotNull: { field: fldAuftrNr } }

Boolesche Kombinationen

{ and: [Ausdruck1, Ausdruck2] }
{ or:  [Ausdruck1, Ausdruck2] }
{ not: Ausdruck }

WICHTIG: @oneOf-Regel

Pro Filterobjekt nur EIN Operator:

# FALSCH:
fastFilter: { eq: [...], gt: [...] }

# RICHTIG:
fastFilter: { and: [ { eq: [...] }, { gt: [...] } ] }

IN-Operator (nur slowFilter)

{ in: { left: { field: fldLagBestArt }, list: [1, 7] } }

Alle Werte muessen denselben Typ haben (@sametype-Regel).

keyFilter - Performantester Filter

Filtert auf kf...-Felder INNERHALB des by...-Parameters. Schneller als fast/slowFilter.

# Alle Artikel ab Nummer "10"
rowsRead(
  allBetween: {
    byNr: {
      keyFilter: { ge: [{ field: kf1ArtNr }, { value: "10" }] }
      kf1ArtNr: { from: { string: "0" }, to: { string: "ZZZZZ" } }
    }
  }
)

# Mehrere Werte per OR
keyFilter: {
  or: [
    { eq: [{ field: kf1AdrNr }, { value: "10000" }] }
    { eq: [{ field: kf1AdrNr }, { value: "70000" }] }
  ]
}

Prioritaet: keyFilter > fastFilter > slowFilter (immer schnellsten moegl. Typ waehlen).

Detaillierte keyFilter-Patterns siehe references/erweiterte-query-patterns.md.

Funktionen in Filtern (nur slowFilter)

{ fnPos: [{ value: "Suchtext" }, { field: fldSuchBeg }] }   # Textsuche (>0 = gefunden, NUR String-Felder!)
{ fnGetAktDate: [] }                                      # Aktuelles Datum
{ fnIncDate: [{ fnGetAktDate: [] }, { value: 0 }, { value: -12 }] }  # Datum +/- Monate

Arithmetik in slowFilter

# Brutto > 100 pruefen
slowFilter: { gt: [{ mul: [{ field: fldVk0_Preis }, { value: 1.19 }] }, { value: 100 }] }

Operatoren: add, sub, mul, div, mod, neg. Details in references/erweiterte-query-patterns.md.


6. Direktiven

@store - Wert in Variable speichern

Variable muss in der Operations-Signatur deklariert werden:

query ($storedValue: Any = null) {
  tblProducts {
    rowsRead {
      fldSuchBeg @store(in: $storedValue)
      echo: _any(value: $storedValue)
    }
  }
}

@store funktioniert ueber Verschachtelungsebenen hinweg (aeussere Tabelle → verschachtelte tbl/lnk).

@onNull - Null-Behandlung

fldSuchBeg @onNull(returnValue: "Nicht gefunden")     # Alternativwert
fldPreis @onNull(returnValue: skip)                    # Feld ueberspringen
fldArtNr @onNull(errorMessage: "ArtNr fehlt")          # Fehler ausloesen

@acquireLocks - Praventive Sperren (nur mutation)

mutation @acquireLocks(
  forWriting: [tblTransactions, tblTransactionItems],
  forReading: [tblAddresses, tblProducts]
) { ... }

Verhindert Deadlocks bei Multi-Tabellen-Mutationen.

@skip / @include

fldPreis @include(if: $includePrice)

7. System-Felder

# Wertausgabe
_any(value: $variable)
_string(expr: { add: [{field: fldArtNr}, {value: " - "}, {field: fldSuchBeg}] })
_boolean(expr: { gt: [{field: fldLagMge}, {value: 0}] })
_localDate(expr: { fnGetAktDate: [] })

# Bedingte Ausfuehrung
details: _if(expr: { gt: [{field: fldLagMge}, {value: 0}] }) {
  fldStdPreis
  fldLagMge
}

# Bedingter Skalarwert
status: _ifThenElse(
  expr: { gt: [{field: fldLagMge}, {value: 0}] },
  then: "Verfuegbar",
  else: "Nicht auf Lager"
)

# Fehler ausloesen
_raise(message: "Negative Lagermenge!")

8. Mutationen

query vs. mutation

  • query: Snapshot-Transaktion, keine Sperren, null bei Fehler
  • mutation: Normale Transaktion, Alles-oder-Nichts (Fehler = Rollback)

Schreiboperationen

OperationZweck
rowNewNeuen Datensatz erstellen
rowNew(ifNotExists:...)Nur erstellen wenn nicht vorhanden (gibt null statt Fehler)
rowCopy(exactMatch:...)Datensatz kopieren (nicht-gesetzte Felder vom Original)
rowModify(exactMatch:...)Datensatz aendern
rowDelete(exactMatch:...)Datensatz loeschen
rowsModify/rowsCopy/rowsDeleteMassenoperationen (Fehler bei einem → Rollback aller)

Row-Kontexte

KontextSchreibenlnk...tbl... schreibbar
RowMutationNew/Copy/Modifyjaneinja
RowMutationRead (nach rowSave)neinja (mit Schreiben)nein
RowMutationDeleteneinneinnein

Datensatz erstellen

mutation {
  tblProducts {
    rowNew {
      fldArtNr(set: { string: "PROD-001" })
      fldBez1(set: { text: "Neuer Artikel" } as: DISPLAY_TEXT)
      fldVk0_Preis(set: { float: 99.95 })
    }   # Automatisch gespeichert am Block-Ende
  }
}

Bedingt (kein Fehler wenn vorhanden, gibt null zurueck):

rowNew(ifNotExists: { exactMatch: { byNr: { kf1ArtNr: { string: "PROD-001" } } } })

Datensatz kopieren

mutation {
  tblProducts {
    rowCopy(kf1ArtNr: { string: "LUTSCHER" }) {
      fldArtNr(set: { string: "LUTSCHER-V2" })
      # Alle anderen Felder (Preis, Bez., etc.) vom Original uebernommen
      fldBez1(as: DISPLAY_TEXT)
      fldVk0_Preis(as: FLOAT)
    }
  }
}

Details zu rowCopy, ifNotExists und Optimistic Locking in references/mutation-patterns.md.

Datensatz aendern

mutation {
  tblProducts {
    rowModify(kf1ArtNr: { string: "PROD-001" }) {
      fldVk0_Preis(set: { float: 129.95 })
      fldBez1(as: DISPLAY_TEXT)       # Nur lesen
    }
  }
}

Datensatz loeschen

mutation {
  tblProducts {
    rowDelete(kf1ArtNr: { string: "PROD-001" }, ignoreWarnings: true) {
      fldArtNr                         # Noch lesbar vor Loeschung
    }
  }
}

Speicheroperationen

# rowSave - Speichern, dann Read-Kontext (lnk... verfuegbar)
rowNew {
  fldArtNr(set: { string: "X" })
  rowSave { fldID fldModifyLSN }     # Ab hier nur lesen + lnk...
}

# rowSaveAndModify - Speichern, weiter schreiben
rowNew {
  fldArtNr(set: { string: "X" })
  rowSaveAndModify {
    fldBez1(set: { text: "Name" } as: DISPLAY_TEXT)
    tblTransactionItems { ... }       # Verschachtelte Tabelle schreibbar
  }
}

WICHTIG: Nach rowSave/rowSaveAndModify NICHT mehr im aeusseren Block schreiben!

Feldmanipulation (set-Parameter)

fldArtNr(set: { string: "PROD-005" })           # String
fldVk0_Preis(set: { float: 99.95 })             # Float
fldVk0_Preis(set: { text: "99,95" })            # Lokalisierter Text
fldGspAbDat(set: { text: "2023-12-24" })          # Datum (ISO-Format YYYY-MM-DD, auch localdate moeglich)
fldGspKz(set: { boolean: true })                 # Boolean
fldArt(set: { text: "Rechnung I" })              # Vorgangsart (immer Text, Nummern koennen abweichen!)
fldMge(set: { int: 5 })                         # Integer
fldGspAbDat(set: {})                             # NULL setzen

# Auto-Nummerierung (naechste freie Nr wenn vergeben)
fldAdrNr(set: { text: "10000", allowAutoNrOnSave: true })

# Kaskadierende Updates unterdruecken
fldZahlBed(set: { text: "30 Tage netto", suppressRelatedUpdates: true })

Assign-Parameter

# Row-Assign: Felder aus anderem Datensatz befuellen
rowNew(assignAddress: { kf1AdrNr: { text: "10000" } }) { ... }
rowNew(assignUser: { using: current }) { ... }

# Feld-Assign: Einzelnes Feld per Suche zuweisen
fldWgrNr(assignProductGroup: { exactMatch: { byBez: { kf1Bez: { text: "Elektronik" } } } })
fldSBzrNr(assignUser: { using: current })

# using: context in Verlinkungen (nimmt aeusseren Datensatz)
lnkProjects { rowNew(assignAddress: { using: context }) { ... } }

Verlinkungen in Mutationen (nur in RowMutationRead)

mutation {
  tblAddresses {
    rowRead(kf1AdrNr: { string: "10000" }) {
      lnkPostalAddresses {
        rowNew(setAdrNrAnsNr: usingAdrNr) {
          fldNa2(set: { text: "Lieferanschrift" })
          rowSave { fldAnsNr }
        }
      }
    }
  }
}

set...-Parameter bei rowNew in Verlinkungen: befuellt Schluesselfelder automatisch aus Kontext.


9. Vorgaenge - Kern-Workflow

Vorgangsarten

WICHTIG: Immer text statt int verwenden - Nummern koennen pro Installation abweichen!

fldArt(set: { text: "Rechnung I" })     # RICHTIG - Bezeichnung
fldArt(set: { int: 70 })                # VERMEIDEN - Nummer kann abweichen

Hinweis: fnConvert akzeptiert den Parameter transactionTypeNo sowohl als Integer als auch als Text:

fnConvert(transactionTypeNo: 50, ...)              # Integer - Standard-Nummer (50 = Lieferschein)
fnConvert(transactionTypeNo: "Lieferschein", ...)  # Text - Bezeichnung

Standard-Nummern und Bezeichnungen finden sich in references/vorgangsarten.md.

Vollstaendige Liste aller Vorgangsarten mit Standard-Nummern und Buchungsparametern: references/vorgangsarten.md

Funktionsuebersicht

FunktionBeschreibungKontextRueckgabe
fnPostBuchenrowReadEinzelwert
fnReverseStornierenrowReadEinzelwert
fnConvertWandelnrowReadArray
fnMoveToArchiveArchivierenrowReadEinzelwert

Alle erfordern: mutation + rowRead-Kontext. Leere Belegnummer = fehlgeschlagen.

Vorgang anlegen mit Positionen

mutation @acquireLocks(
  forWriting: [tblTransactions, tblTransactionItems]
  forReading: [tblAddresses, tblProducts]
) {
  tblTransactions {
    rowNew(assignAddress: { kf1AdrNr: { text: "10000" } }) {
      fldArt(set: { text: "Rechnung I" })

      rowSaveAndModify {
        fldBelegNr

        tblTransactionItems {
          pos1: rowNew(assignProduct: { kf1ArtNr: { text: "LUTSCHER" } }) {
            fldMge(set: { float: 10 })
          }
          pos2: rowNew(assignProduct: { kf1ArtNr: { text: "MYSTERYBOX" } }) {
            fldMge(set: { float: 2 })
          }
        }
      }
    }
  }
}

Hinweise:

  • fldArtNr akzeptiert Artikelnummern UND Barcodes (Auto-Resolve)
  • fldArt kann als Nummer (int: 50) oder Text (text: "Rechnung I") gesetzt werden
  • fldZeilenNr(set: {int: 0}) fuegt Position an den Anfang

Vorgang buchen (fnPost)

# Bestehenden Vorgang buchen
mutation {
  tblTransactions {
    rowRead(exactMatch: { byBelegNr: { kf1BelegNr: { string: "RE12500005" } } }) {
      fnPost { fldBelegNr }     # Leer = nicht gebucht!
    }
  }
}

Anlegen + Buchen in einer Mutation

mutation @acquireLocks(
  forWriting: [tblTransactions, tblTransactionItems]
  forReading: [tblAddresses, tblProducts]
) {
  tblTransactions {
    rowNew(assignAddress: { kf1AdrNr: { text: "10000" } }) {
      fldArt(set: { text: "Rechnung I" })
      rowSaveAndModify {
        fldBelegNr
        tblTransactionItems {
          pos1: rowNew(assignProduct: { kf1ArtNr: { text: "LUTSCHER" } }) {
            fldMge(set: { float: 10 })
          }
        }
        rowSave {                    # WICHTIG: Erst speichern!
          fnPost { fldBelegNr }      # Dann buchen
        }
      }
    }
  }
}

Vorgang stornieren (fnReverse)

mutation {
  tblTransactions {
    rowRead(exactMatch: { byBelegNr: { kf1BelegNr: { string: "RE12500002" } } }) {
      fnReverse { fldBelegNr }
    }
  }
}

Vorgang wandeln (fnConvert)

Gibt ein Array zurueck (kann mehrere Vorgaenge erzeugen):

mutation {
  tblTransactions {
    rowRead(exactMatch: { byBelegNr: { kf1BelegNr: { string: "AN2500001" } } }) {
      fnConvert(transactionTypeNo: 50, deliveryQuantityHandling: IGNORE) {
        fldBelegNr
      }
    }
  }
}

deliveryQuantityHandling: IGNORE | KEEP_UNCHANGED | RECALCULATE | RECALCULATE_IF_ZERO

Preisberechnung nach Speichern

rowSave {
  acoGPreis {
    totalGrossAmount          # Brutto
    totalNetAmount            # Netto
    totalTaxAmount            # Steuer
  }
}

10. Betragsgruppen (aco...)

Kurzbeispiel Lesen: acoEPr {totalGrossAmount totalNetAmount totalTaxAmount}

Details (Lesen, Schreiben, Preisberechnung nach Speichern): references/betragsgruppen.md


11. Paginierung (Relay Connection)

query ($pageSize: Int = 10, $after: String) {
  tblProducts {
    conRead(first: $pageSize, after: $after) {
      edges {
        cursor
        node { fldArtNr fldSuchBeg }
      }
      pageInfo { hasNextPage endCursor startCursor edgeCount }
    }
  }
}

WICHTIG: edgeCount gibt nur die Anzahl der zurueckgegebenen Edges zurueck, NICHT die Gesamtanzahl der Datensaetze. Es gibt kein totalCount-Feld. Zum Zaehlen: first mit ausreichend grossem Wert setzen und hasNextPage pruefen.


12. Haeufige Fehler vermeiden

FehlerLoesung
fnPost in rowModify-KontextNur in rowRead-Kontext
fnPost ohne rowSaveImmer rowSave vor fnPost
Schreiben nach rowSave im selben BlockNach rowSave nur lesen, oder rowSaveAndModify
lnk... in schreibendem KontextErst rowSave, dann lnk... im Read-Kontext
Mehrere Operatoren in einem Filterobjektand/or verwenden (@oneOf-Regel)
fnMoveToArchive nach fnPost in einer MutationGetrennte Mutationen (Auto-Archivierung!)
Leere Belegnummer nicht geprueftImmer fldBelegNr in fn...-Rueckgabe pruefen
by.../using... auf lnk... statt auf rowsReadGehoeren auf rowsRead/rowsModify innerhalb des Links
@store(as: "name")Korrekt: @store(in: $variable) mit Deklaration in Signatur
"Argument \"set\" is not defined"Fehlende Berechtigung - set wird ohne Recht nicht angeboten
Feldreihenfolge nicht beachtetFelder werden sequentiell ausgefuehrt - Menge VOR Preis setzen
rowCopy ohne neuen SchluesselKopie braucht eigenen Primaerschluessel
rowsDelete bricht abEin Fehler bei einem Datensatz → Rollback ALLER Loeschungen
fnConvert schlaegt fehl → rowNew als WorkaroundVERBOTEN! Bricht die Prozesskette. Fehlerursache klaeren und Nutzer informieren
fnReverse schlaegt fehl → rowDelete als WorkaroundVERBOTEN! Umgeht Storno-Logik (keine Gegenbuchungen, kein Audit-Trail). Nutzer informieren
fnPost schlaegt fehl → naechsten Schritt trotzdem ausfuehrenVERBOTEN! Folgeschritte (z.B. Wandlung) setzen erfolgreiche Buchung voraus. Nutzer informieren
fnMoveToArchive schlaegt fehl → manuell Daten kopieren/loeschenVERBOTEN! Archivierung hat eigene Logik. Nutzer informieren
Prozessschritte ueberspringen (z.B. direkt RE statt AB→LI→RE)Nur wenn Nutzer dies explizit bestaetigt. Auf moeglichen Kettenverlust hinweisen
edgeCount als Gesamtanzahl interpretiertedgeCount zaehlt nur zurueckgegebene Edges, NICHT alle Datensaetze. first: 0 ergibt immer edgeCount: 0. Zum Zaehlen: first: 100+ und hasNextPage pruefen
fldNa2/fldOrt/fldPLZ/fldStr auf tblAddressesDiese Felder leben in tblPostalAddresses, Zugriff ueber lnkPostalAddresses

13. Troubleshooting

Fehlermeldung: "Argument \"set\" is not defined"

Ursache: Fehlende Berechtigung. Der API-Nutzer hat kein Recht, dieses Feld zu setzen. Loesung: Berechtigung im ERP pruefen. Berechtigungs-pflichtige Felder: fldDat, fldVerk, fldKredLimit, fldInExtBeaKz, fldGspKz, fldEPreis.

Fehlermeldung: "Address \"10002\" is blocked."

Ursache: Adresse hat fldGspKz = true (Gesperrt-Kennzeichen). Loesung: Andere Adresse verwenden oder Sperrung im ERP aufheben.

Leere Belegnummer nach fnPost/fnReverse/fnConvert

Ursache: Funktion konnte nicht ausgefuehrt werden (Voraussetzungen nicht erfuellt). Loesung: Immer Belegnummer pruefen: fnPost {fldBelegNr}. Leer = fehlgeschlagen.

Rollback nach fnPost trotz erfolgreicher Buchung

Ursache: Eine NACHFOLGENDE Operation in derselben Mutation ist fehlgeschlagen. Alles-oder-Nichts. Loesung: fnPost und Folgeoperationen in getrennte Mutationen aufteilen, oder Fehlerquelle beheben.

fnPost hat keine Wirkung (Positionen fehlen)

Ursache: rowSave vor fnPost vergessen. fnPost arbeitet nur auf gespeicherten Daten. Loesung: Immer rowSave {fnPost {fldBelegNr}} - rowSave VOR fnPost.

lnk...-Felder nicht verfuegbar

Ursache: Datensatz ist noch in schreibendem Kontext (RowMutationNew/Copy/Modify). Loesung: Erst rowSave aufrufen → wechselt zu RowMutationReadlnk... wird verfuegbar.

Laufzeitfehler nach rowSave

Ursache: Versuch im selben Block nach rowSave noch Felder zu schreiben. Loesung: rowSaveAndModify verwenden wenn danach noch geschrieben werden soll, oder alle Schreiboperationen VOR rowSave platzieren.

Deadlock bei parallelen Mutationen

Ursache: @acquireLocks fehlt oder unvollstaendig. Loesung: @acquireLocks(forWriting: [...], forReading: [...]) mit ALLEN beteiligten Tabellen.

fn-Funktion schlaegt fehl (fnConvert/fnPost/fnReverse/fnMoveToArchive)

Ursache: Vielfaeltig - fehlende Konfiguration (Wandlungspfad), Beleg bereits archiviert, fehlende Berechtigung, Geschaeftsregel verletzt, Beleg gesperrt. Loesung: STOPP - KEINEN Workaround versuchen! Insbesondere:

  • NICHT per rowNew einen Ersatzbeleg anlegen (bricht Prozesskette)
  • NICHT per rowDelete einen Beleg loeschen statt zu stornieren (umgeht Audit-Trail)
  • NICHT den naechsten Prozessschritt ausfuehren wenn der aktuelle fehlschlug Stattdessen: Fehlermeldung dem Nutzer zeigen und gemeinsam klaeren. Moegliche Ursachen:
  • Wandlungspfad im ERP nicht konfiguriert → ERP-Administrator muss Pfad freischalten
  • Beleg bereits im Archiv → fnConvert nur auf aktive Vorgaenge moeglich
  • Fehlende Berechtigung → API-Nutzer-Rechte pruefen
  • Geschaeftsregel verletzt → Beleg-Daten pruefen (z.B. fehlende Pflichtfelder)

Query gibt null zurueck obwohl Datensatz existiert

Ursache (in mutation): modifyLSN stimmt nicht ueberein (Optimistic Locking Konflikt). Ursache (in query): Schluessel falsch oder Sortierfolge stimmt nicht. Loesung: @onNull-Pattern verwenden um Konflikte abzufangen. Siehe references/mutation-patterns.md.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

32%
按下载量换算54

Claude

30.77%
按下载量换算52

Cursor

18.94%
按下载量换算32

Gemini CLI

9.29%
按下载量换算16

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

external-service

该 Skill 可能调用第三方服务、云服务或外部模型 API,使用前需要确认账号、额度、数据发送范围和服务条款。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills