Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3a9ce86
feat: add CREATE/DROP NANOFLOW support — grammar, AST, visitor, executor
retran Apr 23, 2026
1805bc3
feat: add CALL NANOFLOW, GRANT/REVOKE nanoflow access, agentic skill,…
retran Apr 23, 2026
85aa8df
feat: add SHOW ACCESS, MERMAID, diff, and describe improvements
retran Apr 23, 2026
e764eb3
docs: add nanoflow references across repo documentation
retran Apr 24, 2026
b1856b3
fix: error propagation, MDL output fields, isNumericLiteral hardening
retran Apr 24, 2026
7153d1e
rewrite nanoflow test cases as QA manual test documentation
retran Apr 24, 2026
59b4e95
feat: add call javascript action MDL pipeline and association retriev…
retran Apr 24, 2026
a408062
docs: nanoflow BSON mapping, Go example, test cases, and validation f…
retran Apr 24, 2026
e18a3e2
feat: nanoflow ELK diagram support for VS Code preview
retran Apr 28, 2026
bd3ecd3
fix: propagate ELK errors, dedup entity lookup, correct docs
retran Apr 28, 2026
716beb3
docs: add §19 ELK diagram test cases to nanoflow test plan
retran Apr 28, 2026
5415a6a
fix: address PR review — denylist DownloadFileStmt, cache flow lookup…
retran Apr 29, 2026
d701f4a
feat: add LSP snippet completions for nanoflow statements
retran Apr 29, 2026
3dc5ce9
fix: resolve 5 unparseable nanoflows — negative literals, XPath predi…
retran Apr 29, 2026
06c519a
fix: omit empty JS/Java action params instead of emitting invalid '..…
retran Apr 29, 2026
3954e54
fix: add nanoflow validation parity, fast-path lookup, and consolidat…
retran Apr 29, 2026
f914d3d
docs: update documentation to reflect nanoflow implementation state
retran Apr 29, 2026
e9dfbc3
Merge branch 'main' into pr4-nanoflows-all
ako Apr 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/skills/mendix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Detailed syntax for each MDL document type:
|-------|---------|----------|
| [mdl-entities.md](mdl-entities.md) | Entity, attribute, association syntax | Creating domain models |
| [write-microflows.md](write-microflows.md) | Microflow syntax reference | Writing microflow logic |
| [write-nanoflows.md](write-nanoflows.md) | Nanoflow syntax reference | Writing client-side nanoflow logic |
| [write-oql-queries.md](write-oql-queries.md) | OQL query syntax | Creating VIEW entities |
| [create-page.md](create-page.md) | Page and widget syntax | Creating pages |
| [fragments.md](fragments.md) | Fragment (reusable widget group) syntax | Reusing widget patterns across pages |
Expand Down
3 changes: 3 additions & 0 deletions .claude/skills/mendix/create-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ actionbutton widgetName (caption: 'Caption', action: ACTION_TYPE [, buttonstyle:
- `action: delete` - Delete object
- `action: microflow Module.MicroflowName` - Call microflow
- `action: microflow Module.MicroflowName(Param: $value)` - Call microflow with parameters
- `action: nanoflow Module.NanoflowName` - Call nanoflow (client-side)
- `action: nanoflow Module.NanoflowName(Param: $value)` - Call nanoflow with parameters
- `action: show_page Module.PageName` - Navigate to page
- `action: show_page Module.PageName(Param: $value)` - Navigate with parameters
- `action: show_page Module.PageName($Param = $value)` - Also accepted (microflow-style)
Expand Down Expand Up @@ -341,6 +343,7 @@ column colActions (caption: 'Actions') {
| `datasource: database from Module.Entity` | Direct database query |
| `datasource: $Variable` | Variable bound (requires DATAVIEW parent with entity) |
| `datasource: microflow Module.GetData()` | Microflow datasource |
| `datasource: nanoflow Module.GetData()` | Nanoflow datasource (client-side, no server roundtrip) |
| `datasource: selection widgetName` | Listen to selection from another widget |
| `datasource: association path` | Retrieve by association from context (ByAssociation) |
| `datasource: $currentObject/Module.Assoc` | Sugar for `association` — same semantics, reads more naturally |
Expand Down
15 changes: 15 additions & 0 deletions .claude/skills/mendix/manage-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,21 @@ grant execute on microflow MyModule.ACT_Customer_Create to MyModule.User, MyModu
revoke execute on microflow MyModule.ACT_Customer_Create from MyModule.User;
```

### Nanoflow Access

```sql
-- Grant execute access (same syntax as microflows)
grant execute on nanoflow MyModule.NF_ValidateCart to MyModule.User, MyModule.Admin;

-- Revoke from specific roles
revoke execute on nanoflow MyModule.NF_ValidateCart from MyModule.User;

-- Show current access
show access on nanoflow MyModule.NF_ValidateCart;
```

> **Note:** Security roles persist through DROP+CREATE of the same nanoflow name within a session (by design, for refactor-in-place workflows).

### Page Access

```sql
Expand Down
2 changes: 2 additions & 0 deletions .claude/skills/mendix/validation-microflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Use this skill when:
- Building conditional validation chains
- Creating action microflows that call validation microflows

> **Nanoflow validation:** The same patterns apply to nanoflows (`create nanoflow` instead of `create microflow`). Use nanoflows for client-side validation when server roundtrips are unnecessary — validation feedback renders instantly without a network call.

## The Validation Pattern

Mendix validation follows a two-microflow pattern:
Expand Down
150 changes: 150 additions & 0 deletions .claude/skills/mendix/write-nanoflows.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Mendix Nanoflow Skill

This skill provides guidance for writing Mendix nanoflows in MDL syntax. Nanoflows share syntax with microflows but execute client-side with restricted capabilities.

## When to Use This Skill

Use this skill when:
- Writing CREATE NANOFLOW statements
- Debugging nanoflow validation errors
- Understanding nanoflow restrictions vs microflows

## Key Differences from Microflows

| Aspect | Microflow | Nanoflow |
|--------|-----------|----------|
| **Execution** | Server-side | Client-side (browser/mobile) |
| **Database access** | Full | No direct access |
| **Transactions** | Supported | Not supported |
| **Java actions** | Supported | Not supported |
| **JavaScript actions** | Not supported | Supported |
| **File downloads** | Supported | Not supported |
| **Error handling** | Full `ON ERROR` blocks | Per-action `ON ERROR` supported; `ErrorEvent` (raise error) forbidden |
| **Offline** | Not available | Available |

## Nanoflow Structure

```mdl
/**
* Nanoflow description
*
* @param $Parameter1 Description
* @returns Description of return value
*/
CREATE [OR MODIFY] NANOFLOW Module.NAV_Name (
$Parameter1: type
)
RETURNS ReturnType AS $Result
FOLDER 'FolderPath'
BEGIN
-- Nanoflow logic here
RETURN $Result;
END;
```

## Naming Convention

Nanoflow names use the `NAV_` prefix by convention:
- `NAV_ValidateCart` — client-side validation
- `NAV_ShowDetails` — page navigation
- `NAV_ToggleFilter` — UI state toggle

## Supported Activities

### Object Operations (in-memory only)
```mdl
$Item = CREATE Sales.CartItem (Quantity = 1);
CHANGE $Item (Quantity = $Item/Quantity + 1);
```

### Calling Other Flows
```mdl
$Result = CALL NANOFLOW Sales.NAV_ValidateCart (Cart = $Cart);
$ServerResult = CALL MICROFLOW Sales.ACT_SubmitOrder (Order = $Order);
$JsResult = CALL JAVASCRIPT ACTION MyModule.MyJsAction (Param = $Value);
```

### UI Activities
```mdl
SHOW PAGE Sales.CartDetail ($Cart = $Cart);
CLOSE PAGE;
VALIDATION FEEDBACK $Item/Quantity MESSAGE 'Quantity must be at least 1';
```

### Logging and Variables
```mdl
LOG INFO 'Cart updated with ' + toString($ItemCount) + ' items';
DECLARE $IsValid Boolean = true;
SET $IsValid = false;
```

### Control Flow
```mdl
IF $Cart/ItemCount = 0 THEN
VALIDATION FEEDBACK $Cart/ItemCount MESSAGE 'Cart is empty';
RETURN false;
ELSE
SHOW PAGE Sales.Checkout ($Cart = $Cart);
RETURN true;
END IF;
```

## Disallowed Activities

These will produce validation errors (12 case branches covering 22 action types in `nanoflow_validation.go`):
- `ErrorEvent` / `RAISE ERROR` — not available in nanoflows
- `CALL JAVA ACTION` — Java actions cannot run client-side
- `EXECUTE DATABASE QUERY` — direct SQL requires server
- `CALL EXTERNAL ACTION` — external actions are server-side
- `SHOW HOME PAGE` — home page navigation is server-side
- `CALL REST SERVICE` / `SEND REST REQUEST` — REST calls are server-side
- `IMPORT FROM MAPPING` / `EXPORT TO MAPPING` — mapping operations are server-side
- `TRANSFORM JSON` — JSON transformations are server-side
- `DOWNLOAD FILE` — file downloads require server-side processing
- All **workflow actions** (11 types: CallWorkflow, OpenWorkflow, SetTaskOutcome, OpenUserTask, etc.)

**Note:** Object operations (CREATE, CHANGE, COMMIT, DELETE, RETRIEVE) ARE allowed in nanoflows — they operate in-memory on the client.

## Return Type Restrictions

Binary return type is NOT allowed in nanoflows.

## Security (GRANT/REVOKE)

```mdl
GRANT EXECUTE ON NANOFLOW Shop.NAV_Filter TO Shop.User, Shop.Admin;
REVOKE EXECUTE ON NANOFLOW Shop.NAV_Filter FROM Shop.User;
```

## Management Commands

```mdl
SHOW NANOFLOWS
SHOW NANOFLOWS IN MyModule
DESCRIBE NANOFLOW MyModule.NAV_ShowDetails
DROP NANOFLOW MyModule.NAV_ShowDetails;
MOVE NANOFLOW Sales.NAV_OpenCart TO FOLDER 'UI/Navigation';
```

## Common Mistakes

1. **Using Java actions** — Use CALL JAVASCRIPT ACTION instead.
2. **Using ErrorEvent** — Nanoflows cannot raise errors directly. Handle errors per-action with ON ERROR.
3. **Expecting transactions** — Nanoflows have no rollback. Design for idempotency.
4. **File operations** — DOWNLOAD FILE is server-only.
5. **Binary return types** — Not supported in nanoflows.
6. **REST/external calls** — REST calls and external actions are server-only.

## Validation Checklist

- [ ] No ErrorEvent / raise error
- [ ] No Java action calls
- [ ] No REST calls, external action calls, or database queries
- [ ] No file download operations
- [ ] No import/export mapping or JSON transformation
- [ ] No workflow actions
- [ ] No show home page
- [ ] No binary return type
- [ ] Parameters and return types are nanoflow-compatible
- [ ] JavaDoc documentation present
- [ ] NAV_ naming prefix used
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- **OpenAPI import for REST clients** — `CREATE REST CLIENT` now accepts `OpenAPI: 'path/or/url'` to auto-generate a consumed REST service document from an OpenAPI 3.0 spec (JSON or YAML); operations, path/query parameters, request bodies, response types, resource groups (tags), and Basic auth are derived automatically; spec content is stored in `OpenApiFile` for Studio Pro parity (#207)
- **DESCRIBE CONTRACT OPERATION FROM OPENAPI** — Preview what would be generated from an OpenAPI spec without writing to the project

- **Flow bug fixes** — Module existence validation for SHOW NANOFLOWS and SHOW MICROFLOWS, numeric return literals no longer get spurious `$` prefix, empty flow names rejected at create time, `NanoflowCallAction` error handling type resolved correctly, `not()` expression spacing preserved on roundtrip, JavaScript action call rendering in DESCRIBE output
- **Nanoflow diff support** — `mxcli diff` now detects and displays nanoflow changes (previously silently skipped)
- **Nanoflow validation parity** — `mxcli check` now runs full body validation on nanoflows (undeclared variables, missing returns, branch scoping) via shared `validateFlowBody` helper; `allNames()` includes nanoflows for forward-reference detection
- **DownloadFileStmt denylist** — `DOWNLOAD FILE` added to nanoflow disallowed action list
- **JavaScript action MDL syntax** — `call javascript action Module.ActionName(params)` now fully supported in CREATE NANOFLOW/MICROFLOW bodies: grammar, parser, builder, serializer, and roundtrip
- **LSP snippet completions** — Added `CREATE NANOFLOW (with params)`, `CALL MICROFLOW`, `CALL NANOFLOW`, `CALL JAVASCRIPT ACTION`, `CALL JAVA ACTION` snippets
- **Flow builder cache** — `lookupMicroflowReturnType` and `lookupNanoflowReturnType` now cache results with lazy-load bool flags, avoiding repeated `ListNanoflows`/`ListMicroflows` calls; nanoflow lookup uses `GetRawUnitByName` fast path
- **Parser fixes** — Negative literals no longer greedily consumed by lexer (`-?` removed from `NUMBER_LITERAL`); XPath multi-predicate brackets correctly split and re-wrapped; multi-line string literals in change/create object expressions escaped; `ExclusiveSplit` (if/else) inside loop bodies now emits correct `end if;`
- **Empty action params** — JS and Java action parameters with empty/nil values are omitted from DESCRIBE output instead of rendering as `...` or bare `= )`
- **Association retrieve roundtrip fidelity** — `retrieve $X from $Y/Module.Association` syntax preserved on roundtrip (previously converted to `from Entity where Assoc = $Y`)
- **DESCRIBE empty-then optimization** — If/else blocks with empty true branches are swapped and condition negated for readable output

### Changed

- **MDL string literal escapes** — `mdlQuote`/`unquoteString` now treat `\n`, `\r`, `\t`, and `\\` inside single-quoted literals as escape sequences (previously a literal backslash followed by the letter). This is a compatibility break for any MDL script that intentionally embedded a raw `\n` / `\t` / `\\` as two characters; such scripts must now double the backslash (`\\n` to preserve the two-character form). Applies to `LOG` messages, `@caption`/`@annotation` text, and other string literals round-tripped via the describer.
Expand Down
7 changes: 4 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ Regenerate after modifying `MDLLexer.g4` or `MDLParser.g4`: `make grammar`. See
- `.claude/skills/version-awareness.md` - **CHECK project version first** - Run `show features` before using version-gated syntax
- `.claude/skills/design-mdl-syntax.md` - **READ before designing new MDL syntax** - Design principles, decision framework, anti-patterns, checklist
- `.claude/skills/write-microflows.md` - Microflow syntax, common mistakes, validation checklist
- `.claude/skills/write-nanoflows.md` - Nanoflow syntax, restrictions, disallowed activities, validation checklist
- `.claude/skills/create-page.md` - Page/widget syntax reference
- `.claude/skills/alter-page.md` - ALTER PAGE/SNIPPET in-place modifications (SET, INSERT, DROP, REPLACE, SET Layout)
- `.claude/skills/overview-pages.md` - CRUD page patterns
Expand All @@ -439,9 +440,9 @@ Regenerate after modifying `MDLLexer.g4` or `MDLParser.g4`: `make grammar`. See
- `.claude/skills/database-connections.md` - External database connections from microflows
- `.claude/skills/test-microflows.md` - **READ for testing work** - Test annotations, file formats, Docker setup requirement

### Mendix Microflow Idioms (MUST follow)
### Mendix Microflow/Nanoflow Idioms (MUST follow)

These rules apply whenever generating microflow MDL. Violations are caught by `mxcli check`.
These rules apply whenever generating microflow or nanoflow MDL. Violations are caught by `mxcli check`.

1. **NEVER create empty list variables as loop sources.** If processing imported data, accept the list as a microflow parameter — `declare $Items list of ... = empty` followed by `loop $item in $Items` is always wrong.
2. **NEVER use nested LOOPs for list matching.** Loop over the primary list and use `retrieve $match from $TargetList where key = $item/key limit 1` for O(N) lookup. Nested loops are O(N^2).
Expand All @@ -464,7 +465,7 @@ Full syntax tables for all MDL statements (microflows, pages, security, navigati
- MPR v1/v2 reading and writing
- Domain model (entities, attributes, associations)
- ALTER ENTITY (add/rename/modify/drop attributes, indexes, documentation)
- Microflows/Nanoflows with 60+ activity types
- Microflows/Nanoflows with 60+ activity types, JavaScript action calls, nanoflow validation parity
- Pages with 50+ widget types
- ALTER PAGE/SNIPPET (SET, INSERT, DROP, REPLACE operations on widget trees)
- Image widgets (IMAGE, STATICIMAGE, DYNAMICIMAGE) with Width/Height properties
Expand Down
5 changes: 5 additions & 0 deletions cmd/mxcli/cmd_describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ Example:
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
} else if upper == "NANOFLOW" {
if err := exec.NanoflowELK(name); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
} else if upper == "PAGE" {
if err := exec.PageWireframeJSON(name); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
Expand Down
5 changes: 5 additions & 0 deletions cmd/mxcli/lsp_completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ var mdlCreateSnippets = []protocol.CompletionItem{
snippet("CREATE MICROFLOW", "CREATE MICROFLOW ${1:Module}.${2:MicroflowName}\nBEGIN\n\t$0\nEND;", "Create a new microflow"),
snippet("CREATE MICROFLOW (with params)", "CREATE MICROFLOW ${1:Module}.${2:MicroflowName}\n(\n\t$$${3:Param}: ${4:Module.Entity}\n)\nRETURNS ${5:Boolean} AS $$${6:Result}\nBEGIN\n\t$0\nEND;", "Create microflow with parameters"),
snippet("CREATE NANOFLOW", "CREATE NANOFLOW ${1:Module}.${2:NanoflowName}\nBEGIN\n\t$0\nEND;", "Create a new nanoflow"),
snippet("CREATE NANOFLOW (with params)", "CREATE NANOFLOW ${1:Module}.${2:NanoflowName}\n(\n\t$$${3:Param}: ${4:Module.Entity}\n)\nRETURNS ${5:Boolean} AS $$${6:Result}\nBEGIN\n\t$0\nEND;", "Create nanoflow with parameters"),
snippet("CREATE ENUMERATION", "CREATE ENUMERATION ${1:Module}.${2:EnumName}\n(\n\t'${3:Value1}' '${4:Caption1}',\n\t'${5:Value2}' '${6:Caption2}'\n);", "Create a new enumeration"),
snippet("CREATE CONSTANT", "CREATE CONSTANT ${1:Module}.${2:ConstantName}\nTYPE ${3|String,Integer,Long,Decimal,Boolean,DateTime|}\nDEFAULT ${4:'value'};", "Create a new constant"),
snippet("CREATE PAGE", "CREATE PAGE ${1:Module}.${2:PageName}\n(\n\tTitle: '${3:Page Title}',\n\tLayout: ${4:Atlas_Core.Atlas_Default}\n)\n{\n\t$0\n}", "Create a new page"),
Expand All @@ -199,6 +200,10 @@ var mdlStatementSnippets = []protocol.CompletionItem{
snippet("RETRIEVE ... FROM $Var/Assoc", "RETRIEVE $$${1:List} FROM $$${2:Parent}/${3:Module.AssociationName};", "Retrieve by association"),
snippet("DATAVIEW", "DATAVIEW ${1:dvName} (DataSource: $$${2:Var}) {\n\t$0\n}", "Data view widget"),
snippet("INDEX", "INDEX (${1:AttributeName});", "Entity index"),
snippet("CALL MICROFLOW", "$$${1:Result} = CALL MICROFLOW ${2:Module.MicroflowName}(${3});", "Call a microflow"),
snippet("CALL NANOFLOW", "$$${1:Result} = CALL NANOFLOW ${2:Module.NanoflowName}(${3});", "Call a nanoflow"),
snippet("CALL JAVASCRIPT ACTION", "$$${1:Result} = CALL JAVASCRIPT ACTION ${2:Module.ActionName}(${3});", "Call a JavaScript action"),
snippet("CALL JAVA ACTION", "$$${1:Result} = CALL JAVA ACTION ${2:Module.ActionName}(${3});", "Call a Java action"),
}

// inferCompletionTypes examines the line prefix and returns the ObjectType
Expand Down
30 changes: 21 additions & 9 deletions docs-site/src/language/nanoflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Nanoflows are client-side logic flows that execute in the user's browser or on m
| **Close page** | Supported | Supported |
| **Network** | Requires server round-trip | No network call (fast) |
| **Offline** | Not available offline | Available offline |
| **Error handling** | `ON ERROR` blocks | Limited error handling |
| **Error handling** | `ON ERROR` blocks | Per-action `ON ERROR` (no `ErrorEvent`) |

## When to Use Which

Expand All @@ -36,7 +36,7 @@ Nanoflows are client-side logic flows that execute in the user's browser or on m
## CREATE NANOFLOW Syntax

```sql
CREATE [OR REPLACE] NANOFLOW <Module.Name>
CREATE [OR MODIFY] NANOFLOW <Module.Name>
[FOLDER '<path>']
BEGIN
[<declarations>]
Expand Down Expand Up @@ -70,6 +70,9 @@ $Result = CALL NANOFLOW Sales.NAV_ValidateCart (Cart = $Cart);

-- Call a microflow (triggers server round-trip)
$ServerResult = CALL MICROFLOW Sales.ACT_SubmitOrder (Order = $Order);

-- Call a JavaScript action
$HasNetwork = CALL JAVASCRIPT ACTION NanoflowCommons.HasConnectivity();
```

### UI Activities
Expand Down Expand Up @@ -110,13 +113,18 @@ END IF;

The following activities are server-only and cannot be used in nanoflows:

- `RETRIEVE ... FROM Module.Entity WHERE ...` (database retrieval)
- `COMMIT`
- `DELETE`
- `ROLLBACK`
- `CALL JAVA ACTION`
- `EXECUTE DATABASE QUERY`
- `ON ERROR { ... }` (full error handler blocks)
- `CALL JAVA ACTION` — Java actions cannot run client-side
- `ErrorEvent` / `RAISE ERROR` — error events are not available in nanoflows
- `DOWNLOAD FILE` — file downloads require server-side processing
- `CALL REST SERVICE` / `SEND REST REQUEST` — REST calls are server-side
- `IMPORT FROM MAPPING` / `EXPORT TO MAPPING` — mapping operations are server-side
- `EXECUTE DATABASE QUERY` — direct SQL requires server
- `TRANSFORM JSON` — JSON transformations are server-side
- `SHOW HOME PAGE` — home page navigation is server-side
- `CALL EXTERNAL ACTION` — external actions are server-side
- All **workflow actions** (call/open workflow, set task outcome, user task, etc.)

> **Note:** Per-action error handling (`on error continue`) IS supported in nanoflows. Only `ErrorEvent` (raise error as a standalone flow action) is forbidden. Note that `on error rollback` is syntactically valid but only rolls back in-memory changes — nanoflows have no database transactions.

## SHOW and DESCRIBE

Expand Down Expand Up @@ -179,3 +187,7 @@ BEGIN
SHOW PAGE Sales.Order_Detail ($Order = $Order);
END;
```

## Security

Nanoflow access control uses GRANT/REVOKE to specify which module roles can execute a nanoflow. See [Grant & Revoke](./grant-revoke.md) and [Document Access](./document-access.md) for full syntax and examples.
2 changes: 1 addition & 1 deletion docs/01-project/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ sequenceDiagram
| `mdl/grammar` | ANTLR4 lexer/parser (generated from MDLLexer.g4 + MDLParser.g4) |
| `mdl/ast` | AST node types for MDL statements |
| `mdl/visitor` | ANTLR listener that builds AST from parse tree |
| `mdl/executor` | Thin orchestrator: parses AST, calls `ctx.Backend.*`, formats output. **No `sdk/mpr` imports.** |
| `mdl/executor` | Thin orchestrator: parses AST, calls `ctx.Backend.*`, formats output. Handles microflows, nanoflows, pages, workflows, domain models, security, and all other MDL document types. **No `sdk/mpr` imports.** |
| `mdl/backend` | Domain-specific backend interfaces (`FullBackend`, `PageMutator`, `WorkflowMutator`, `BackendFactory`) |
| `mdl/backend/mpr` | MPR-backed implementation of all backend interfaces; owns all BSON mutation logic |
| `mdl/backend/mock` | `MockBackend` with Func-field injection for unit testing without a `.mpr` file |
Expand Down
Loading
Loading