@gzl10/nexus-backend 0.20.0 → 1.0.0-alpha.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/claude-commands/nexus-catalog.md +69 -0
- package/claude-commands/nexus-new-action.md +15 -10
- package/claude-commands/nexus-new-entity.md +1 -1
- package/claude-commands/nexus-new-module.md +3 -3
- package/claude-commands/nexus-new-plugin.md +10 -5
- package/claude-commands/nexus-review-module.md +220 -0
- package/claude-commands/nexus-test.md +207 -0
- package/claude-commands/nexus-update-tutorial-plugin.md +1 -1
- package/dist/{app-error-CKbYJQ9V.d.ts → app-error-DMO71vXw.d.ts} +1 -0
- package/dist/cli.js +16619 -6450
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1049 -1219
- package/dist/index.js +19855 -15101
- package/dist/index.js.map +1 -1
- package/dist/instrumentation.d.ts +7 -4
- package/dist/instrumentation.js +6 -6
- package/dist/instrumentation.js.map +1 -1
- package/dist/main.js +18573 -13428
- package/dist/main.js.map +1 -1
- package/dist/migration-helpers/index.js +433 -11701
- package/dist/migration-helpers/index.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +23 -10
- package/dist/testing/index.js.map +1 -1
- package/llms.txt +190 -0
- package/migrations/{core__1773764515717_auto.js → core__1775119448468_auto.js} +51 -17
- package/migrations/core__1775166359370_auto.js +15 -0
- package/migrations/core__1775186782150_auto.js +100 -0
- package/migrations/core__1775212779996_auto.js +21 -0
- package/migrations/core__1775618072245_drop-schedules-tags.js +22 -0
- package/migrations/core__1775619133207_split-target-config.js +73 -0
- package/migrations/core__1775861704914_auto.js +36 -0
- package/migrations/core__1776150736671_auto.js +27 -0
- package/package.json +18 -22
- package/migrations/core__1773864100000_audit_log.js +0 -30
- package/migrations/core__1773864200000_migrate_auth_audit.js +0 -85
|
@@ -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
|
|
36
|
-
import {
|
|
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
|
-
|
|
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:
|
|
58
|
-
const { format } =
|
|
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
|
-
|
|
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
|
-
-
|
|
95
|
-
-
|
|
94
|
+
- Handler signature: `handler: async (ctx, input, c?) => {}` — direct function, NOT factory pattern. `c` is the Hono `Context`.
|
|
95
|
+
- Hooks use factory pattern `(ctx) => ({...})`, but action handlers do NOT
|
|
96
|
+
- `key` is the route identifier (NOT `name`)
|
|
97
|
+
- `scope: 'row'` actions receive the entity id via `c.req.param('id')` if `c` is needed
|
|
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.
|
|
@@ -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** —
|
|
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
|
-
|
|
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:
|
|
121
|
+
name: pkg.name,
|
|
118
122
|
code: '{code}',
|
|
119
123
|
label: { en: '{Name}', es: '{Nombre}' },
|
|
120
|
-
icon: '{icon}',
|
|
121
|
-
version:
|
|
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
|
-
-
|
|
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,207 @@
|
|
|
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 **forcing JSON logs** so you can parse them reliably (sin códigos ANSI ni multilínea de pino-pretty):
|
|
80
|
+
|
|
81
|
+
- **Monorepo core:** `cd packages/backend && LOG_FORMAT=json pnpm dev &`
|
|
82
|
+
- **Monorepo demo:** `cd demos/demo-backend && LOG_FORMAT=json pnpm dev &`
|
|
83
|
+
- **Project:** `LOG_FORMAT=json pnpm dev &` (from project root)
|
|
84
|
+
|
|
85
|
+
`LOG_FORMAT=json` produce una línea JSON por evento — útil para grep/jq y para que la IA filtre logs sin parsear ANSI. Si el `.env` ya define `LOG_FORMAT`, el override del entorno tiene prioridad solo si no se exporta antes.
|
|
86
|
+
|
|
87
|
+
Wait until `$CLI client health` succeeds (poll every 2s, max 30s).
|
|
88
|
+
|
|
89
|
+
Record whether we started the backend (to shut it down at the end).
|
|
90
|
+
|
|
91
|
+
## Step 2: Login
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
$CLI client login [email] [password]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- If credentials provided in $ARGUMENTS, use those
|
|
98
|
+
- If not, defaults from .env (ADMIN_EMAIL / ADMIN_PASSWORD) are used automatically
|
|
99
|
+
- If no defaults, ask the user
|
|
100
|
+
|
|
101
|
+
Session is persisted via PAT in `~/.nexus/session.json` indexed by project path — no expiration, survives across commands, supports multiple projects.
|
|
102
|
+
|
|
103
|
+
Confirm login succeeded (check output for user JSON).
|
|
104
|
+
|
|
105
|
+
## Step 3: Execute operations
|
|
106
|
+
|
|
107
|
+
Translate the user's instructions into nexus CLI calls:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
$CLI client entity <module/entity> <action> [args]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Available commands:
|
|
114
|
+
|
|
115
|
+
**Entity CRUD:**
|
|
116
|
+
|
|
117
|
+
- `$CLI client entity <path> list` — list entities
|
|
118
|
+
- `$CLI client entity <path> get <id>` — get by ID
|
|
119
|
+
- `$CLI client entity <path> create '<json>'` — create
|
|
120
|
+
- `$CLI client entity <path> update <id> '<json>'` — update
|
|
121
|
+
- `$CLI client entity <path> delete <id>` — delete
|
|
122
|
+
|
|
123
|
+
**Actions (module/entity/row):**
|
|
124
|
+
|
|
125
|
+
- `$CLI client action <module> <key> ['<json>']` — module action (POST by default)
|
|
126
|
+
- `$CLI client action <module> <key> <id> ['<json>']` — row action
|
|
127
|
+
- `$CLI client action <module> <key> -m GET` — read action (e.g. sessions, list-tokens)
|
|
128
|
+
|
|
129
|
+
**Generic HTTP (any endpoint):**
|
|
130
|
+
|
|
131
|
+
- `$CLI client fetch <METHOD> <url> ['<json>']` — hit any endpoint
|
|
132
|
+
- `$CLI client fetch GET /auth/me` — example read
|
|
133
|
+
- `$CLI client fetch POST /mail/send '{"to":"x"}'` — example write
|
|
134
|
+
- `$CLI client fetch GET /some/endpoint --pat <token>` — bypass session, use PAT directly
|
|
135
|
+
|
|
136
|
+
**Storage:**
|
|
137
|
+
|
|
138
|
+
- `$CLI client storage upload <file...> [--folder X] [--scope X] [--visibility public|internal|private]` — upload one or more files
|
|
139
|
+
- `$CLI client storage download <id> [--output path]` — download file to disk (default: original filename in CWD)
|
|
140
|
+
- `$CLI client storage list [--mimetype X] [--folder X] [--scope X] [--limit N]` — list storage files
|
|
141
|
+
- `$CLI client storage delete <id>` — delete file by ID
|
|
142
|
+
- `$CLI client storage stats` — storage statistics (total files, size, by type)
|
|
143
|
+
|
|
144
|
+
**Other:**
|
|
145
|
+
|
|
146
|
+
- `$CLI client health` — health check
|
|
147
|
+
- `$CLI client login [email] [password]` — authenticate (creates PAT)
|
|
148
|
+
- `$CLI client me` — current user info
|
|
149
|
+
- `$CLI logs [--lines N] [--file path]` — tail backend log file in real time (requires LOG_FILE in .env)
|
|
150
|
+
- `$CLI migrate list` — show migration status (alias for `migrate status`)
|
|
151
|
+
|
|
152
|
+
**Command selection guide:**
|
|
153
|
+
- **entity** — CRUD on entities (list, get, create, update, delete)
|
|
154
|
+
- **action** — declared actions in modules/plugins (have a key, may need body or row id)
|
|
155
|
+
- **storage** — file upload/download/list/delete/stats
|
|
156
|
+
- **fetch** — anything else (custom routes, plugin endpoints, non-standard paths)
|
|
157
|
+
|
|
158
|
+
Use `--debug` flag on any command for verbose HTTP logging.
|
|
159
|
+
|
|
160
|
+
For each operation:
|
|
161
|
+
1. Execute via `$CLI client`
|
|
162
|
+
2. Capture and display the response
|
|
163
|
+
3. Interpret whether it succeeded or failed
|
|
164
|
+
|
|
165
|
+
## Step 4: Verify coherence with database
|
|
166
|
+
|
|
167
|
+
After each write operation (create, update, delete), verify via db shell:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
$CLI db shell <<< "SELECT * FROM <table> WHERE id = '<id>';"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Compare the API response with the raw database state:
|
|
174
|
+
- **Create:** record exists in DB with correct values
|
|
175
|
+
- **Update:** record reflects new values, updated_at changed
|
|
176
|
+
- **Delete:** record no longer exists (or soft-deleted if applicable)
|
|
177
|
+
|
|
178
|
+
Report discrepancies clearly.
|
|
179
|
+
|
|
180
|
+
## Step 5: Logout and cleanup
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
$CLI client logout
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
This revokes the PAT server-side and removes the entry from `~/.nexus/session.json`.
|
|
187
|
+
|
|
188
|
+
If we started the backend in Step 1, stop it:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
kill %1 # or the recorded PID
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Step 6: Report
|
|
195
|
+
|
|
196
|
+
Summarize:
|
|
197
|
+
- Operations executed and their results
|
|
198
|
+
- Database coherence: PASS / FAIL per operation
|
|
199
|
+
- Any errors or unexpected behavior
|
|
200
|
+
|
|
201
|
+
Format as a table:
|
|
202
|
+
|
|
203
|
+
| # | Operation | API Result | DB Check | Status |
|
|
204
|
+
|---|-----------|------------|----------|--------|
|
|
205
|
+
| 1 | POST /contacts | 201 Created | Row exists | PASS |
|
|
206
|
+
| 2 | PATCH /contacts/:id | 200 Updated | Values match | PASS |
|
|
207
|
+
| 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/
|
|
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";
|