[Open Source] Creating a Backend Page in Five Minutes: Comparing AI-Powered Low-Code Design with Traditional Methods

[Open Source] Creating a Backend Page in Five Minutes: Comparing AI-Powered Low-Code Design with Traditional Methods

AI-generated Examples Based on PRD Screenshot Annotations

Tool: Fundamjs

Preview

Evolution of Low-Code Implementation Approaches

0. Non-AI – Json Schema Generation

UI Construction

Develop a builder that supports multi-level structure creation. Through dragging, setting component properties, and other operations, it can ultimately generate a JSON similar to a Json Schema.

Builder Basic Layout

Table Column Configuration

This article does not primarily focus on explaining the builder implementation, but here are some key points:

For the simplest drag-and-drop UI construction, vertical stacking without nested items may suffice for basic scenarios. However, for more complex cases, like grouping within a form in a modal with different titles, you need to plan different UI component types (container vs non-container components) and their compatibility (e.g., a Card’s extra section cannot contain a Table).
Many component properties share common attributes, such as required fields and label width for form items, and common container configurations like Table expand rows or Modal content. Plan these attributes in advance.
Common component combinations can be templated, such as a filter card template with a card, form container, a sample form item, and a button group (reset + query).
Common page component combinations can also be templated, like a CRUD page with a filter card, list card, sample button, and modal, pre-configured with relationships.

Interactivity Configuration

Active Triggers

The most common form of interactivity configuration is active triggers, where an action is directly assigned to a button click, like opening a modal. For instance, configuring a reset button in a filter form to reset the entire form and refresh the list.

Passive Triggers

This is a common approach in functional programming. Consider a list page where queries, resets, additions, deletions, and modal edits all require refreshing the list. Configuring each button to refresh the table directly is inefficient. Instead, use a system-level hidden field or query field. Based on the abstract action type (discussed later), determine if a page data refresh is needed, and update the system field (like the last update time) for the table to monitor and refresh accordingly.

Action Encapsulation

To achieve zero-code construction in the builder, encapsulating various actions is crucial. In modern web applications, numerous functions can be abstracted into common actions, such as:

Updating URL parameters
Fetching and displaying remote data
Submitting remote data
Modal operations
Confirmation modals
Confirmation popups
Form clearing
Form resetting
Clearing selected table rows
And more…

After encapsulating these common actions, similar to component property configuration, identify their commonalities and differences to allow zero-code configuration of actions for UI components.

🔔 These ideas apply not only to backend construction but also to web pages, mini-programs, and even apps.

Data Pool – Optimizing Passive Triggers and Interactivity

Consider a form where selecting A in a radio button shows an input field, while selecting B hides it. How to configure this in the builder? You might think of an active approach like a form builder. But what if selecting A in the radio sends a remote request, and the response determines the visibility?

To handle various complex interactivity scenarios, manage all component states and data, API states and data, query data, history data, table row data, etc., globally. Abstract them into reactive objects, including component props, state attributes, and real-time values. This simplifies passive triggers, as you only need to link the relevant data pool attributes.

Aliases

To make selecting interactive components and data dependencies more intuitive in the builder, configure aliases for each component, request object, etc., instead of displaying less readable unique IDs.

Sample Schema

At this point, any interactivity can be configured through the data pool. Here is a sample schema snippet:

{
“GnarButton_fYfcaz”: {
// Globally unique ID, name of the Field object in the data pool
“$id”: “GnarButton_fYfcaz”,
// Alias, directly select this alias when configuring interaction in the builder
“$alias”: “Filter Form Reset Button”,
// Permission control
“$auth”: false,
// Component used
“$component”: “GnarButton”,
“$slot”: {},
// props configuration
“$componentProps”: {
“title”: “Reset”,
“block”: false,
“danger”: false,
“disabled”: false,
“ghost”: false,
“type”: “default”
},
// Triggers two actions are triggered in series here
“$triggers”: [
{
// Common properties of all actions
// Trigger method
“condition”: “onClick”,
// Action type
“action”: “FORM_RESET”,
// Observe data in the data pool, not observing here, can also trigger when observed value changes
“observe”: [],
// Execution rule, data in the data pool or a js expression. If the result is false, this action will not be executed
“rule”: “”,

“external”: {
// FORM_RESET specific properties, specify which forms to reset, can reset multiple forms at once
“components”: [
“GnarForm_XhzQBB”
]
}
},
{
“condition”: “onClick”,
// Update the query in the address bar
“action”: “QUERY_SUBMIT”,
“observe”: [],
“rule”: “”,
“external”: {
// Parameters to be updated sourced from the data pool
“params”: [
{
// With a key, the value obtained by wrapping valuePath is an object
“key”: “”,
// Data pool value path
“valuePath”: “GnarForm_XhzQBB.form.values”
}
],
// Input/output parameter conversion, can add some extra parameters for remote requests, query updates, etc., and rewrite some parameters returned by remote
“pipe”: {
“params”: {
// Reset to the first page after reset
“pageNum”: 1
}
}
}
}
]
}
}

Data Pool Dependency Configuration Display

The above configuration may seem complex but is just a few selections in the builder.

1. Non-AI – JS/TSX Code Generation

Explanation

Anyone who has worked on schema-generated pages/components or directly from the Json Schema generation above knows: generating a schema for a moderately complex CRUD page can be much larger than the code. This raises some issues:

Should the builder platform manage the entire lifecycle of component, page, and project construction (initial construction, later iterations, refactoring, etc.), or just generate JSON/code once? What if the builder cannot meet some needs?
(tips: If managing the entire lifecycle, plan for unmet scenarios, e.g., design Scope objects to include user-written components/methods, showing a placeholder in the builder).
The generated Json Schema is not very readable, making it hard for new users to grasp. Without mandatory adoption, those who understand all concepts might improve efficiency, but those resistant to new technologies might avoid the builder and find hand-coding schema difficult.

Generating jsx/tsx Code

To address the readability and usability issues, I abstracted action template code and created a feature to configure forms with the generated code. This involves AST parsing, allowing three configuration modes in the builder: UI configuration, data & interaction form configuration, and code writing.

Implementing Two Actions for a Reset Button

After configuring two actions for the reset button in the Interaction and Data section, it no longer generates JSON but directly generates a piece of js code combining multiple actions. This js code can be modified and reflected back into the configuration form.

2. AI – Fundam Builder

With the advancement of AI technology, most industry low-code/no-code builders generating data tables/models, front-end templates/models, etc., are not “intelligent” enough. These technologies typically produce hard-to-read JSON schema, js+schema mixed code, or hard-to-read jsx/tsx code, leading to the problem of “easy to build, hard to maintain.”

Fundam was created to leverage AI to generate easy-to-understand, highly readable, simple, and maintainable jsx/tsx code.

Example

AI
https://fundamjs.com/images/ai-page.gif

Here, AI annotated filter fields and remote request fields based on a PRD, generating a page with 40% functionality within a minute. Due to recording size limits, it can continue dialog for code adjustments, adding modal code, etc.

Note: Fundam aims to use the simplest code to generate various functionalities, which may seem unconventional to some experts, not following typical code modularization practices.

Currently, based on my understanding, the more code an AI needs to learn, the higher the cost, error probability, and result variability. Hence, the first version of FundamGPT was created using just three training data sets (about 500 lines of descriptions and code).

Fundam can generate code from design images, PRD diagrams, other screenshots, and text descriptions. For more examples, refer to Fundam.

Conclusion

Sorry, the images for this article and the Fundam documentation are currently only available in Chinese. However, an English version will be available soon. The good news is that you can use any language to converse with FundamGPT and generate code from the language within the images. It is powered by the robust openAI 🎉

AI / Fundam is not perfect. If the generated code is not what you want, continue the dialogue to adjust. Currently, FundamGPT has limited training data, and Fundam components are not very rich. Contributions are welcome, as more usage and data will make it stronger.

If you find this interesting, follow https://github.com/cdrslab/fundam.

If you have any suggestions, feel free to leave a comment!

Please follow and like us:
Pin Share