Solution Engineer Technical Guide
Build on Fuuz like you built it
Understanding the stack under Fuuz — MongoDB, GraphQL APIs, the Data Flow Engine, Fuuz JSONata bindings, and SaaS on AWS — isn't background knowledge. It's how you write better screens, faster flows, cleaner integrations, and diagnose problems in minutes instead of hours.
MongoDB GraphQL APIs Fuuz JSONata AWS SaaS WebSockets
THE STACK
What's Running Under
Everything You Build
Every screen, data flow, integration, and data model you create in Fuuz runs on this stack. Knowing how each layer works and how they talk to each other changes how you build and how fast you debug.
The Builder's Insight
When something isn't working, the stack gives you a clear isolation strategy. Data wrong? Check the document shape via a GraphQL query. Query returning unexpected results? Check predicates and filters. Transform producing bad output? Check the JSONata or JS expression in the transform console. Screen not rendering? Inspect the element binding. Each layer has a distinct responsibility and a distinct debugging approach.
Real-time: WebSockets, Not GraphQL Subscriptions
Real-time updates in Fuuz — live screen refresh, push events, shop floor alerts — are delivered via a dedicated WebSocket subscription service, separate from the GraphQL APIs. The end result is the same (live data without polling), but it is a distinct service, not a GraphQL subscription.
MongoDB is your data layer
Documents, not rows. Schema lives in the Fuuz data model designer. Document structure determines how simple or complex your queries, flows, and bindings will be.
GraphQL APIs are your data contract
Multiple typed APIs serve different parts of the platform. Filtering and aggregation happen here via predicates and _aggregate queries — not in JSONata transforms.
Data Flow Engine is your workflow layer
The low-code / pro-code engine that orchestrates logic — API calls, transforms, conditionals, error handling, integrations. Sits above GraphQL in the stack.
Fuuz JSONata is your expression language
Fuuz extends standard JSONata with platform-specific bindings: $components, $metadata, $state, join functions, and more. Standard JSONata is just the foundation.
Client Layer Screen Designer · Mobile · External Apps · IoT Devices
GraphQL queries / mutations
WebSocket events (real-time)
Data Flow Engine Low-code / Pro-code workflow engine · Web, Backend & Gateway flows
JSONata / JavaScript transforms
Transformation Layer Fuuz JSONata Bindings · JavaScript · $state · $components · $metadata
typed queries / mutations / predicates
GraphQL APIs Multiple typed APIs · Schema-validated · Real-time via separate WebSocket service
BSON document reads / writes
GraphQL APIs Multiple typed APIs · Schema-validated · Real-time via separate WebSocket service
managed infrastructure
AWS SaaS Infrastructure Auto-scale · CDN · IAM · High availability · Managed operations
MONGODB
Think in Documents, Not Tables
The biggest conceptual shift for engineers from SQL-backed environments. MongoDB stores JSON documents, not rows. How you design documents affects query performance, screen binding complexity, and flow logic.
| Concept | SQL World | MongoDB / Fuuz |
|---|---|---|
| Data unit | Row in a table | JSON document in a collection |
| Relationships | Foreign keys + JOINs | Nested sub-documents or ID references |
| Schema changes | ALTER TABLE + migration + risk | Add field in schema designer → live instantly, zero downtime |
| Optional data | Nullable column on every row | Field simply absent if not applicable |
| Variable shapes | EAV tables or wide nullable rows | Each document carries its own field set |
| Filtering / aggregation | SQL WHERE / GROUP BY | GraphQL predicates and _aggregate queries at the API layer |
| Record ID | Primary key (varies) | Always id in Fuuz GraphQL — no underscore prefix |
On Embedding: Conceptually Sound, Practically Evolving
The embed-vs-reference pattern is the right mental model for document databases. In Fuuz, full embedded type support is actively in development. Apply the principles in your data model design now — as platform support deepens, models designed with this thinking will be well-positioned. Discuss with your team lead which patterns are best supported in your current release.
The #1 Mistake from SQL Backgrounds
Over-normalizing the data model. Creating a separate Fuuz model for every sub-entity because "that's how you do it in SQL." Before splitting, ask: will this data ever be queried independently, or does it always travel with its parent? If it always travels with its parent — it's a candidate for embedding. Fewer models often means simpler queries, cleaner flows, and easier screen bindings.
GRAPHQL APIs
GraphQL: Where
Filtering and Fetching Live
Fuuz exposes multiple GraphQL APIs. This is where you declare what data you want, apply filters and predicates, and run aggregations. Filtering and grouping happen here at the API layer — not in JSONata transforms.
Filtering Belongs in GraphQL, Not JSONata
A common pattern from SQL backgrounds is to fetch a large result set then filter it in a JSONata transform. Don't do this. Use GraphQL predicates to filter at the query layer. Use _aggregate queries for counts, sums, and grouping. JSONata then handles reshaping the already-filtered result.
Declare exactly what you need
Shape the query to match exactly what the screen or flow needs. No over-fetching a 40-field record to display 3 fields on a table row.
Mutations write data
Creates, updates, and deletes all go through GraphQL mutations. Always return id in the mutation selection set to confirm the write and enable chained operations.
Filter via predicates
GraphQL predicates are your WHERE clause. Filter by field values, date ranges, and relationships at the API layer before data ever reaches your screen or flow.
Traverse relationships in one call
Walk from Work Center → Work Orders → Operations in a single query. One roundtrip returns the full graph — no chained REST-style calls.
Aggregate at the query layer
Use _aggregate queries for counts, sums, and grouping. Runs server-side — far more efficient than fetching all records and counting in JSONata.
Schema-validated in real time
The GraphQL input in Fuuz autocompletes and validates against the schema as you type. Field name errors and type mismatches are caught immediately, before runtime.
DATA FLOW ENGINE
The Low-code / Pro-code
Workflow Engine
The Fuuz Data Flow Engine sits above the GraphQL layer — it orchestrates logic, calls APIs, handles errors, and applies transforms. Think of it as your application's business logic layer, built visually with the option to drop into JavaScript for complex operations.
Web Flows
Triggered by user interactions on screens. Handle button actions, form submissions, navigation, and reactive UI logic. Run client-side in the browser context.
Backend Flows
Server-side logic triggered by events, schedules, or API calls. Used for integration logic, data processing, ERP write-backs, and operations that should not run on the client.
Gateway Flows
Expose Fuuz logic to external systems as callable endpoints. Used when external systems need to push data in or trigger Fuuz operations programmatically.
Stack Position: DFE is Above GraphQL
The Data Flow Engine sits above the GraphQL API layer. Flows call GraphQL APIs to read and write data, then use the Transformation Layer to process results. Understanding this ordering matters when tracing what triggered what during a debug session.
Debugging Flows: Use the Console and Flow Logs
When a flow isn't behaving as expected, your primary tools are the Flow Console and execution logs. Every transform node exposes its input and output in the console — inspect the actual data at each step without adding separate debug nodes. Check the console of the relevant transform section before assuming the problem is upstream.
FUUZ JSONATA BINDINGS
Not Just JSONata —
Fuuz JSONata
Standard JSONata is the foundation, but Fuuz extends it substantially with platform-specific bindings. These give you access to screen state, user identity, flow context, join operations, and more. When you're building in Fuuz, you're using Fuuz JSONata — significantly more powerful than the open-source baseline.
Two Execution Contexts — Know Which One You're In
Screen expressions run client-side. You have access to $components, $metadata, $card, data, and $$.
Data Flow expressions run server-side. You have access to $state, $state.context, and $state.claims. Screen bindings like $components are not available here.
$components- Interact with Screen Element
| Expression | What It Does |
|---|---|
$components.Form1.fn.save() |
Save the form |
$components.Form1.fn.setValue("field", val) |
Set a single field value programmatically |
$components.Form1.formState.dirty |
true when unsaved changes exist |
$components.Form1.formState.valid |
true when all validations pass |
$components.Form1.data.fieldName |
Read a field value directly |
$components.Table1.fn.search() |
Trigger table search / refresh |
$components.Table1.selectedRows |
Array of all selected rows |
$components.Table1.selectedRows[0].id |
First selected row's ID |
$components.Screen.fn.setContextValue("k", v) |
Set a single screen context key |
$components.Screen.fn.mergeContext({...}) |
Shallow-merge values into screen context |
$components.Screen.context.myKey |
Read a screen context value |
$metadata — URL, User, Tenant
| Expression | What It Does |
|---|---|
$metadata.urlParameters.id |
URL path parameter (e.g. /record/:id) |
$metadata.querystring.tab |
Query string parameter (?tab=details) |
$metadata.user.id |
Logged-in user ID |
$metadata.user.email |
Logged-in user email |
$metadata.user.roles |
Array of user roles |
$metadata.tenant.id |
Current tenant ID |
$metadata.tenant.name |
Current tenant name |
$metadata.settings.timezone |
User timezone |
$metadata.settings.dateFormat |
User date format string |
$state — Data Flow Context
| Expression | What It Does |
|---|---|
$ |
Current node payload — shorthand for $state.payload |
$state.payload |
Full current node input payload |
$state.context |
Shared flow context (set via Set/Merge Context nodes) |
$state.context.myKey |
Read a specific context value |
$state.claims.userId |
Triggering user ID from auth |
$state.claims.tenantId |
Tenant ID from auth claims |
$state.claims.roles |
User roles from auth claims |
$state.metadata.flowId |
Current flow ID |
$state.lastError |
Error from last caught error node |
data, $card & $$ — Element-level Bindings
| Expression | What It Does |
|---|---|
data.fieldName |
Read a field value inside a Form element |
data.active ? "Yes" : "No" |
Ternary on a boolean form field |
$card.data.id |
Card record ID — use inside Cards elements (not data.id) |
$card.data.status |
Card record field value |
$$.newValue |
New value in an onChange handler |
$$.oldValue |
Previous value in an onChange handler |
$isNotNilOrEmpty($$.newValue) and $not($$.newValue = $$.oldValue) |
Guard: only fire when non-empty and actually changed |
Fuuz Join Functions & Utility Bindings
Critical JSONata Syntax Gotchas
| Gotcha | Correct Usage |
|---|---|
No ! operator |
Use $not(expr) instead of !expr |
String concat is & |
"a" & " " & "b" — not + |
Equality is = |
x = "val" — not == or === |
| Membership check | x in [1,2,3] — not .includes() |
No null coalescing ?? |
$exists(val) ? val : "default" |
| Cards vs Form data | Inside Cards: $card.data.x — not data.x |
Context is $ |
$ = entire current input. Confirm shape in the console before writing transforms. |
MENTAL MODEL
Coming from SQL?
Reframe These 5 Things
These are the specific mental model shifts that trip up experienced engineers when they first build on Fuuz. These are the closest useful parallels — not a 1:1 mapping, the platforms are genuinely different.
| SQL / Relational Normalize everything. Every sub-entity gets its own table. Reconstruct the object at query time with JOINs. | → | MongoDB / Fuuz Design for your access pattern. Data that always travels together belongs together. Think in objects first, storage second. |
| SQL / Relational Schema changes are risky: ALTER TABLE, migration scripts, deployment windows, potential table locks. | → | MongoDB / Fuuz Add a field in the Fuuz schema designer — live instantly, zero downtime. Schema field changes are low-risk, fast tasks. |
| SQL WHERE / GROUP BY Filter and aggregate in the database query engine using SQL clauses. | → |
GraphQL Predicates / _aggregate
Filter at the GraphQL API layer. Use _aggregate for counts and sums. JSONata reshapes the result — it does not filter it.
|
| SQL JOINs Combine data from multiple tables using INNER JOIN, LEFT JOIN, computed by the DB engine. | → | Fuuz JSONata $innerJoin / $leftOuterJoin Fuuz provides join functions to combine result sets from multiple GraphQL queries in a flow transform. |
| On-prem / Hosted SQL Infrastructure is your team's problem. Backups, upgrades, scale events, DR planning — all on you. | → | AWS SaaS / Fuuz All infrastructure is managed. Focus entirely on application delivery. Application performance on large datasets is still your design responsibility. |