@gzl10/nexus-backend 0.20.0 → 0.21.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.
@@ -0,0 +1,69 @@
1
+ # Catalogar cambios en tabla supletoria `nexus` de Neural
2
+
3
+ Detecta cambios recientes en SDK, backend modules, y UI composables que deban reflejarse en la tabla supletoria `nexus` de Neural (`nexus_upsert`). Actualiza registros existentes o crea nuevos.
4
+
5
+ ## Argumentos
6
+
7
+ $ARGUMENTS — Opcional. Scope específico: `sdk`, `backend`, `ui`, `all`. Default: `all`.
8
+
9
+ ## Paso 1: Detectar cambios
10
+
11
+ Comparar estado actual vs último commit/tag para identificar qué cambió:
12
+
13
+ ```bash
14
+ # Si hay argumento de scope, filtrar por paquete
15
+ # all → revisar los 3 paquetes
16
+ git diff HEAD~5 --name-only -- packages/sdk/src/ packages/backend/src/modules/ packages/ui/src/composables/
17
+ ```
18
+
19
+ Clasificar cada cambio detectado:
20
+
21
+ | Cambio en... | Categoría nexus | Acción |
22
+ |---|---|---|
23
+ | `sdk/src/types/entity.ts` (entity types) | `entity_type` | Upsert definición |
24
+ | `sdk/src/types/fields.ts` (field types) | `db_type` o `input_type` | Upsert tipo |
25
+ | `sdk/src/fields/*.ts` (factories) | `field_factory` | Upsert factory |
26
+ | `backend/src/modules/*/` (patterns) | `pattern` | Upsert pattern si es reutilizable |
27
+ | `ui/src/composables/*.ts` | `pattern` | Upsert si es API pública para devs externos |
28
+
29
+ ## Paso 2: Consultar estado actual en Neural
30
+
31
+ Para cada cambio detectado, buscar si ya existe en la tabla:
32
+
33
+ ```
34
+ nexus_search(category: "...", query: "nombre")
35
+ ```
36
+
37
+ Comparar el `summary` existente con el código actual. Si no hay cambios sustanciales, saltar.
38
+
39
+ ## Paso 3: Upsert en Neural
40
+
41
+ Para cada registro nuevo o modificado, usar `nexus_upsert`.
42
+
43
+ **Reglas de redacción del `summary`:**
44
+
45
+ - Pensando en dos audiencias simultáneas:
46
+ 1. **Dev de app** (usa nexus-backend + nexus-ui): qué es, cuándo usarlo, config mínima
47
+ 2. **Dev de plugin** (crea nexus-plugin-*): cómo usarlo desde ctx, integración con engine, gotchas
48
+ - Incluir: propósito, cuándo usar, config/parámetros principales, y advertencias
49
+ - NO incluir código extenso — solo snippets mínimos si clarifican uso
50
+ - Tags descriptivos para filtrado (ej: `crud`, `factory`, `hooks`, `auth`, `sdk`, `how-to`)
51
+
52
+ ## Paso 4: Reportar
53
+
54
+ Mostrar resumen de cambios:
55
+
56
+ | Acción | Categoría | Nombre | Motivo |
57
+ |---|---|---|---|
58
+ | created | field_factory | useMarkdownField | Nuevo factory añadido |
59
+ | updated | pattern | EntityServiceHooks | Añadido hook beforeValidate |
60
+ | skipped | entity_type | collection | Sin cambios |
61
+
62
+ ## Destinos de documentación (referencia)
63
+
64
+ La tabla `nexus` alimenta estos tutoriales en Notion KB:
65
+
66
+ - [Tutorial: App basada en Nexus](https://www.notion.so/3234fc3785408042be6bf648a2876c54)
67
+ - [Tutorial: Plugin para Nexus](https://www.notion.so/3234fc37854080d9a5dece31975385d2)
68
+
69
+ La sincronización Neural → Notion se hace con `/neural-sync-notion`, NO desde este command.
@@ -32,13 +32,13 @@ Find which module to add the action to:
32
32
  Create `src/modules/{module}/actions/{name}.action.ts`:
33
33
 
34
34
  ```typescript
35
- import type { ActionDefinition, ModuleContext, Request, Response } from '@gzl10/nexus-sdk'
36
- import { useTextField, useSelectField } from '@gzl10/nexus-sdk/fields'
35
+ import type { ActionDefinition } from '@gzl10/nexus-sdk'
36
+ import { useSelectField } from '@gzl10/nexus-sdk/fields'
37
37
 
38
38
  export const {camelName}Action: ActionDefinition = {
39
- name: '{kebab-name}',
39
+ key: '{kebab-name}',
40
40
  label: { en: '{Label}', es: '{Etiqueta}' },
41
- icon: '{icon}',
41
+ icon: 'mdi:{icon}',
42
42
  scope: '{scope}', // 'module' | 'entity' | 'row'
43
43
  variant: 'primary',
44
44
 
@@ -53,14 +53,14 @@ export const {camelName}Action: ActionDefinition = {
53
53
  })
54
54
  },
55
55
 
56
- // Handler
57
- handler: (ctx: ModuleContext) => async (req: Request, res: Response) => {
58
- const { format } = req.body
56
+ // Handler — signature: (ctx, input, req?, res?) => Promise<unknown>
57
+ handler: async (ctx, input) => {
58
+ const { format } = input as { format: string }
59
59
 
60
60
  // Action logic here
61
61
  // Use ctx.db, ctx.services, ctx.logger, ctx.errors
62
62
 
63
- res.json({ success: true, message: 'Action completed' })
63
+ return { success: true, message: 'Action completed' }
64
64
  },
65
65
 
66
66
  casl: {
@@ -91,9 +91,14 @@ npx tsc --noEmit
91
91
 
92
92
  ## Gotchas
93
93
 
94
- - Actions use `handler: (ctx) => async (req, res) => {}` — factory pattern like hooks
95
- - `scope: 'row'` actions receive `req.params.id`
94
+ - Handler signature: `handler: async (ctx, input, req?, res?) => {}` — direct function, NOT factory pattern
95
+ - Hooks use factory pattern `(ctx) => ({...})`, but action handlers do NOT
96
+ - `key` is the route identifier (NOT `name`)
97
+ - `scope: 'row'` actions receive `req.params.id` — import `AuthRequest` from SDK if you need `req`
96
98
  - `input` defines the form shown before execution (Record<string, FieldDefinition>)
97
99
  - `output: {}` shows raw JSON result, `output` with fields shows structured modal
98
100
  - `batch: true` + `timeout: number` for batch processing with SSE progress
99
101
  - `disabled` accepts `FieldCondition` for per-row client-side evaluation
102
+ - `hidden: true` makes the action API-only (not shown in UI)
103
+ - `inputSchema` accepts a Zod schema for server-side validation
104
+ - Icons use Iconify format: `mdi:play`, `mdi:export`, etc.
@@ -129,7 +129,7 @@ definitions: [...existing, {name}Entity]
129
129
  ## Step 5: Run migration
130
130
 
131
131
  ```bash
132
- npx nexus migrate dev
132
+ pnpm nexus migrate dev
133
133
  ```
134
134
 
135
135
  ## Gotchas
@@ -27,7 +27,7 @@ ls src/modules/
27
27
  Ask the user (if not provided in arguments):
28
28
 
29
29
  1. **Category** — one of: content, data, assets, messaging, jobs, ai, analytics, integrations, commerce, security, legal, settings
30
- 2. **Icon** — Ionicons 5 icon name (suggest based on category)
30
+ 2. **Icon** — Iconify icon name with `mdi:` prefix (e.g. `mdi:cart`, `mdi:chart-bar`). Suggest based on category
31
31
  3. **Initial entity?** — yes/no. If yes, ask type: collection, single, or tree
32
32
 
33
33
  ## Step 3: Generate module
@@ -41,7 +41,7 @@ import type { ModuleManifest } from '@gzl10/nexus-sdk'
41
41
  export const {name}Module: ModuleManifest = {
42
42
  name: '{name}',
43
43
  label: { en: '{Name}', es: '{Nombre}' },
44
- icon: '{icon}',
44
+ icon: 'mdi:{icon}',
45
45
  category: '{category}',
46
46
  definitions: []
47
47
  }
@@ -65,7 +65,7 @@ Add the entity import and include it in `definitions[]`.
65
65
  ## Step 5: Verify
66
66
 
67
67
  ```bash
68
- npx tsc --noEmit
68
+ pnpm typecheck
69
69
  ```
70
70
 
71
71
  ## Gotchas
@@ -100,13 +100,17 @@ export default defineConfig({
100
100
  ### src/index.ts
101
101
 
102
102
  ```typescript
103
+ import { readFileSync } from 'node:fs'
104
+ import { join } from 'node:path'
103
105
  import type { PluginManifest, ModuleManifest } from '@gzl10/nexus-sdk'
104
106
  import { {name}Entity } from './entities/{name}.js'
105
107
 
108
+ const pkg = JSON.parse(readFileSync(join(import.meta.dirname, '..', 'package.json'), 'utf-8')) as { name: string; version: string }
109
+
106
110
  const {name}Module: ModuleManifest = {
107
111
  name: '{name}',
108
112
  label: { en: '{Name}', es: '{Nombre}' },
109
- icon: '{icon}',
113
+ icon: 'mdi:{icon}',
110
114
  category: '{category}',
111
115
  definitions: [{name}Entity]
112
116
  }
@@ -114,11 +118,11 @@ const {name}Module: ModuleManifest = {
114
118
  export { {name}Module, {name}Entity }
115
119
 
116
120
  export const {name}Plugin: PluginManifest = {
117
- name: '@{scope}/nexus-plugin-{name}',
121
+ name: pkg.name,
118
122
  code: '{code}',
119
123
  label: { en: '{Name}', es: '{Nombre}' },
120
- icon: '{icon}',
121
- version: '1.0.0',
124
+ icon: 'mdi:{icon}',
125
+ version: pkg.version,
122
126
  description: { en: '{description_en}', es: '{description_es}' },
123
127
  category: '{category}',
124
128
  modules: [{name}Module]
@@ -147,7 +151,8 @@ pnpm typecheck
147
151
 
148
152
  - `code` must be exactly 3 lowercase chars — validated by `registerPlugin()`
149
153
  - `export default` the PluginManifest (plugins use default export, modules use named)
154
+ - **NEVER hardcode `name` or `version`** — read from `package.json` with `readFileSync`
150
155
  - `peerDependencies` on `@gzl10/nexus-sdk` — not direct dependency
151
156
  - `files: ["dist", "migrations"]` — include migrations dir even if empty initially
152
- - Plugin name in PluginManifest.name must match package.json name exactly
157
+ - Icons use Iconify format: `mdi:bookmark`, `mdi:chart-bar`, etc.
153
158
  - Users install with `nexus plugin add`, not `pnpm add`
@@ -0,0 +1,220 @@
1
+ # Nexus Module Review
2
+
3
+ Analyzes a nexus-ui module page (screenshot or module name) and suggests improvements to EntityDefinition, fields, actions, and display modes based on backend metadata.
4
+
5
+ ## Arguments
6
+
7
+ $ARGUMENTS — Module to review. Accepts:
8
+ - A **screenshot** (user pastes image or provides path) — vision identifies the module
9
+ - A **module name** (e.g. "contacts", "inventory") — skips screenshot analysis
10
+ - Empty — ask the user for a screenshot or module name
11
+
12
+ ## Context detection
13
+
14
+ Detect execution context by inspecting the working directory:
15
+
16
+ | Check | Context | Metadata source |
17
+ |-------|---------|-----------------|
18
+ | `packages/backend/package.json` with `@gzl10/nexus-backend` | **Monorepo** | Read EntityDefinition from source files |
19
+ | `package.json` has `@gzl10/nexus-backend` dep | **Project** | Read EntityDefinition from source files |
20
+ | Neither | **Remote** | Fetch manifest from API (`GET /api/v1/system/manifest`) |
21
+
22
+ For **Remote** mode, ask the user for the backend URL if not provided.
23
+
24
+ ## Step 1: Identify module
25
+
26
+ ### From screenshot
27
+
28
+ Read the image with the Read tool. Extract:
29
+ - **Module name**: from header, sidebar highlight, or breadcrumb
30
+ - **Active entity tab**: which entity is currently displayed
31
+ - **Display mode**: table, board, list, masonry, tree, calendar, timeline
32
+ - **Visible columns/fields**: field names from table headers or card content
33
+ - **Visible actions**: buttons in toolbar, row dropdown items
34
+ - **Data state**: how many rows visible, empty columns, patterns in data
35
+ - **UI issues**: anything visually off (truncation, overflow, empty space, alignment)
36
+
37
+ ### From module name
38
+
39
+ If the user provides a name directly, skip vision and go to Step 2.
40
+
41
+ ## Step 2: Load entity metadata
42
+
43
+ ### Monorepo / Project mode (preferred)
44
+
45
+ 1. Find the module definition:
46
+ ```
47
+ Grep for: export const {moduleName}Module | name: '{moduleName}'
48
+ In: packages/backend/src/modules/ OR src/modules/ OR demos/*/src/modules/
49
+ Also check: plugins/*/src/index.ts (for plugin entities)
50
+ ```
51
+
52
+ 2. Read the module's `index.ts` — extract:
53
+ - All `EntityDefinition` objects (definitions array)
54
+ - All `ActionDefinition` objects (actions array + entity.actions)
55
+ - Module manifest metadata (label, icon, category)
56
+
57
+ 3. For each entity, catalog:
58
+ - **Fields**: name, input type, `db.type`, `meta.showInDisplay`, `meta.showInForm`, `meta.searchable`, `meta.sortable`
59
+ - **Display config**: `displayMode`, `availableDisplayModes`, `groupBy`, `groupableFields`, `calendarFrom/To`, `defaultSort`
60
+ - **CRUD flags**: `allowCreate`, `allowEdit`, `allowDelete`, `hidden`
61
+ - **Features**: `taggeable`, `attachable`, `realtime`, `refreshInterval`
62
+ - **Actions**: scope (module/entity/row), label, variant, disabled condition, batch
63
+ - **CASL**: subject, sensitiveFields, permissions wildcards
64
+
65
+ ### Remote mode (fallback)
66
+
67
+ Fetch `GET {baseUrl}/api/v1/system/manifest` (no auth needed for public capabilities, but manifest needs auth).
68
+
69
+ If auth needed:
70
+ ```bash
71
+ nexus client login --url {baseUrl}
72
+ nexus client fetch GET /api/v1/system/manifest
73
+ ```
74
+
75
+ Parse the ManifestDTO — it contains the same metadata serialized via `toEntityDefinitionDTO`.
76
+
77
+ ## Step 3: Analyze and generate findings
78
+
79
+ Cross-reference the visible UI (from screenshot) with entity metadata. If no screenshot, analyze metadata standalone for common issues.
80
+
81
+ ### Analysis categories
82
+
83
+ Run through each category. Only report genuine findings, not noise.
84
+
85
+ #### 3.1 Display mode fitness
86
+
87
+ | Check | Finding |
88
+ |-------|---------|
89
+ | Entity has select/enum fields but no BoardDisplay available | Suggest adding to `availableDisplayModes` + `groupableFields` |
90
+ | Entity has date/datetime fields but no CalendarDisplay | Suggest `calendarFrom`/`calendarTo` config |
91
+ | Entity has `created_at` + temporal data but no TimelineDisplay | Suggest as available mode |
92
+ | Entity type is tree/dag but default display is table | Suggest tree as default |
93
+ | `availableDisplayModes` is restricted but useful modes are excluded | Suggest expanding |
94
+
95
+ #### 3.2 Field visibility
96
+
97
+ | Check | Finding |
98
+ |-------|---------|
99
+ | Field with `showInDisplay: true` (or default) but provides little value in tables (e.g., long text, JSON, description) | Suggest `showInDisplay: false` |
100
+ | Field important for identification not shown in display (e.g., email, status, type) | Suggest `showInDisplay: true` |
101
+ | Too many columns visible (>8 in table) — information overload | Suggest hiding less important ones |
102
+ | Too few columns visible (<3) — table feels empty | Suggest showing more relevant fields |
103
+ | `labelField` not set or points to a non-descriptive field | Suggest better `labelField` |
104
+ | Password/secret field without `sensitiveFields` in CASL | Flag security issue |
105
+
106
+ #### 3.3 Search and sort
107
+
108
+ | Check | Finding |
109
+ |-------|---------|
110
+ | No `defaultSort` configured | Suggest by most recent (if timestamps) or alphabetical (if labelField) |
111
+ | Fields that should be searchable but `searchable: false` | Suggest enabling |
112
+ | Fields that should be sortable but `sortable: false` | Suggest enabling |
113
+ | No fields marked as `searchable` | Suggest at least labelField + key identifier fields |
114
+
115
+ #### 3.4 Actions review
116
+
117
+ | Check | Finding |
118
+ |-------|---------|
119
+ | Row action that doesn't need the row ID (e.g., "Export all") | Suggest entity or module scope instead |
120
+ | Entity/module action that logically operates on a single record | Suggest row scope |
121
+ | Action without clear label or with generic label ("Execute", "Run") | Suggest descriptive label |
122
+ | Batch-capable action not marked `batch: true` | Suggest enabling batch |
123
+ | Destructive action without `variant: 'danger'` | Suggest adding danger variant |
124
+ | Action with `ConfirmConfig` but confirm message is generic | Suggest specific message |
125
+ | Many row actions (>4) — dropdown gets long | Suggest grouping or hiding less-used ones |
126
+
127
+ #### 3.5 Entity configuration
128
+
129
+ | Check | Finding |
130
+ |-------|---------|
131
+ | Collection without `timestamps: true` | Suggest adding (audit trail) |
132
+ | Entity with delete but no `softDelete` for important data | Suggest soft delete |
133
+ | Entity with `realtime: false` that would benefit from live updates | Suggest `'sync'` or `'live'` |
134
+ | Entity suitable for tags but `taggeable` not set | Suggest enabling |
135
+ | Entity with file references but `attachable` not set | Suggest enabling |
136
+ | `expose: true` (default) for internal/auxiliary entities | Suggest `expose: false` or `hidden: true` |
137
+ | Entity with only 1-2 records that should be `single` type | Suggest type change |
138
+
139
+ #### 3.6 Screenshot-specific (only when screenshot provided)
140
+
141
+ | Check | Finding |
142
+ |-------|---------|
143
+ | Empty columns visible in >70% of rows | Suggest `showInDisplay: false` or rethink field |
144
+ | Data truncated in columns (ellipsis visible) | Suggest wider column or `showInDisplay: false` |
145
+ | Actions visible that don't make sense in current context | Investigate scope mismatch |
146
+ | Missing pagination or infinite scroll with many rows | Check pagination config |
147
+ | No search bar visible for a collection with many records | Check toolbar rendering |
148
+ | Inconsistent date formats | Check field input type |
149
+
150
+ ## Step 4: Present findings
151
+
152
+ Group findings by priority and category:
153
+
154
+ ```markdown
155
+ ## Module Review: {moduleName}
156
+
157
+ ### Entity: {entityName} ({type})
158
+
159
+ #### High impact
160
+ - [display] {finding with specific suggestion and code change}
161
+ - [fields] {finding}
162
+
163
+ #### Medium impact
164
+ - [actions] {finding}
165
+ - [search] {finding}
166
+
167
+ #### Low impact / Nice-to-have
168
+ - [config] {finding}
169
+
170
+ ### Suggested changes
171
+
172
+ For each high/medium finding, show the specific code change:
173
+
174
+ **{entity}.fields.{field}:**
175
+ ```typescript
176
+ // Current (inferred)
177
+ meta: { showInDisplay: true }
178
+ // Suggested
179
+ meta: { showInDisplay: false } // Long text, rarely useful in table view
180
+ ```
181
+ ```
182
+
183
+ ## Step 5: Apply changes (optional)
184
+
185
+ After presenting findings, ask:
186
+
187
+ ```
188
+ {N} findings found. Options:
189
+ [1] Apply high-impact changes (I'll edit the EntityDefinition files)
190
+ [2] Create work items in Plane for manual review
191
+ [3] Just the report, thanks
192
+ ```
193
+
194
+ - **Option 1**: Edit the source files directly. Only for monorepo/project mode.
195
+ - **Option 2**: Create work items using Plane tools (like neural-review).
196
+ - **Option 3**: Done.
197
+
198
+ For option 2, create a single work item with all findings:
199
+
200
+ ```
201
+ mcp__neural__plane_work_item_create(
202
+ workspace_slug, project_id,
203
+ name: "review: {moduleName} module UI/DX improvements",
204
+ description_html: "{findings as HTML list}",
205
+ priority: "medium"
206
+ )
207
+ ```
208
+
209
+ Assign to the relevant module in Plane (`plane_module_add_work_items`).
210
+
211
+ ## Rules
212
+
213
+ - **Do NOT change entity types** (collection to single, etc.) without explicit user approval
214
+ - **Do NOT remove fields** — only suggest visibility changes
215
+ - **Do NOT modify CASL permissions** — only flag security issues
216
+ - **Do NOT touch migrations** — only EntityDefinition metadata
217
+ - **Be specific**: every finding must include the exact field/action/config and the suggested change
218
+ - **No false positives**: if unsure, skip. Quality over quantity
219
+ - **Context matters**: a CRM module has different needs than an audit log. Adapt heuristics
220
+ - **Multiple screenshots**: if the user provides more screenshots of the same module (different tabs, scroll positions), accumulate findings across all of them
@@ -0,0 +1,194 @@
1
+ # Nexus Manual Tester
2
+
3
+ Interactive testing via nexus-client against a running (or auto-started) backend.
4
+
5
+ ## Arguments
6
+
7
+ $ARGUMENTS — What to test (e.g. "create a contact, verify it exists, delete it"). If empty, ask the user. If the user says "en la demo" or similar, use demo mode (see below).
8
+
9
+ ## Context detection
10
+
11
+ Detect the execution context by inspecting the working directory:
12
+
13
+ | Check | Context | CLI prefix | Notes |
14
+ |-------|---------|-----------|-------|
15
+ | `packages/backend/package.json` exists with `@gzl10/nexus-backend` | **Monorepo** | see below | Nexus monorepo development |
16
+ | Otherwise | **Project** | `pnpm nexus` or `npx nexus` | External project using Nexus |
17
+
18
+ **Monorepo sub-modes** (detected from $ARGUMENTS):
19
+
20
+ | Mode | Trigger | CLI prefix | Target |
21
+ |------|---------|-----------|--------|
22
+ | **Core** (default) | No demo/plugin mention | `pnpm nexus` | `packages/backend` |
23
+ | **Demo** | "en la demo", "demo", "demo-backend", or when testing plugins | `pnpm nexus:demo` | `demos/demo-backend` |
24
+
25
+ **Project context:** Use `pnpm nexus` if `nexus` is in local devDependencies, otherwise `npx nexus`. Backend start command: whatever `scripts.dev` is in `package.json`.
26
+
27
+ Throughout the steps below, `$CLI` refers to the resolved CLI prefix.
28
+
29
+ ## Plugin testing rule
30
+
31
+ **In monorepo context:** Plugins MUST be tested in demo mode only (`pnpm nexus:demo` / `demos/demo-backend`). NEVER install or activate plugins in the core backend (`packages/backend`). If the user asks to test a plugin without mentioning "demo", auto-select demo mode and inform them.
32
+
33
+ **In project context:** Plugins are tested directly (the project IS the app).
34
+
35
+ Before testing a plugin:
36
+
37
+ 1. **Verify the plugin is installed and enabled:**
38
+ ```bash
39
+ $CLI plugin list
40
+ ```
41
+ If the plugin is not listed or not enabled, install/enable it first:
42
+ ```bash
43
+ $CLI plugin add <plugin-name>
44
+ $CLI plugin enable <plugin-name>
45
+ ```
46
+
47
+ 2. **Run pending migrations:**
48
+ ```bash
49
+ $CLI migrate deploy
50
+ ```
51
+
52
+ 3. Only then proceed with testing.
53
+
54
+ ## Step 0: Discover available endpoints
55
+
56
+ Read the REST Client files to understand what endpoints and payloads are available:
57
+
58
+ - **Monorepo core:** `packages/backend/requests/*.http`
59
+ - **Monorepo demo:** `demos/demo-backend/requests/*.http` (if exists), plus core requests
60
+ - **Monorepo plugins:** `plugins/*/requests/*.http`
61
+ - **Project:** `requests/*.http` (if exists)
62
+
63
+ Use these as reference for endpoint paths, expected payloads, and authentication patterns.
64
+
65
+ ## Step 1: Build (if needed) and ensure backend is running
66
+
67
+ **Monorepo demo mode only:** Build core packages if dist directories are missing:
68
+
69
+ ```bash
70
+ pnpm build --filter @gzl10/nexus-sdk --filter @gzl10/nexus-backend --filter @gzl10/nexus-client --filter @gzl10/nexus-ui
71
+ ```
72
+
73
+ Check if the backend is reachable:
74
+
75
+ ```bash
76
+ $CLI client health
77
+ ```
78
+
79
+ If it fails (connection refused), start the backend in background:
80
+
81
+ - **Monorepo core:** `cd packages/backend && pnpm dev &`
82
+ - **Monorepo demo:** `cd demos/demo-backend && pnpm dev &`
83
+ - **Project:** `pnpm dev &` (from project root)
84
+
85
+ Wait until `$CLI client health` succeeds (poll every 2s, max 30s).
86
+
87
+ Record whether we started the backend (to shut it down at the end).
88
+
89
+ ## Step 2: Login
90
+
91
+ ```bash
92
+ $CLI client login [email] [password]
93
+ ```
94
+
95
+ - If credentials provided in $ARGUMENTS, use those
96
+ - If not, defaults from .env (ADMIN_EMAIL / ADMIN_PASSWORD) are used automatically
97
+ - If no defaults, ask the user
98
+
99
+ Session is persisted via PAT in `~/.nexus/session.json` indexed by project path — no expiration, survives across commands, supports multiple projects.
100
+
101
+ Confirm login succeeded (check output for user JSON).
102
+
103
+ ## Step 3: Execute operations
104
+
105
+ Translate the user's instructions into nexus CLI calls:
106
+
107
+ ```bash
108
+ $CLI client entity <module/entity> <action> [args]
109
+ ```
110
+
111
+ Available commands:
112
+
113
+ **Entity CRUD:**
114
+
115
+ - `$CLI client entity <path> list` — list entities
116
+ - `$CLI client entity <path> get <id>` — get by ID
117
+ - `$CLI client entity <path> create '<json>'` — create
118
+ - `$CLI client entity <path> update <id> '<json>'` — update
119
+ - `$CLI client entity <path> delete <id>` — delete
120
+
121
+ **Actions (module/entity/row):**
122
+
123
+ - `$CLI client action <module> <key> ['<json>']` — module action (POST by default)
124
+ - `$CLI client action <module> <key> <id> ['<json>']` — row action
125
+ - `$CLI client action <module> <key> -m GET` — read action (e.g. sessions, list-tokens)
126
+
127
+ **Generic HTTP (any endpoint):**
128
+
129
+ - `$CLI client fetch <METHOD> <url> ['<json>']` — hit any endpoint
130
+ - `$CLI client fetch GET /auth/me` — example read
131
+ - `$CLI client fetch POST /mail/send '{"to":"x"}'` — example write
132
+ - `$CLI client fetch GET /some/endpoint --pat <token>` — bypass session, use PAT directly
133
+
134
+ **Other:**
135
+
136
+ - `$CLI client health` — health check
137
+ - `$CLI client login [email] [password]` — authenticate (creates PAT)
138
+ - `$CLI client me` — current user info
139
+
140
+ **Command selection guide:**
141
+ - **entity** — CRUD on entities (list, get, create, update, delete)
142
+ - **action** — declared actions in modules/plugins (have a key, may need body or row id)
143
+ - **fetch** — anything else (custom routes, plugin endpoints, non-standard paths)
144
+
145
+ Use `--debug` flag on any command for verbose HTTP logging.
146
+
147
+ For each operation:
148
+ 1. Execute via `$CLI client`
149
+ 2. Capture and display the response
150
+ 3. Interpret whether it succeeded or failed
151
+
152
+ ## Step 4: Verify coherence with database
153
+
154
+ After each write operation (create, update, delete), verify via db shell:
155
+
156
+ ```bash
157
+ $CLI db shell <<< "SELECT * FROM <table> WHERE id = '<id>';"
158
+ ```
159
+
160
+ Compare the API response with the raw database state:
161
+ - **Create:** record exists in DB with correct values
162
+ - **Update:** record reflects new values, updated_at changed
163
+ - **Delete:** record no longer exists (or soft-deleted if applicable)
164
+
165
+ Report discrepancies clearly.
166
+
167
+ ## Step 5: Logout and cleanup
168
+
169
+ ```bash
170
+ $CLI client logout
171
+ ```
172
+
173
+ This revokes the PAT server-side and removes the entry from `~/.nexus/session.json`.
174
+
175
+ If we started the backend in Step 1, stop it:
176
+
177
+ ```bash
178
+ kill %1 # or the recorded PID
179
+ ```
180
+
181
+ ## Step 6: Report
182
+
183
+ Summarize:
184
+ - Operations executed and their results
185
+ - Database coherence: PASS / FAIL per operation
186
+ - Any errors or unexpected behavior
187
+
188
+ Format as a table:
189
+
190
+ | # | Operation | API Result | DB Check | Status |
191
+ |---|-----------|------------|----------|--------|
192
+ | 1 | POST /contacts | 201 Created | Row exists | PASS |
193
+ | 2 | PATCH /contacts/:id | 200 Updated | Values match | PASS |
194
+ | 3 | DELETE /contacts/:id | 204 | Row gone | PASS |
@@ -13,7 +13,7 @@ Read these files to understand the current state of the plugin API:
13
13
  1. `packages/sdk/AGENTS.md` — SDK reference and gotchas
14
14
  2. `packages/backend/AGENTS.md` — Backend reference, CLI, gotchas
15
15
  3. `demos/demo-plugin/` — plugin developer reference (all files)
16
- 4. `plugins/tags/src/index.ts` — simplest real plugin
16
+ 4. `plugins/secrets/src/index.ts` — simplest real plugin
17
17
  5. `packages/sdk/src/types/manifest.ts` — PluginManifest interface (verify)
18
18
  6. `packages/sdk/src/types/entity.ts` — entity types (verify)
19
19
  7. `packages/backend/src/cli.ts` — CLI commands (verify plugin commands)
@@ -38,6 +38,7 @@ declare const ErrorCodes: {
38
38
  readonly STORAGE_FILE_TOO_LARGE: "STORAGE_FILE_TOO_LARGE";
39
39
  readonly STORAGE_FILE_TYPE_NOT_ALLOWED: "STORAGE_FILE_TYPE_NOT_ALLOWED";
40
40
  readonly STORAGE_PAYLOAD_TOO_LARGE: "STORAGE_PAYLOAD_TOO_LARGE";
41
+ readonly STORAGE_ERROR: "STORAGE_ERROR";
41
42
  readonly RESOURCE_NOT_FOUND: "RESOURCE_NOT_FOUND";
42
43
  readonly RESOURCE_CONFLICT: "RESOURCE_CONFLICT";
43
44
  readonly RESOURCE_CREATE_NOT_SUPPORTED: "RESOURCE_CREATE_NOT_SUPPORTED";