@vertesia/appgen-docs 1.5.0-dev.20260725.083715Z

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.
@@ -0,0 +1,220 @@
1
+ # App Package Processes
2
+
3
+ Use this when a Vertesia app needs to expose process definitions through its service package.
4
+
5
+ ## Registering Processes
6
+
7
+ App package processes are exposed as `InCodeProcessDefinition` objects registered on the tool server config.
8
+
9
+ For non-trivial processes, prefer a YAML/YML file as the app-owned source of truth. The service can load/parse that YAML into the native JSON `ProcessDefinitionBody` that Studio validates and installs. If you must keep the definition in TypeScript, keep it small, explicit, and validate it before publish.
10
+
11
+ ## Preferred YAML Source
12
+
13
+ ```yaml
14
+ format_version: 1
15
+ process: creative_ops_pipeline
16
+ description: Run the campaign creative operations workflow.
17
+ initial: brief_intake
18
+ context:
19
+ schema:
20
+ type: object
21
+ properties:
22
+ campaign_id:
23
+ type: string
24
+ asset_ids:
25
+ type: array
26
+ items:
27
+ type: string
28
+ approved:
29
+ type: boolean
30
+ notes:
31
+ type: string
32
+ additionalProperties: true
33
+ initial:
34
+ campaign_id: ""
35
+ asset_ids: []
36
+ approved: false
37
+ notes: ""
38
+ nodes:
39
+ brief_intake:
40
+ type: human_task
41
+ title: Brief intake
42
+ task:
43
+ title: Review campaign brief
44
+ description: Confirm the campaign is ready for creative production.
45
+ assignee: group:marketing-ops
46
+ fields:
47
+ - name: approved
48
+ label: Approved
49
+ type: boolean
50
+ required: true
51
+ - name: notes
52
+ label: Review notes
53
+ type: text
54
+ writes:
55
+ - approved
56
+ - notes
57
+ transitions:
58
+ - to: done
59
+ trigger: user
60
+ done:
61
+ type: final
62
+ title: Intake complete
63
+ ```
64
+
65
+ Register the parsed definition in `ServerConfig.processes`:
66
+
67
+ ```ts
68
+ import type { InCodeProcessDefinition, ProcessDefinitionBody } from '@vertesia/common';
69
+ import type { ToolServerConfig } from '@vertesia/tools-sdk';
70
+
71
+ const creativeOpsPipelineDefinition: ProcessDefinitionBody = {
72
+ format_version: 1,
73
+ process: 'creative_ops_pipeline',
74
+ description: 'Run the campaign creative operations workflow.',
75
+ initial: 'brief_intake',
76
+ context: {
77
+ schema: {
78
+ type: 'object',
79
+ properties: {
80
+ campaign_id: { type: 'string' },
81
+ asset_ids: { type: 'array', items: { type: 'string' } },
82
+ approved: { type: 'boolean' },
83
+ notes: { type: 'string' },
84
+ },
85
+ additionalProperties: true,
86
+ },
87
+ initial: {
88
+ campaign_id: '',
89
+ asset_ids: [],
90
+ approved: false,
91
+ notes: '',
92
+ },
93
+ },
94
+ nodes: {
95
+ brief_intake: {
96
+ type: 'human_task',
97
+ title: 'Brief intake',
98
+ task: {
99
+ title: 'Review campaign brief',
100
+ description: 'Confirm the campaign is ready for creative production.',
101
+ assignee: 'group:marketing-ops',
102
+ fields: [
103
+ { name: 'approved', label: 'Approved', type: 'boolean', required: true },
104
+ { name: 'notes', label: 'Review notes', type: 'text' },
105
+ ],
106
+ },
107
+ writes: ['approved', 'notes'],
108
+ transitions: [{ to: 'done', trigger: 'user' }],
109
+ },
110
+ done: {
111
+ type: 'final',
112
+ title: 'Intake complete',
113
+ },
114
+ },
115
+ };
116
+
117
+ export const processes = [
118
+ {
119
+ id: 'creative-ops-pipeline',
120
+ name: 'creative_ops_pipeline',
121
+ title: 'Creative Ops Pipeline',
122
+ description: 'Campaign creative operations workflow.',
123
+ tags: ['creative-ops'],
124
+ definition: creativeOpsPipelineDefinition,
125
+ },
126
+ ] satisfies InCodeProcessDefinition[];
127
+
128
+ export const ServerConfig = {
129
+ prefix: '/api',
130
+ processes,
131
+ // tools, interactions, types, dashboards, templates...
132
+ } satisfies ToolServerConfig;
133
+ ```
134
+
135
+ The app package endpoint serializes `ServerConfig.processes`:
136
+
137
+ - `GET /api/package?scope=processes` returns `{ processes: [...] }`.
138
+ - `GET /api/processes` lists registered processes.
139
+ - `GET /api/processes/:name` retrieves by `id`, `name`, or `definition.process`.
140
+
141
+ The standard `pnpm run service:build:server` package writer validates every packaged process before it writes `dist/app-package.json`. Always also run `validate_process_definition` on the parsed JSON definition while authoring so failures are found before publish. Treat validation failures as blocker app-code issues. The tool input is the native JSON definition, not the raw YAML string:
142
+
143
+ ```json
144
+ {
145
+ "definition": {
146
+ "format_version": 1,
147
+ "process": "creative_ops_pipeline",
148
+ "initial": "brief_intake",
149
+ "context": {
150
+ "schema": {
151
+ "type": "object",
152
+ "properties": {
153
+ "campaign_id": { "type": "string" },
154
+ "approved": { "type": "boolean" },
155
+ "notes": { "type": "string" }
156
+ },
157
+ "additionalProperties": true
158
+ },
159
+ "initial": {
160
+ "campaign_id": "",
161
+ "approved": false,
162
+ "notes": ""
163
+ }
164
+ },
165
+ "nodes": {
166
+ "brief_intake": {
167
+ "type": "human_task",
168
+ "task": {
169
+ "title": "Review campaign brief",
170
+ "fields": [
171
+ { "name": "approved", "type": "boolean", "required": true },
172
+ { "name": "notes", "type": "text" }
173
+ ]
174
+ },
175
+ "writes": ["approved", "notes"],
176
+ "transitions": [{ "to": "done", "trigger": "user" }]
177
+ },
178
+ "done": { "type": "final" }
179
+ }
180
+ }
181
+ }
182
+ ```
183
+
184
+ ## Shape
185
+
186
+ `InCodeProcessDefinition`:
187
+
188
+ ```ts
189
+ interface InCodeProcessDefinition {
190
+ id: string;
191
+ name: string;
192
+ title?: string;
193
+ description?: string;
194
+ tags?: string[];
195
+ definition: ProcessDefinitionBody;
196
+ }
197
+ ```
198
+
199
+ `ProcessDefinitionBody` requires:
200
+
201
+ - `format_version: 1`
202
+ - `process`: stable process name
203
+ - `initial`: first node id
204
+ - `context: { schema, initial }`
205
+ - `nodes`: record of node ids to process nodes
206
+
207
+ Common node types are `tool`, `interaction`, `agent`, `script`, `human_task`, `foreach`, `branch`, `condition`, `process`, and `final`.
208
+
209
+ Transition rules:
210
+
211
+ - Use `transitions: [{ to: "node_id" }]`; do not use `target`.
212
+ - `branch` and `condition` nodes use `branches: [{ to: "node_id" }]`.
213
+ - A `human_task` node must include `task.title` and `task.fields`; fields support `string`, `number`, `boolean`, `select`, and `text`.
214
+ - A `script` node references an embedded bundle in top-level `resources.scripts`. Scripts read `VERTESIA_PROCESS_INPUT`, write JSON to `VERTESIA_PROCESS_RESULT`, and may place artifacts under `VERTESIA_PROCESS_OUT_DIR`. JavaScript and TypeScript sandboxes include `@vertesia/client`; import it without adding it to the resource's packages.
215
+
216
+ ## App Manifest
217
+
218
+ When publishing a service app that exposes processes, ensure the app manifest/capabilities include `processes` and publish with `target: "service"`.
219
+
220
+ Studio normalizes app process ids to `app:<app-name>:<id>` when returning installed app processes.
@@ -0,0 +1,80 @@
1
+ # App-Owned Types
2
+
3
+ Use app-owned in-code type definitions for schema owned by the generated app. Do not create tenant-local stored content types for product-owned schema unless the user explicitly asks for project-local configuration.
4
+
5
+ ## Type refs
6
+
7
+ Use stable app refs in runtime data and UI code:
8
+
9
+ ```ts
10
+ const APP_NAME = 'my-business-app'; // MUST equal package.json name === VITE_APP_NAME === manifest name
11
+ const CASE_TYPE = `app:${APP_NAME}:case`;
12
+ const TASK_TYPE = `app:${APP_NAME}:task`;
13
+ ```
14
+
15
+ > **App-owned types are in-code strings, not ObjectIds.** A Store object's `type` is EITHER a stored-type ObjectId OR an in-code-type string `app:<app-name>:<local>`. Portable apps MUST pass the in-code string directly to `objects.create`/`objects.search` — the platform resolves it from the app package (including during preview, for the app owner, before install). NEVER resolve an app-owned type to a project-local ObjectId (e.g. a `types.list({ name })`→id lookup or a `useTypeIds` hook): that bakes in one project's id and breaks the app the moment it is installed anywhere else. Derive every `app:` ref from the single `APP_NAME` constant; never paste the literal app name into a ref.
16
+
17
+ > **For TYPES, `<local>` is the declared type `name` — bare, no collection segment.** `app:<name>:case` is correct; `app:<name>:cases:case` is only a legacy alias. The `ContentTypesCollection` is code organization, not identity, so type names MUST be unique across collections (the package build fails on duplicates). This differs from interactions/activities, whose ids DO include the collection (`app:<name>:<collection>:<interaction>`).
18
+
19
+ When creating or searching Store objects, pass the app type code string:
20
+
21
+ ```ts
22
+ await client.objects.create({
23
+ type: CASE_TYPE,
24
+ properties: {
25
+ title: 'Supplier review',
26
+ status: 'open',
27
+ seed_marker: `appgen:${APP_NAME}`,
28
+ },
29
+ });
30
+
31
+ const { results } = await client.objects.search({
32
+ query: {
33
+ type: CASE_TYPE,
34
+ match: { 'properties.seed_marker': `appgen:${APP_NAME}` },
35
+ },
36
+ limit: 50,
37
+ });
38
+ ```
39
+
40
+ ## Package source
41
+
42
+ Define package types under `src/modules/app/resources/types/<domain>/index.ts` and export their collection from `src/modules/app/resources/types/index.ts`. Generated module wiring includes that array in `ServerConfig.types`.
43
+
44
+ ```ts
45
+ import type { InCodeTypeSpec } from '@vertesia/common';
46
+ import { ContentTypesCollection } from '@vertesia/tools-sdk';
47
+
48
+ const caseType = {
49
+ name: 'case',
50
+ title: 'Compliance Case',
51
+ description: 'App-owned case record.',
52
+ tags: ['compliance'],
53
+ object_schema: {
54
+ type: 'object',
55
+ properties: {
56
+ title: { type: 'string' },
57
+ status: { type: 'string' },
58
+ owner: { type: 'string' },
59
+ seed_marker: { type: 'string' },
60
+ },
61
+ required: ['title', 'status'],
62
+ },
63
+ } satisfies InCodeTypeSpec;
64
+
65
+ export const ComplianceTypes = new ContentTypesCollection({
66
+ name: 'compliance',
67
+ title: 'Compliance Types',
68
+ types: [caseType],
69
+ });
70
+ ```
71
+
72
+ `src/modules/app/resources/types/index.ts`:
73
+
74
+ ```ts
75
+ import { ComplianceTypes } from './compliance/index.js';
76
+
77
+ export const types = [ComplianceTypes];
78
+ ```
79
+
80
+ Keep generated apps portable: schema and behavior live in the app package; seeded records live in the Store and use installed app type refs.
@@ -0,0 +1,94 @@
1
+ # Store Object Search And Seeding
2
+
3
+ Use the Vertesia client from `useUserSession()` in browser code and the injected token/client in app workspace scripts. Prefer `client.objects.search` over list/find guessing.
4
+
5
+ App-owned types are referenced by their **in-code string** `app:<app-name>:<local>`, never a resolved ObjectId — pass the string straight to `search`/`create` and derive it from a single `APP_NAME` constant (= package.json name = VITE_APP_NAME = manifest name) so the app stays portable. See `package-types.md` for the rule.
6
+
7
+ ## Search
8
+
9
+ ```ts
10
+ const APP_NAME = 'my-app'; // = package.json name = VITE_APP_NAME = manifest name
11
+ const CASE_TYPE = `app:${APP_NAME}:case`;
12
+
13
+ const { results, count } = await client.objects.search({
14
+ query: {
15
+ type: CASE_TYPE,
16
+ match: { 'properties.seed_marker': `appgen:${APP_NAME}` },
17
+ },
18
+ limit: 100,
19
+ offset: 0,
20
+ });
21
+ ```
22
+
23
+ For text search:
24
+
25
+ ```ts
26
+ const { results } = await client.objects.search({
27
+ query: {
28
+ type: CASE_TYPE,
29
+ full_text: searchText,
30
+ match: { 'properties.status': 'open' },
31
+ },
32
+ limit: 25,
33
+ });
34
+ ```
35
+
36
+ ## Idempotent seed
37
+
38
+ Always mark generated records so they can be counted, updated, and cleaned up safely.
39
+
40
+ ```ts
41
+ import type { VertesiaClient } from '@vertesia/client';
42
+
43
+ const APP_NAME = 'my-app';
44
+ const SEED_MARKER = `appgen:${APP_NAME}`;
45
+ const CASE_TYPE = `app:${APP_NAME}:case`;
46
+
47
+ async function seedCase(client: VertesiaClient, record: { external_id: string; title: string }) {
48
+ const existing = await client.objects.search({
49
+ query: {
50
+ type: CASE_TYPE,
51
+ match: {
52
+ 'properties.seed_marker': SEED_MARKER,
53
+ 'properties.external_id': record.external_id,
54
+ },
55
+ },
56
+ limit: 1,
57
+ });
58
+
59
+ if (existing.results?.[0]?.id) {
60
+ return client.objects.update(existing.results[0].id, {
61
+ properties: { ...record, seed_marker: SEED_MARKER },
62
+ });
63
+ }
64
+
65
+ return client.objects.create({
66
+ type: CASE_TYPE,
67
+ properties: { ...record, seed_marker: SEED_MARKER },
68
+ });
69
+ }
70
+ ```
71
+
72
+ ## Markdown source content
73
+
74
+ For document, review, and intake apps, attach realistic source content to representative objects instead of only creating properties.
75
+
76
+ ```ts
77
+ await client.objects.create({
78
+ type: `app:${APP_NAME}:evidence`,
79
+ properties: {
80
+ title: 'Screening evidence',
81
+ seed_marker: SEED_MARKER,
82
+ },
83
+ text: [
84
+ '# Screening Evidence',
85
+ '',
86
+ 'Denied party screening completed for shipment GTC-1001.',
87
+ '',
88
+ '- Result: potential hit',
89
+ '- Reviewer: trade compliance',
90
+ ].join('\n'),
91
+ });
92
+ ```
93
+
94
+ If the exact source attachment API differs in the installed SDK, write the intended create code first, then run `app_workspace_typecheck` and fix from compiler diagnostics. Do not spend more than five docs lookups rediscovering the object shape.