Download

Generate SaaS applications from JSON schemas.

Build enterprise applications with declarative JSON schemas instead of thousands of lines of boilerplate. Nor Abon generates your database, API and administration interface, leaving only your business logic to implement.

How it works

Nor Abon brings together declarative JSON schemas and custom business logic in a unified AI-native architecture that automatically generates APIs and admin panels.

JSON database schemas

Describe entities, fields, relationships, and data storage structures.

JSON objects schemas

Define application entities, permissions, and field behavior logic.

JSON commands schemas

Define the list of available commands for entities and configure permissions.

JSON pages schemas

Describe administrative pages, forms, tables, and other interface elements.

Custom logic

Extend standard functionality with isolated business logic.

API

Automatically generated SaaS admin panel.

Nor Abon provides a universal API layer for a SaaS ecosystem.
It enables any external or internal clients (web, mobile, desktop, IoT, and automated services) to connect to a unified core of business logic.

AI-first architecture

Less context

Most of the application is defined using compact JSON schemas instead of large files with mixed logic.

Predictable Architecture

Every Nor Abon project follows the same architectural principles. Pages, components, objects, actions, and APIs are defined consistently, eliminating dozens of competing patterns and conventions.

Isolated Business Logic

Most repetitive infrastructure code is generated automatically by the framework. There's no need to manually create controllers, DTOs, services, forms, access policies, or other boilerplate components.

Less boilerplate means fewer bugs, easier maintenance, and faster development.

Less boilerplate.
More business logic.

Nor Abon automates the repetitive parts of CRM and SaaS development through declarative schemas. Define your data model once, and let the framework build the database, API, validation and administrative interface.

  • Schema-Driven architecture
  • Generated CRUD and admin pages
  • Predictable project structure
  • Custom actions for business logic
  • Modular and extensible design
  • Framework updates independent of your application
{
    "title": "Add account",
    "type": "add",
    "object_scheme": "accounts",
    "required_permissions": [ "accounts", "accounts_add" ]
}
{
    "title": "Clients",
    "table": "clients",
    "is_trash": true,
    "properties": [
        {
            "title": "First name",
            "article": "first_name",
            "data_type": "string",
            "field_type": "string",
            "is_default_in_list": true,
            "is_unique": false,
            "is_autofill": true,
            "required_permissions": [],
            "use_in_actions": ["add", "update"],
            "require_in_actions": ["add"]
        },
        {
            "title": "Last name",
            "article": "last_name",
            "data_type": "string",
            "field_type": "string",
            "is_default_in_list": true,
            "is_unique": false,
            "is_autofill": true,
            "required_permissions": [],
            "use_in_actions": ["add", "update"],
            "require_in_actions": []
        },
        {
            "title": "Patronymic",
            "article": "patronymic",
            "data_type": "string",
            "field_type": "string",
            "is_default_in_list": false,
            "is_unique": false,
            "is_autofill": true,
            "required_permissions": [],
            "use_in_actions": ["add", "update"],
            "require_in_actions": []
        },
        {
            "title": "Email",
            "article": "email",
            "data_type": "email",
            "field_type": "email",
            "is_default_in_list": false,
            "is_unique": true,
            "is_autofill": true,
            "required_permissions": [],
            "use_in_actions": ["add", "update"],
            "require_in_actions": []
        },
        {
            "title": "Phone",
            "article": "phone",
            "data_type": "phone",
            "field_type": "phone",
            "is_default_in_list": false,
            "is_unique": true,
            "is_autofill": true,
            "required_permissions": [],
            "use_in_actions": ["add", "update"],
            "require_in_actions": []
        }
    ]
}
{
    "title": "Call history",
    "properties": [
        {
            "title": "Employee ID",
            "article": "employee_id",
            "type": "int",
            "default": null,
            "is_required": "Y"
        },
        {
            "title": "Client ID",
            "article": "client_id",
            "type": "int",
            "default": null,
            "is_required": "N"
        },
        {
            "title": "Duration (sec)",
            "article": "duration",
            "type": "int",
            "default": null,
            "is_required": "N"
        },
        {
            "title": "Record",
            "article": "record",
            "type": "varchar(255)",
            "default": null,
            "is_required": "N"
        },
        {
            "title": "Created at",
            "article": "created_at",
            "type": "datetime",
            "default": "CURRENT_TIMESTAMP",
            "is_required": "Y"
        }
    ]
}
{
    "required_permissions": [],
    "required_modules": [],
    "structure": {
        "header": {
            "title": "Page header",
            "size": 3,
            "type": "header",
            "required_permissions": [],
            "required_modules": [],
            "settings": {
                "title": "users",
                "annotation": "",
                "breadcrumbs": []
            },
            "components": {}
        },
        "users": {
            "title": "Users list",
            "type": "list",
            "size": 4,
            "settings": {
                "object": "users"
            },
            "components": {
                "filters": [
                    {
                        "title": "Role",
                        "type": "list",
                        "settings": {
                            "is_search": false,
                            "recipient_property": "role_id",
                            "donor_object": "roles",
                            "donor_property_title": "title",
                            "donor_property_value": "id"
                        },
                        "required_permissions": []
                    }
                ]
            }
        }
    }
}
if ( !$requestData->sort_by ) {

    $requestData->sort_by = "last_name";

}
if ( $requestData->context->block === "list" ) {

    /**
     * Specifying the Promotion Period and Type
     */

    $returnRows = [];

    foreach ( $response[ "data" ] as $row ) {

        $detailPromotion = $API->DB->from( "promotions" )
            ->where( "id", $row[ "id" ] )
            ->limit( 1 )
            ->fetch();


        $row[ "period" ] = date( 'Y-m-d H:i', strtotime( $row[ "start" ] ) ) .
            " - " . date( 'Y-m-d H:i', strtotime( $row[ "end" ] ) );

        if ( $detailPromotion[ "promotion_type" ] == "percent" )
            $row[ "value" ] =  $row[ "value" ] . "%";
        else if ( $row[ "promotion_type" ] == "fixed" )
            $row[ "value" ] =  $row[ "value" ] . "$";


        $returnRows[] = $row;

    } // foreach. $response[ "data" ]

    $response[ "data" ] = $returnRows;

} // if. $requestData->context->block === "list"
$listOfStores = $API->DB->from( "stores" )
    ->where( "is_active", 'Y' );

foreach ( $listOfStores as $store ) {

    $payments = mysqli_query(
        $API->DB_connection,
        "SELECT * FROM sales WHERE pay_type = \"sell\" AND is_active = \"Y\" AND store_id = {$store[ "id" ]}"
    );

    $incomeBalance = $API->DB->from( "cashboxBalance" )
        ->where( "store_id", $store[ "id" ] )
        ->orderBy( "created_at DESC" )
        ->limit( 1 )
        ->fetch();

    $paymentsSummary = 0;
    $incomeBalance = $incomeBalance[ "balance" ] ?? 0;

    foreach ( $payments as $payment ) $paymentsSummary += $payment[ "summary" ];
    $paymentsSummary += $incomeBalance;

    $API->DB->insertInto( "cashboxBalance" )
        ->values([
            "balance" => $paymentsSummary,
            "store_id" => $store[ "id" ]
        ])
        ->execute();

} // foreach. $listOfStores

Docs

Pricing

Lifetime License
$ 295
One-time payment.
All future updates included.

FAQ

Yes. Once you purchase a license, you can build commercial applications without paying any royalties. All future framework updates are included.
Every license includes all future updates at no additional cost.
No. The framework generates the administration interface from schemas, allowing you to focus on backend logic.
No. Nor Abon is a framework for building CRM, ERP and other business applications. It follows a Schema-Driven approach and automates much of the repetitive infrastructure typically required in administrative systems.
No. Although CRM systems are the primary use case, Nor Abon is suitable for ERP, inventory management, booking systems, internal business tools and other data-driven SaaS applications.
Yes. The backend is independent from the administrative interface. You can use the API with your own frontend or integrate it into an existing project.