@zeyos/client 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -4
- package/README.md +31 -1
- package/agents/README.md +4 -0
- package/agents/shared/zeyos-entity-map.md +5 -1
- package/agents/shared/zeyos-entity-reference.md +89 -33
- package/agents/zeyos-mail-operations/SKILL.md +7 -1
- package/agents/zeyos-mail-operations/references/workflows.md +19 -2
- package/agents/zeyos-platform-and-schema/SKILL.md +1 -1
- package/agents/zeyos-platform-and-schema/references/workflows.md +21 -5
- package/agents/zeyos-time-tracking/SKILL.md +48 -0
- package/agents/zeyos-time-tracking/references/workflows.md +230 -0
- package/agents/zeyos-work-management/SKILL.md +5 -2
- package/agents/zeyos-work-management/references/workflows.md +54 -4
- package/docs/02-javascript-client/03-making-requests.md +46 -1
- package/docs/03-cli/02-commands.md +63 -1
- package/docs/03-cli/03-configuration.md +37 -5
- package/docs/04-agent-workflows/01-agent-quickstart.md +24 -0
- package/docs/04-agent-workflows/03-cli-coverage-and-escalation.md +3 -2
- package/docs/06-okf/01-overview.md +70 -0
- package/docs/06-okf/02-producing-and-consuming.md +46 -0
- package/docs/06-okf/03-keeping-fresh.md +53 -0
- package/docs/06-okf/04-loops.md +58 -0
- package/docs/06-okf/_category_.json +9 -0
- package/okf/concepts/counting-and-sums.md +10 -0
- package/okf/concepts/dates-unix-seconds.md +12 -0
- package/okf/concepts/enums.md +14 -0
- package/okf/concepts/filters-vs-filter.md +14 -0
- package/okf/concepts/index.md +8 -0
- package/okf/concepts/operationid-vocabulary.md +17 -0
- package/okf/concepts/visibility-column.md +13 -0
- package/okf/entities/accounts.md +82 -0
- package/okf/entities/actionsteps.md +84 -0
- package/okf/entities/addresses.md +50 -0
- package/okf/entities/applicationassets.md +43 -0
- package/okf/entities/applications.md +62 -0
- package/okf/entities/appointments.md +79 -0
- package/okf/entities/associations.md +41 -0
- package/okf/entities/binfiles.md +32 -0
- package/okf/entities/campaigns.md +66 -0
- package/okf/entities/categories.md +55 -0
- package/okf/entities/channels.md +54 -0
- package/okf/entities/comments.md +44 -0
- package/okf/entities/components.md +46 -0
- package/okf/entities/contacts.md +96 -0
- package/okf/entities/contacts2contacts.md +42 -0
- package/okf/entities/contracts.md +83 -0
- package/okf/entities/couponcodes.md +58 -0
- package/okf/entities/coupons.md +69 -0
- package/okf/entities/customfields.md +59 -0
- package/okf/entities/davservers.md +74 -0
- package/okf/entities/devices.md +65 -0
- package/okf/entities/documents.md +76 -0
- package/okf/entities/dunning.md +82 -0
- package/okf/entities/dunning2transactions.md +46 -0
- package/okf/entities/entities2channels.md +42 -0
- package/okf/entities/events.md +57 -0
- package/okf/entities/feedservers.md +67 -0
- package/okf/entities/files.md +50 -0
- package/okf/entities/follows.md +40 -0
- package/okf/entities/forks.md +54 -0
- package/okf/entities/groups.md +48 -0
- package/okf/entities/groups2users.md +44 -0
- package/okf/entities/index.md +93 -0
- package/okf/entities/invitations.md +53 -0
- package/okf/entities/items.md +95 -0
- package/okf/entities/ledgers.md +56 -0
- package/okf/entities/likes.md +40 -0
- package/okf/entities/links.md +70 -0
- package/okf/entities/mailinglists.md +67 -0
- package/okf/entities/mailingrecipients.md +45 -0
- package/okf/entities/mailservers.md +77 -0
- package/okf/entities/messagereads.md +40 -0
- package/okf/entities/messages.md +104 -0
- package/okf/entities/notes.md +73 -0
- package/okf/entities/objects.md +70 -0
- package/okf/entities/opportunities.md +87 -0
- package/okf/entities/participants.md +52 -0
- package/okf/entities/payments.md +76 -0
- package/okf/entities/permissions.md +46 -0
- package/okf/entities/pricelists.md +70 -0
- package/okf/entities/pricelists2accounts.md +46 -0
- package/okf/entities/prices.md +49 -0
- package/okf/entities/projects.md +72 -0
- package/okf/entities/records.md +75 -0
- package/okf/entities/relateditems.md +43 -0
- package/okf/entities/resources.md +55 -0
- package/okf/entities/services.md +64 -0
- package/okf/entities/stocktransactions.md +72 -0
- package/okf/entities/storages.md +56 -0
- package/okf/entities/suppliers.md +51 -0
- package/okf/entities/tasks.md +86 -0
- package/okf/entities/tickets.md +86 -0
- package/okf/entities/transactions.md +118 -0
- package/okf/entities/users.md +66 -0
- package/okf/entities/weblets.md +66 -0
- package/okf/index.md +11 -0
- package/okf/log.md +4 -0
- package/okf/metrics/cash-received.md +10 -0
- package/okf/metrics/index.md +6 -0
- package/okf/metrics/invoiced-net-revenue.md +16 -0
- package/okf/metrics/open-customers.md +14 -0
- package/okf/metrics/overdue-receivables.md +12 -0
- package/okf/playbooks/customer-360.md +12 -0
- package/okf/playbooks/index.md +5 -0
- package/okf/playbooks/revenue-this-year.md +19 -0
- package/okf/playbooks/ticket-work-packet.md +11 -0
- package/package.json +9 -5
- package/scripts/data/okf-curation.mjs +258 -0
- package/scripts/generate-client.mjs +4 -275
- package/scripts/generate-okf.mjs +241 -0
- package/scripts/lib/okf.mjs +272 -0
- package/scripts/lib/spec-model.mjs +325 -0
- package/src/index.js +4 -0
- package/src/runtime/client.js +199 -18
- package/src/runtime/okf.js +237 -0
- package/samples/missioncontrol/README.md +0 -106
- package/samples/missioncontrol/fetch-data.mjs +0 -341
- package/samples/missioncontrol/index.html +0 -419
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Metric
|
|
3
|
+
title: Overdue Receivables
|
|
4
|
+
description: "Receivables in collection, via dunning — not from transactions alone."
|
|
5
|
+
tags: [collections]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
**Definition.** Overdue/in-collection exposure is tracked through [dunning](/entities/dunning.md) notices and the [dunning2transactions](/entities/dunning2transactions.md) junction, not inferred from [transactions](/entities/transactions.md) alone.
|
|
9
|
+
|
|
10
|
+
**operationId trap.** Use `listDunningNotices` / `getDunningNotice` and `listDunningToTransactions`. See [operationid-vocabulary](/concepts/operationid-vocabulary.md).
|
|
11
|
+
|
|
12
|
+
Separate invoice exposure (the receivable) from collection stage and next action.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Playbook
|
|
3
|
+
title: Customer 360
|
|
4
|
+
description: "Assemble a cross-domain summary for one customer."
|
|
5
|
+
tags: [crm]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
1. Resolve the account first ([accounts](/entities/accounts.md) by `customernum`/`lastname`).
|
|
9
|
+
2. Open work: [tickets](/entities/tickets.md) for the account.
|
|
10
|
+
3. Billing: [transactions](/entities/transactions.md) (invoices/credits) and [payments](/entities/payments.md).
|
|
11
|
+
4. Mail: resolve [contacts](/entities/contacts.md) email, then [messages](/entities/messages.md) (no direct account FK — see the entity note).
|
|
12
|
+
5. Present facts and inference separately; state interpretations.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Playbooks
|
|
2
|
+
|
|
3
|
+
* [Customer 360](customer-360.md) - Assemble a cross-domain summary for one customer.
|
|
4
|
+
* [Revenue This Year](revenue-this-year.md) - Answer "what have we invoiced/collected this year?" end to end.
|
|
5
|
+
* [Ticket Work Packet](ticket-work-packet.md) - Trace a ticket down to its tasks and follow-ups.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Playbook
|
|
3
|
+
title: Revenue This Year
|
|
4
|
+
description: "Answer \"what have we invoiced/collected this year?\" end to end."
|
|
5
|
+
tags: [billing]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
1. Decide invoiced revenue vs cash received. If unspecified, state you are using invoiced net revenue ([invoiced-net-revenue](/metrics/invoiced-net-revenue.md)).
|
|
9
|
+
2. Normalize the window to Unix **seconds** (e.g. 2026-01-01 = 1767225600). See [dates-unix-seconds](/concepts/dates-unix-seconds.md).
|
|
10
|
+
3. `list` billing invoices ([transactions](/entities/transactions.md) `type = 3`) in the window with `netamount`; high `--limit`.
|
|
11
|
+
4. If net-after-credits, `list` `type = 4` and subtract.
|
|
12
|
+
5. Sum client-side and report the figure (do not describe the plan — run it).
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
zeyos list transactions \
|
|
16
|
+
--filter '{"type":3,"date":{">=":1767225600,"<":1798761600}}' \
|
|
17
|
+
--fields ID,transactionnum,date,netamount --limit 10000 --json \
|
|
18
|
+
| python3 -c 'import sys,json; r=json.load(sys.stdin); print(sum(x.get("netamount",0) for x in r.get("data",r)))'
|
|
19
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Playbook
|
|
3
|
+
title: Ticket Work Packet
|
|
4
|
+
description: "Trace a ticket down to its tasks and follow-ups."
|
|
5
|
+
tags: [work]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
1. Resolve the [ticket](/entities/tickets.md) (`ticketnum`/`name`).
|
|
9
|
+
2. [tasks](/entities/tasks.md) where `ticket` = that ID (use the `filters` form for the FK — see [filters-vs-filter](/concepts/filters-vs-filter.md)).
|
|
10
|
+
3. [actionsteps](/entities/actionsteps.md) bound to the ticket/its tasks for smaller follow-ups.
|
|
11
|
+
4. Summarize open vs closed (closed ticket = `status` IN [9, 11]).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeyos/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Dependency-light JavaScript client for ZeyOS OpenAPI services",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,14 +29,15 @@
|
|
|
29
29
|
"files": [
|
|
30
30
|
"src",
|
|
31
31
|
"scripts/generate-client.mjs",
|
|
32
|
+
"scripts/generate-okf.mjs",
|
|
33
|
+
"scripts/lib",
|
|
34
|
+
"scripts/data",
|
|
32
35
|
"openapi",
|
|
33
36
|
"docs",
|
|
37
|
+
"okf",
|
|
34
38
|
"samples/crm",
|
|
35
39
|
"samples/dashboard",
|
|
36
40
|
"samples/kanban",
|
|
37
|
-
"samples/missioncontrol/README.md",
|
|
38
|
-
"samples/missioncontrol/fetch-data.mjs",
|
|
39
|
-
"samples/missioncontrol/index.html",
|
|
40
41
|
"agents",
|
|
41
42
|
"README.md",
|
|
42
43
|
"CHANGELOG.md",
|
|
@@ -46,7 +47,10 @@
|
|
|
46
47
|
"node": ">=18"
|
|
47
48
|
},
|
|
48
49
|
"scripts": {
|
|
49
|
-
"generate": "node scripts/generate-client.mjs",
|
|
50
|
+
"generate": "node scripts/generate-client.mjs && node scripts/generate-okf.mjs",
|
|
51
|
+
"okf:build": "node scripts/generate-okf.mjs",
|
|
52
|
+
"okf:check": "node --test test/okf.test.js",
|
|
53
|
+
"okf:refine": "node test/agent-protocol/harness/refine-okf.mjs",
|
|
50
54
|
"test": "node scripts/test.mjs",
|
|
51
55
|
"test:cli-integration": "node --test cli/test/integration.mjs",
|
|
52
56
|
"test:agent-protocol": "node test/agent-protocol/harness/run.mjs",
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// Curated OKF content — the single canonical home for ZeyOS business knowledge
|
|
2
|
+
// that is NOT mechanically derivable from the specs. Entity purposes are lifted
|
|
3
|
+
// from agents/shared/zeyos-entity-reference.md; metric/playbook/concept seeds
|
|
4
|
+
// from agents/**/references/workflows.md and project memory. generate-okf.mjs
|
|
5
|
+
// uses ENTITY_META for entity frontmatter + curated-note seeds, and seeds the
|
|
6
|
+
// metrics/playbooks/concepts docs from the arrays below (seed-if-absent: once a
|
|
7
|
+
// doc exists it is owned by humans/the refiner and is not overwritten).
|
|
8
|
+
|
|
9
|
+
// ── Per-entity curation (purpose → description; cluster → tag; optional note) ──
|
|
10
|
+
export const ENTITY_META = {
|
|
11
|
+
// CRM, customer, relationship
|
|
12
|
+
accounts: { description: 'Customer, supplier, prospect, or employee master records.', tags: ['crm'], note: 'No `name` column — use `lastname` + `firstname`. `type`: 0=PROSPECT,1=CUSTOMER,2=SUPPLIER,3=CUSTOMERANDSUPPLIER,4=COMPETITOR,5=EMPLOYEE. `createAccount` REQUIRES `currency` (NOT NULL, no default) or it 500s.' },
|
|
13
|
+
contacts: { description: 'People linked to accounts.', tags: ['crm'] },
|
|
14
|
+
addresses: { description: 'Additional address records linked to accounts or contacts.', tags: ['crm'] },
|
|
15
|
+
contacts2contacts: { description: 'Contact-to-contact relationships.', tags: ['crm'] },
|
|
16
|
+
opportunities: { description: 'Sales pipeline and deal records.', tags: ['crm'] },
|
|
17
|
+
campaigns: { description: 'Marketing or outreach campaigns.', tags: ['outreach'] },
|
|
18
|
+
contracts: { description: 'Long-lived commercial agreements.', tags: ['crm'] },
|
|
19
|
+
participants: { description: 'Contacts enrolled in campaigns or mailing lists.', tags: ['outreach'] },
|
|
20
|
+
mailinglists: { description: 'Mailing list definitions.', tags: ['outreach'] },
|
|
21
|
+
|
|
22
|
+
// Work, delivery, calendar
|
|
23
|
+
tickets: { description: 'Support or service work items.', tags: ['work'], note: 'Closed = `status` IN [9 (COMPLETED), 11 (BOOKED)]. Filter time windows on the indexed `date` field, not `creationdate`/`lastmodified` (unindexed → HTTP 503). Has a `visibility` column. `priority`: 0=LOWEST…4=HIGHEST.' },
|
|
24
|
+
tasks: { description: 'Actionable delivery work.', tags: ['work'] },
|
|
25
|
+
actionsteps: { description: 'Cross-record follow-up work items with assignee, due date, status, and effort.', tags: ['work'], note: 'Record-bound follow-ups (linked to a task, ticket, or account, with optional transaction). Do not inflate into full project tasks.' },
|
|
26
|
+
projects: { description: 'Top-level initiatives.', tags: ['work'] },
|
|
27
|
+
appointments: { description: 'Calendar appointments.', tags: ['work'] },
|
|
28
|
+
invitations: { description: 'Appointment invitations.', tags: ['work'] },
|
|
29
|
+
events: { description: 'Generic event records attached to entities.', tags: ['collaboration'] },
|
|
30
|
+
|
|
31
|
+
// Messaging, knowledge, collaboration
|
|
32
|
+
messages: { description: 'Email and message records.', tags: ['messaging'], note: 'No direct `account` foreign key — link via `ticket`/`opportunity`/`mailinglist`/`reference`, or resolve customer email addresses first. Reconstruct threads via `reference`/`messageid`/`subject`.' },
|
|
33
|
+
mailingrecipients: { description: 'Recipient records for a message.', tags: ['outreach'] },
|
|
34
|
+
messagereads: { description: 'Read-tracking records for messages.', tags: ['messaging'] },
|
|
35
|
+
notes: { description: 'Text-centric internal knowledge items.', tags: ['knowledge'] },
|
|
36
|
+
documents: { description: 'Formal file-like business documents.', tags: ['knowledge'] },
|
|
37
|
+
files: { description: 'Attachments linked to a record or comment.', tags: ['knowledge'] },
|
|
38
|
+
comments: { description: 'Record-linked comments.', tags: ['collaboration'] },
|
|
39
|
+
channels: { description: 'Collaboration or distribution channels.', tags: ['collaboration'] },
|
|
40
|
+
entities2channels: { description: 'Junction between records and channels.', tags: ['collaboration'] },
|
|
41
|
+
follows: { description: 'Follow/watch subscriptions on entities.', tags: ['collaboration'] },
|
|
42
|
+
likes: { description: 'Lightweight positive reactions on records.', tags: ['collaboration'] },
|
|
43
|
+
records: { description: 'Generic feed and discussion records with entity/index references.', tags: ['collaboration'] },
|
|
44
|
+
|
|
45
|
+
// Billing, payments, collections
|
|
46
|
+
transactions: { description: 'Billing, procurement, or production business transactions.', tags: ['billing'], note: 'NO `visibility` column — adding `"visibility":0` to a filter 400s. Use `type` 3=billing invoice, 4=billing credit. Use `netamount` for invoiced revenue; sum client-side (no server-side SUM). Use `date` for period reporting.' },
|
|
47
|
+
payments: { description: 'Cash movement records.', tags: ['billing'], note: 'Cash basis. Links to a `transaction` or directly to an `account`. Sum `amount` for cash received.' },
|
|
48
|
+
ledgers: { description: 'Payment ledger definitions.', tags: ['billing'] },
|
|
49
|
+
dunning: { description: 'Collection or dunning notices.', tags: ['collections'], note: 'operationId trap: list via `listDunningNotices` / get via `getDunningNotice` (NOT `listDunning`). A collection-stage object, not the receivable itself.' },
|
|
50
|
+
dunning2transactions: { description: 'Dunning-to-transaction junction.', tags: ['collections'], note: 'operationId: `listDunningToTransactions`.' },
|
|
51
|
+
|
|
52
|
+
// Inventory, pricing, commerce
|
|
53
|
+
items: { description: 'Product and service catalog entries.', tags: ['commerce'] },
|
|
54
|
+
categories: { description: 'Category definitions.', tags: ['commerce'], note: 'operationId trap: list op is `listCategorys` (sic); singular ops use `Category`.' },
|
|
55
|
+
components: { description: 'Item-to-item composition records (BOM/kit).', tags: ['commerce'] },
|
|
56
|
+
relateditems: { description: 'Related product links (cross-sell, substitute, accessory).', tags: ['commerce'] },
|
|
57
|
+
stocktransactions: { description: 'Inventory movements.', tags: ['commerce'] },
|
|
58
|
+
storages: { description: 'Inventory storage locations.', tags: ['commerce'] },
|
|
59
|
+
suppliers: { description: 'Supplier-to-item links.', tags: ['commerce'] },
|
|
60
|
+
pricelists: { description: 'Price list definitions.', tags: ['commerce'], note: 'operationId: `listPriceLists`.' },
|
|
61
|
+
pricelists2accounts: { description: 'Account-to-price-list assignments.', tags: ['commerce'], note: 'operationId: `listPriceListsToAccounts`.' },
|
|
62
|
+
prices: { description: 'Item prices within a price list.', tags: ['commerce'] },
|
|
63
|
+
coupons: { description: 'Coupon definitions.', tags: ['commerce'] },
|
|
64
|
+
couponcodes: { description: 'Codes under a coupon definition.', tags: ['commerce'] },
|
|
65
|
+
|
|
66
|
+
// Platform, extensibility, admin, dev
|
|
67
|
+
users: { description: 'System users.', tags: ['platform'], note: 'Resolve assignees/ownership here; user names may not match contact names.' },
|
|
68
|
+
groups: { description: 'User groups.', tags: ['platform'] },
|
|
69
|
+
groups2users: { description: 'Group membership junction.', tags: ['platform'], note: 'Read-only; operationId `listGroupsToUsers`.' },
|
|
70
|
+
permissions: { description: 'Group-level permission grants.', tags: ['platform'] },
|
|
71
|
+
applications: { description: 'Application definitions.', tags: ['platform'] },
|
|
72
|
+
applicationassets: { description: 'Assets linked to an application.', tags: ['platform'] },
|
|
73
|
+
resources: { description: 'Named resources linked to an application or standalone.', tags: ['platform'] },
|
|
74
|
+
services: { description: 'Hook, timing, or remote-call services.', tags: ['platform'] },
|
|
75
|
+
weblets: { description: 'UI modules with view/type metadata.', tags: ['platform'] },
|
|
76
|
+
forks: { description: 'Module/fork definitions with identifiers and module names.', tags: ['platform'] },
|
|
77
|
+
customfields: { description: 'Custom field definitions.', tags: ['platform'] },
|
|
78
|
+
objects: { description: 'Custom object records with arbitrary JSON payloads.', tags: ['platform'] },
|
|
79
|
+
links: { description: 'Link records with name and description.', tags: ['platform'] },
|
|
80
|
+
davservers: { description: 'DAV (calendar/contact sync) server definitions.', tags: ['platform'], note: 'operationId: `listDAVServers`.' },
|
|
81
|
+
feedservers: { description: 'Feed server definitions.', tags: ['platform'] },
|
|
82
|
+
binfiles: { description: 'Binary file storage records.', tags: ['platform'], note: 'List-only: `listBinFiles`.' },
|
|
83
|
+
associations: { description: 'Generic cross-entity relation records with metadata.', tags: ['platform'] },
|
|
84
|
+
devices: { description: 'Inventory device records.', tags: ['platform'] },
|
|
85
|
+
mailservers: { description: 'Mail server definitions.', tags: ['messaging'] }
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// ── Curated narrative docs (seed-if-absent) ───────────────────────────────────
|
|
89
|
+
|
|
90
|
+
export const METRICS = [
|
|
91
|
+
{
|
|
92
|
+
id: 'invoiced-net-revenue',
|
|
93
|
+
title: 'Invoiced Net Revenue',
|
|
94
|
+
description: 'Net invoiced revenue from billing invoices over a date window.',
|
|
95
|
+
tags: ['billing', 'revenue'],
|
|
96
|
+
body: `**Definition.** Sum of \`netamount\` over [transactions](/entities/transactions.md) where \`type = 3\` (billing invoice) and \`date\` falls in the window. For *net after credits*, also sum \`type = 4\` (billing credit) and subtract.
|
|
97
|
+
|
|
98
|
+
**Why \`date\`, not \`lastmodified\`.** \`date\` is the business-effective invoice date; \`lastmodified\` is change tracking. See [dates-unix-seconds](/concepts/dates-unix-seconds.md).
|
|
99
|
+
|
|
100
|
+
**No server-side SUM.** \`list\` the matching rows (high \`--limit\`, up to 10000) with \`netamount\` and add them up client-side. See [counting-and-sums](/concepts/counting-and-sums.md).
|
|
101
|
+
|
|
102
|
+
**Do not** add \`"visibility":0\` — \`transactions\` has no such column and it 400s. See [visibility-column](/concepts/visibility-column.md).
|
|
103
|
+
|
|
104
|
+
Related playbook: [revenue-this-year](/playbooks/revenue-this-year.md).`
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: 'cash-received',
|
|
108
|
+
title: 'Cash Received',
|
|
109
|
+
description: 'Cash collected (settlement basis) over a date window.',
|
|
110
|
+
tags: ['billing', 'payments'],
|
|
111
|
+
body: `**Definition.** Sum of \`amount\` over [payments](/entities/payments.md) with \`date\` in the window. This is cash basis — distinct from [invoiced-net-revenue](/metrics/invoiced-net-revenue.md) (accrual/billed basis).
|
|
112
|
+
|
|
113
|
+
Separate direct account payments from transaction-linked payments if the answer needs it. Sum client-side; there is no server-side SUM.`
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'open-customers',
|
|
117
|
+
title: 'Open Customers',
|
|
118
|
+
description: 'Count of active customer accounts.',
|
|
119
|
+
tags: ['crm'],
|
|
120
|
+
body: `**Definition.** Count of [accounts](/entities/accounts.md) where \`type = 1\` (CUSTOMER), excluding archived (\`visibility = 0\`).
|
|
121
|
+
|
|
122
|
+
\`\`\`bash
|
|
123
|
+
zeyos count accounts --filter '{"type":1,"visibility":0}'
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
Count server-side (\`count\`), never \`list\` + row length. See [counting-and-sums](/concepts/counting-and-sums.md). State the definition you used ("customer = type 1, excluding archived").`
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: 'overdue-receivables',
|
|
130
|
+
title: 'Overdue Receivables',
|
|
131
|
+
description: 'Receivables in collection, via dunning — not from transactions alone.',
|
|
132
|
+
tags: ['collections'],
|
|
133
|
+
body: `**Definition.** Overdue/in-collection exposure is tracked through [dunning](/entities/dunning.md) notices and the [dunning2transactions](/entities/dunning2transactions.md) junction, not inferred from [transactions](/entities/transactions.md) alone.
|
|
134
|
+
|
|
135
|
+
**operationId trap.** Use \`listDunningNotices\` / \`getDunningNotice\` and \`listDunningToTransactions\`. See [operationid-vocabulary](/concepts/operationid-vocabulary.md).
|
|
136
|
+
|
|
137
|
+
Separate invoice exposure (the receivable) from collection stage and next action.`
|
|
138
|
+
}
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
export const PLAYBOOKS = [
|
|
142
|
+
{
|
|
143
|
+
id: 'revenue-this-year',
|
|
144
|
+
title: 'Revenue This Year',
|
|
145
|
+
description: 'Answer "what have we invoiced/collected this year?" end to end.',
|
|
146
|
+
tags: ['billing'],
|
|
147
|
+
body: `1. Decide invoiced revenue vs cash received. If unspecified, state you are using invoiced net revenue ([invoiced-net-revenue](/metrics/invoiced-net-revenue.md)).
|
|
148
|
+
2. Normalize the window to Unix **seconds** (e.g. 2026-01-01 = 1767225600). See [dates-unix-seconds](/concepts/dates-unix-seconds.md).
|
|
149
|
+
3. \`list\` billing invoices ([transactions](/entities/transactions.md) \`type = 3\`) in the window with \`netamount\`; high \`--limit\`.
|
|
150
|
+
4. If net-after-credits, \`list\` \`type = 4\` and subtract.
|
|
151
|
+
5. Sum client-side and report the figure (do not describe the plan — run it).
|
|
152
|
+
|
|
153
|
+
\`\`\`bash
|
|
154
|
+
zeyos list transactions \\
|
|
155
|
+
--filter '{"type":3,"date":{">=":1767225600,"<":1798761600}}' \\
|
|
156
|
+
--fields ID,transactionnum,date,netamount --limit 10000 --json \\
|
|
157
|
+
| python3 -c 'import sys,json; r=json.load(sys.stdin); print(sum(x.get("netamount",0) for x in r.get("data",r)))'
|
|
158
|
+
\`\`\``
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: 'customer-360',
|
|
162
|
+
title: 'Customer 360',
|
|
163
|
+
description: 'Assemble a cross-domain summary for one customer.',
|
|
164
|
+
tags: ['crm'],
|
|
165
|
+
body: `1. Resolve the account first ([accounts](/entities/accounts.md) by \`customernum\`/\`lastname\`).
|
|
166
|
+
2. Open work: [tickets](/entities/tickets.md) for the account.
|
|
167
|
+
3. Billing: [transactions](/entities/transactions.md) (invoices/credits) and [payments](/entities/payments.md).
|
|
168
|
+
4. Mail: resolve [contacts](/entities/contacts.md) email, then [messages](/entities/messages.md) (no direct account FK — see the entity note).
|
|
169
|
+
5. Present facts and inference separately; state interpretations.`
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
id: 'ticket-work-packet',
|
|
173
|
+
title: 'Ticket Work Packet',
|
|
174
|
+
description: 'Trace a ticket down to its tasks and follow-ups.',
|
|
175
|
+
tags: ['work'],
|
|
176
|
+
body: `1. Resolve the [ticket](/entities/tickets.md) (\`ticketnum\`/\`name\`).
|
|
177
|
+
2. [tasks](/entities/tasks.md) where \`ticket\` = that ID (use the \`filters\` form for the FK — see [filters-vs-filter](/concepts/filters-vs-filter.md)).
|
|
178
|
+
3. [actionsteps](/entities/actionsteps.md) bound to the ticket/its tasks for smaller follow-ups.
|
|
179
|
+
4. Summarize open vs closed (closed ticket = \`status\` IN [9, 11]).`
|
|
180
|
+
}
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
export const CONCEPTS = [
|
|
184
|
+
{
|
|
185
|
+
id: 'filters-vs-filter',
|
|
186
|
+
title: 'filters vs filter (the FK/GIN footgun)',
|
|
187
|
+
description: 'Use `filters` (plural) so foreign-key fields match via their GIN/partial indexes.',
|
|
188
|
+
tags: ['query'],
|
|
189
|
+
body: `The OpenAPI spec documents the list body field as \`filter\` (singular), but **\`filters\` (plural)** is what reliably matches GIN-indexed / partial-indexed foreign-key fields (\`account\`, \`project\`, \`ticket\` on related resources).
|
|
190
|
+
|
|
191
|
+
- \`@zeyos/client\`: use \`filters\`.
|
|
192
|
+
- \`zeyos\` CLI: pass \`--filter '{…}'\` — it serializes to \`filters\` internally.
|
|
193
|
+
- Raw REST: the spec says \`filter\`; verify against the target instance.
|
|
194
|
+
|
|
195
|
+
\`client.schema.validate()\` flags a top-level \`filter\` on list/count ops and suggests \`filters\`. Only filter on columns the resource actually has — an unknown column 400s with no hint which field was wrong (run \`zeyos describe <resource>\` first).`
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
id: 'visibility-column',
|
|
199
|
+
title: 'visibility: 0 (only where the column exists)',
|
|
200
|
+
description: 'visibility:0 hides archived rows — but only resources that have the column.',
|
|
201
|
+
tags: ['query'],
|
|
202
|
+
body: `\`visibility = 0\` excludes archived/deleted rows, but **only some resources have a \`visibility\` column**:
|
|
203
|
+
|
|
204
|
+
- Have it: [tickets](/entities/tickets.md), [accounts](/entities/accounts.md), [items](/entities/items.md).
|
|
205
|
+
- Do **not** have it: [transactions](/entities/transactions.md) — adding \`"visibility":0\` there returns an opaque **HTTP 400**.
|
|
206
|
+
|
|
207
|
+
More generally, filtering on any column a resource lacks 400s with no field name. Include \`visibility:0\` on resources that have it unless the user wants archived records; \`zeyos describe <resource>\` tells you whether the column exists.`
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: 'dates-unix-seconds',
|
|
211
|
+
title: 'Dates are Unix seconds',
|
|
212
|
+
description: 'All ZeyOS timestamps are Unix seconds; pick the indexed date field.',
|
|
213
|
+
tags: ['query'],
|
|
214
|
+
body: `All ZeyOS dates are Unix timestamps in **seconds** (not milliseconds).
|
|
215
|
+
|
|
216
|
+
- \`date\` — business-effective date (invoice date, message date). Use for period reporting. Indexed.
|
|
217
|
+
- \`lastmodified\` — recent-change tracking.
|
|
218
|
+
- \`creationdate\` — often **unindexed**; filtering a time window on it (or other unindexed date columns) can return **HTTP 503**. Prefer the indexed \`date\` field for windows.`
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
id: 'operationid-vocabulary',
|
|
222
|
+
title: 'operationId ≠ table noun',
|
|
223
|
+
description: 'REST operationIds are CamelCase compounds; several diverge from the dbref noun.',
|
|
224
|
+
tags: ['query'],
|
|
225
|
+
body: `The dbref table noun (also the REST URL path segment) is **not** the \`@zeyos/client\` operationId. Most follow \`list<Plural>\`/\`get<Singular>\`/… but several diverge:
|
|
226
|
+
|
|
227
|
+
- \`dunning\` → \`listDunningNotices\` / \`getDunningNotice\`
|
|
228
|
+
- \`dunning2transactions\` → \`listDunningToTransactions\`
|
|
229
|
+
- \`pricelists\` → \`listPriceLists\`; \`pricelists2accounts\` → \`listPriceListsToAccounts\`
|
|
230
|
+
- \`mailinglists\` → \`listMailingLists\`; \`actionsteps\` → \`listActionSteps\`
|
|
231
|
+
- \`categories\` → \`listCategorys\` (sic) but \`getCategory\`
|
|
232
|
+
- \`davservers\` → \`listDAVServers\`; \`binfiles\` → \`listBinFiles\` (list-only)
|
|
233
|
+
|
|
234
|
+
Each entity concept's **Operations** section lists its real operationIds (read straight from \`api.json\`). \`client.schema.validate()\` suggests the closest operationId for an unknown name.`
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
id: 'enums',
|
|
238
|
+
title: 'Common enums',
|
|
239
|
+
description: 'Priority and ticket status enum values.',
|
|
240
|
+
tags: ['reference'],
|
|
241
|
+
body: `Each entity concept's **Enums** section carries that entity's enums (parsed from the schema). The most-used:
|
|
242
|
+
|
|
243
|
+
**Priority** (tickets/tasks): \`0\`=LOWEST, \`1\`=LOW, \`2\`=MEDIUM, \`3\`=HIGH, \`4\`=HIGHEST.
|
|
244
|
+
|
|
245
|
+
**Ticket status**: \`0\`=NOT_STARTED, \`1\`=AWAITING_ACCEPTANCE, \`2\`=ACCEPTED, \`3\`=REJECTED, \`4\`=ACTIVE, \`5\`=INACTIVE, \`6\`=FEEDBACK_REQUIRED, \`7\`=TESTING, \`8\`=CANCELLED, \`9\`=COMPLETED, \`10\`=FAILED, \`11\`=BOOKED. Closed = IN [9, 11].
|
|
246
|
+
|
|
247
|
+
**Account type**: \`0\`=PROSPECT, \`1\`=CUSTOMER, \`2\`=SUPPLIER, \`3\`=CUSTOMERANDSUPPLIER, \`4\`=COMPETITOR, \`5\`=EMPLOYEE.`
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
id: 'counting-and-sums',
|
|
251
|
+
title: 'Counting and summing',
|
|
252
|
+
description: 'Count server-side; there is no server-side SUM.',
|
|
253
|
+
tags: ['query'],
|
|
254
|
+
body: `**Counts.** Use \`zeyos count <resource>\` (CLI) or \`count: true\` on the list call (client). Never \`list\` + array length: \`zeyos list\` defaults to \`--limit 50\`, so you get the page size, not the total (the only \`--json\` truncation signal is a stderr "Showing X–Y of TOTAL" hint).
|
|
255
|
+
|
|
256
|
+
**Sums.** There is no server-side SUM. \`list\` the matching rows with the numeric field at a high \`--limit\` (up to 10000) and add them up client-side.`
|
|
257
|
+
}
|
|
258
|
+
];
|