Workflow
README.md
# Product Studio
Local **Product Owner** workspace: a browser chat UI, your company OpenAI-compatible LLM (no Cursor), and optional MCP tools for Jira, Confluence, GitLab, Workflow, Database, and Solver.
## Requirements
- Node.js **22.13+**
- Access to your LLM endpoint
- Optional: Jira / Confluence / GitLab — the app still runs if any are missing
## Install
```bash
npm install
npm run build
```
## Run (chat UI)
```bash
npm start
# → http://127.0.0.1:8787
```
Or:
```bash
npx tsx src/index.ts serve --port 8787
```
### Login / members
Access requires a Studio account (httpOnly session cookie). Passwords are stored as **scrypt** hashes in SQLite — never plaintext.
**First admin (pick one):**
1. Open the UI with no users → **Create admin** setup screen
2. Or CLI:
```bash
npx tsx src/index.ts user bootstrap --username admin --password "your-secure-password"
```
**Add a limited member (after admin exists):**
```bash
npx tsx src/index.ts user create --username alice --password "alice-pass-here" --role limited
npx tsx src/index.ts user list
```
Or in the UI: **Settings → Members** (admin only).
| Role | Access |
|------|--------|
| **admin** | Everything + member management |
| **full** | Chat, Workflows (create/edit/delete), Status, Settings integrations |
| **limited** | Chat, run/view workflows + pauses, Status — no Settings, no workflow delete/disable/create |
## Configure
Configs persist in SQLite (`data/product-studio.sqlite`).
**In the UI:** send `/config` and follow the menu.
**CLI:**
```bash
npx tsx src/index.ts config llm --base-url "https://your-llm/v1" --api-key "..." --model "..."
npx tsx src/index.ts config jira --base-url "..." --email "..." --api-token "..."
npx tsx src/index.ts config database --dialect sqlite --file-path data/app-data.sqlite --name default
npx tsx src/index.ts status
```
## UI workspaces
- **Chat** — agent conversation (`New chat` keeps past threads; `/start` clears only the current chat; last 20 messages are sent as context)
- **Workflows** — create, edit, run, and visualize HTTP/SQL sequences; approve pending SQL here
- **Settings** — LLM / Jira / Confluence / GitLab / Database forms
- **Status** — connection state and active MCP tools
## Workflows
```bash
npx tsx src/index.ts workflow create --name "demo" --description "sample" --definition-file data/sample-workflow.json
npx tsx src/index.ts workflow visualize demo
```
HTTP nodes support **GET / POST / PUT / PATCH / DELETE** with templated `headers`, `query` (object or query string), and `body` (JSON object or raw string). Body is **not** sent on GET/HEAD by default. Use `{{nodeId.path}}` and `{{secrets.*}}` in URL/headers/query/body. SQL nodes use `type: "sql"` (or `"database"`) with arbitrary `sql` (and optional `params` / `connectionId`). **Every SQL statement pauses for approval** (including SELECT) until `POST /api/approvals/:id/approve`.
### Return mapping (`returns`)
Optional top-level `returns` declares the **Output** shape of a successful run. Values are templates against node outputs (`{{nodeId.path}}`). A single template keeps the typed value; missing paths become `null` and are listed in `meta.returnWarnings` (set `returnsStrict: true` to fail instead).
When `returns` is present, MCP `workflow_run` / `POST /api/workflows/:id/run` include `returns` and omit full `outputs` unless you pass `includeNodes: true` (Studio Run always sets this for debugging). Workflows without `returns` keep the previous full-`outputs` response.
```json
{
"nodes": [ /* ... */ ],
"returns": {
"response": "{{get_profile.body}}",
"token": "{{exchangeToken.body.access_token}}",
"userId": "{{profile.body.id}}"
}
}
```
HTTP node outputs always include `body` (parsed JSON or raw text), plus `status`, `ok`, `text`, and response `headers`. Use `{{nodeId.body}}` for the full payload object, `{{nodeId}}` for the entire node bag, or `{{nodeId.body.field}}` for a leaf. Body object fields are also promoted to the top level for older templates (`{{nodeId.field}}`), except when they collide with envelope keys (`body`, `status`, `ok`, `text`, `headers`).
Example GET (query) and POST (JSON body + headers):
```json
{
"nodes": [
{
"id": "listItems",
"type": "http",
"name": "List items",
"method": "GET",
"url": "https://httpbin.org/get",
"headers": { "Accept": "application/json" },
"query": { "page": "1", "q": "{{input.search}}" }
},
{
"id": "createItem",
"type": "http",
"name": "Create item",
"method": "POST",
"url": "https://httpbin.org/post",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer {{secrets.jira.apiToken}}"
},
"body": { "title": "{{input.title}}", "from": "{{listItems.url}}" }
}
]
}
```
Smoke-check HTTP request construction: `npx tsx scripts/smoke-http-node.ts`
Smoke-check workflow engine (transform, choice, parallel, auth): `npm run smoke:workflow`
### Node cheat-sheet (extras)
| Capability | Snippet |
|------------|---------|
| **Transform** `merge_arrays` / `merge_object` / `parse_json` / `map` / `format_table` | `{ "type":"transform", "op":"format_table", "source":"{{list.body}}", "columns":["id","name"] }` → `{{node.markdown}}` |
| **Choice input** | `{ "type":"input", "inputType":"choice", "optionsFrom":"{{table.items}}", "valueField":"id", "labelFields":"name,tag" }` |
| **HTTP auth helper** | `{ "type":"http", "auth":{ "type":"bearer", "from":"{{token.accessToken}}" }, "headers":{...} }` (raw `Authorization` overrides) |
| **Parallel HTTP** | `{ "type":"parallel", "requests":[{ "id":"a", "method":"GET", "url":"..." }, { "id":"b", ... }] }` → `{{node.results.a.body}}` |
| **Approval** | `{ "type":"approval", "prompt":"Confirm POST?", "summary":"{{body.result}}" }` — reply yes/بله or no/خیر in Chat |
Example SQL node:
```json
{
"id": "q1",
"type": "sql",
"name": "list users",
"operation": "sql",
"sql": "SELECT id, email FROM users LIMIT 20",
"connectionId": "default"
}
```
Approvals API: `GET /api/approvals?status=pending`, `POST /api/approvals/:id/approve`, `POST /api/approvals/:id/reject`.
## MCP servers
| Server | When enabled |
|--------|----------------|
| Jira | baseUrl + (bearer **or** email+apiToken) |
| Confluence | same pattern |
| GitLab | baseUrl + token |
| Workflow | always |
| Database | always (connections optional); schema inspect needs a connection |
| Solver | when LLM is configured |
Database MCP tools (English names): `database_list_connections`, `database_upsert_connection`, `database_delete_connection`, `database_test_connection`, `database_list_databases`, `database_list_schemas`, `database_list_tables`, `database_describe_table`, `database_list_indexes`, `database_list_foreign_keys`, `database_request_sql` (queues approval), `database_list_approvals`.This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues