Our system architecture: frontend, backend and infrastructure on Fractal 2

How we build systems for businesses: a description in three languages instead of hand-written code, React and TypeScript on the frontend, Yii 2 and a REST API on the backend, Docker and observability in the infrastructure, and AI kept in check by automated tests.

Our system architecture: frontend, backend and infrastructure on Fractal 2
INGELLO / BUSINESS3056

Most of the systems we build for businesses are not typed out by hand from scratch; they are described. We define the data structure, the screens and the links between them in three small languages, and the Fractal 2 generator turns that description into a database, a documented REST API, an admin panel, a React interface and a technical specification. Below is how it all fits together: frontend, backend, infrastructure, where AI sits in the process, and the checks without which generated code cannot be trusted.

Every screenshot was taken on a working test bench. The running example is Dubrava, a furniture factory, and all its data is test data. The Fractal 2 studio in the screenshots has a Russian interface, while the Dubrava app itself is in Ukrainian.

Our system architecture: frontend, backend and infrastructure on Fractal 2
Six lines of client brief and the screen map Claude assembled from them: 18 screens and 15 models

The approach: a description instead of code

Conventional development keeps the same system in several places at once: in the specification, the database schema, the backend code, the frontend types and the API documentation. Every change has to be made everywhere, and within six months those places start to drift apart. The documentation lies, the frontend expects a field that no longer exists, and an integration breaks for no obvious reason.

In Fractal there is a single source, written in three languages:

  • SFL (Structurer Fractal Language) describes the data: tables, fields, types, relations and modules;
  • IFL (Interface Fractal Language) describes the screens: the grid, components, fields and transitions, plus business logic directives;
  • ISFL describes the screen map: which screens exist, which patterns they are built on and how they link together.

The generator derives everything else from that description. So changing the structure takes minutes, and the documentation and code cannot drift apart by definition: they are built from the same place.

Diagram: the client brief, ISFL, SFL and IFL feed into the Fractal 2 generator, which outputs the database, models, REST API, types, admin panel, screens, test data and specification
One description produces eight parts of the system

This is what SFL looks like. One line describes one column, a field ending in _id becomes a foreign key, and an exclamation mark makes the field required:

User|user
Name|name !
Email|email !

Order|order
User|user_id !
Amount|sum float(10,2)
Status|status
Created|created_at

The table name prefix sets the module, as in Odoo: sales_order goes into the sales module, wh_stock into the warehouse module. Admin menus, API sections, ER diagrams and specification chapters are then split by module automatically.

From client brief to working system

Dubrava has forty staff, two workshops, a warehouse of boards and fittings, three showrooms and a website. Everything lives in Excel and messaging apps, orders get lost and deadlines slip. The director wants to follow every order from measurement to installation, cost each job from materials and labour, plan workshop capacity, run the warehouse and purchasing, and keep track of payments.

An analyst pastes this text into the studio as it is, as a file or by voice. From there the path is:

  1. Claude breaks the brief down into screens, patterns and models. The result is an ISFL map that the analyst edits on a graph, adding screens and connecting transitions with arrows.
  2. From the map, Claude designs the data schema with modules and comments. The SFL parser checks the response and, if it finds errors, sends it back for correction.
  3. The generator builds the database, backend, API, admin panel and screens, then checks that everything responds.

For Dubrava that comes to 22 tables and 157 columns across three modules (clients and orders, production, warehouse), plus 18 screens containing 60 components and 237 elements. Not a single parser error or warning.

SFL editor in the Fractal 2 studio and an ER diagram of 22 tables with a module filter
SFL with highlighting and live validation; on the right, the ER diagram with a module filter
IFL editor in the studio: order list and order creation screens with a preview built from components
IFL: a screen described as rows, columns and components, with a preview on the right

Frontend: React assembled from the description

Every IFL screen becomes a React 19 and TypeScript 7 page built from our UI kit on Material UI 9. Data arrives through TanStack Query, Vite handles the build, Chart.js draws the charts and Leaflet the maps. The interface is responsive from 360 px, comes with light and dark themes, and supports Ukrainian, Russian and English.

The key architectural decision here: the TypeScript types and the API client are generated from the same schema as the backend. If a field changes in SFL, the frontend finds out at type-checking time, not from a user in production.

The frontend only displays. Calculations, validation and data changes live on the server, so the rules cannot be bypassed from the browser. Components that standard patterns cannot describe are created once as a stub and from then on belong to the developer: the generator does not overwrite them.

Generated order list screen in the Dubrava app: a table with filters by client, showroom, furniture type, status and stage
The Orders screen, shown in the app's Ukrainian interface: a sortable table with a filter row for every field and relation
Order card with client, showroom, stage, totals, payment and estimate line items
Order card: related records are pulled from the API in a single request
The same order list on a phone screen 390 pixels wide
The same screen on a phone

The admin panel is not written separately. It is built from the schema metadata: a table, search, filters, sorting, a card with related records, a form and deletion for every model, and menus grouped by module.

Admin panel generated from the schema: models grouped by module, each with its record count
Admin panel with three modules: clients and orders, production, warehouse

Backend: API first, logic only on the server

The server runs on PHP 8.4 and Yii 2, with a MySQL 8.4 database on InnoDB with foreign keys and utf8mb4. Every table immediately becomes a REST resource: paginated lists, filters by field and relation, search, sorting, expanding relations in a single request, aggregates, actions and service methods. The OpenAPI 3.1 description of the API is generated from SFL, and interactive documentation is available at /docs.

The frontend and the admin panel call the same API as external systems do. So integrating with a CRM, 1C, a website or an AI agent needs no separate development: the API already exists and is already documented.

Our system architecture: frontend, backend and infrastructure on Fractal 2
API documentation is built automatically, with example requests

Business logic lives only in server-side services. IFL directives become their methods: before-save and after-save events, button actions, calculations for screens. The method body is written by a person or by CodeGen, which is covered below.

Security is on by default:

  • role permissions are checked on the server, and the interface merely reflects them;
  • secret account columns are unavailable in filters and aggregates;
  • the token is accepted only in the Authorization: Bearer header;
  • studio requests that change data carry a separate anti-CSRF header, and after 10 failed sign-ins within 10 minutes, sign-in is blocked.

Why Yii 2 rather than a fashionable framework? The 2.0.55 core, with no known vulnerabilities, runs on PHP 8.4 and MySQL 8.4. Rewriting a working foundation for the sake of fashion means spending the client's money on something they will never see.

Request diagram: staff member, Caddy, React app, REST API, services, MySQL; Docker infrastructure with OpenTelemetry and ClickStack observability
The path of a request through a generated application

The generation pipeline and changes without data loss

Generation runs as a background job with a step log: PHP-FPM has a 45-second limit, and building a project takes longer. The studio shows the progress of each step in real time.

Ten-step generation pipeline: validation, database, backend, data, client, screens, documents, build, API check, manifest
Generation counts as successful only if every resource and screen has responded

Two things make regeneration safe at any point in a project:

  • Your own code is never lost. Base classes and the _generated folder are overwritten, stubs are created once, and the manifest stores file hashes and deletes an outdated file only if nobody has edited it.
  • The database changes through migrations. Change mode compares SFL with the live database, writes a Yii migration with rollback and applies it. Columns missing from the description are not dropped. Migration history and a rollback button are available in the studio.

That is why a client's system can evolve together with its description instead of being frozen after the first version.

Where AI works and why it can be trusted

The generator uses Claude Opus 5.5 through the Agent SDK on a subscription. It breaks the brief down into screens, designs the data schema, populates reference lists (statuses, types, stages) and writes custom components and service methods. We use it in two modes, and both are constrained:

AI workflow diagram: studio, Node bridge with the Agent SDK, Claude; JSON schema response mode and agent mode with file restrictions; what is closed off to AI
AI goes through the same checks as code written by a person
  • Responses strictly to a JSON schema. No tools and no file access. The parser checks the response, and if there is an error it is sent back for correction up to two times.
  • The CodeGen agent. It reads only the project code and writes only to permitted files: the custom component and the screen's services. After edits, type checking runs, errors get one round of correction, and forbidden calls are rolled back.

.env files, secrets and the runtime are closed off to AI, and the bridge environment is stripped down to the subscription token and the path to the programs. A CodeGen task can be dictated by voice right in the studio: the component is added as a line in IFL, the generator creates a stub, and the agent completes it.

The CodeGen tab in the studio, labelled КодГен in its Russian interface: screen selection, task description, microphone and agent launch
CodeGen in the studio: pick a screen, set the task in text or by voice, launch the agent
Calendar screen for measurements and installations in the Dubrava app, with a custom component stub awaiting completion
The Calendar component stub before CodeGen runs: the task and the file path are already on screen

Infrastructure: one setup for every project

Every project runs in Docker Compose. The application container with PHP-FPM 8.4 and Node 24 is shared across projects, with a common vendor directory, while MySQL 8.4 runs separately with backups and scheduled jobs. Caddy with TLS handles the entry point for every address.

Each container has memory and CPU limits. This is a deliberate decision: generation, tests and video have to run alongside other work rather than eat up the whole machine. Container logs and metrics are collected by OpenTelemetry and sent to ClickStack (ClickHouse and HyperDX), configured to be economical.

Fractal 2 stack with logos: React, TypeScript, Material UI, TanStack Query, Vite, Chart.js, Leaflet, PHP, Yii 2, MySQL, Composer, OpenAPI, Scalar, Claude, Agent SDK, Node.js, Docker, Caddy, OpenTelemetry, ClickStack, Git, Playwright, FFmpeg
Versions are pinned in the images; a generated project gets the same stack

Checks: never take generation on trust

Fractal 2 is tested at three levels:

  • Generator tests: 45 tests and 1,277 checks in 1.3 seconds. Parsers, patterns, modules, migrations with rollback, code generators, the specification and CodeGen safeguards.
  • Every generation: type checking across the entire frontend plus an HTTP check: sign-in, list and record for every resource with relations expanded, service methods, every screen and the admin panel.
  • Browser: Playwright opens every screen, fills in and submits forms, applies filters, sorts tables, and creates and deletes records in the admin panel.

A run across ten registry projects on 27 October 2026: 799 pages and 593 actions, zero errors. The same engine records narrated video walkthroughs of the screens, and FFmpeg stitches them into a single film.

Our system architecture: frontend, backend and infrastructure on Fractal 2
Generator tests run at the click of a button right in the studio

A specification built from the same description

The technical specification for client sign-off is generated too: the stack, the data model by module with ER diagrams, requirements with identifiers and acceptance criteria, screens, the API, non-functional requirements, acceptance and an effort estimate. The document can be copied into Google Docs with its tables and diagrams, or downloaded as DOCX.

Technical specification generated from the system description, with export to Google Docs and DOCX
The specification in Ukrainian or Russian, exported to Google Docs, DOCX and Markdown

What the client gains and where the limits are

  • Speed at the start. A working prototype with a database, API and screens appears before the first line of business logic is written, so the discussion is about the product rather than mock-ups.
  • Documentation that does not lie. The specification, the API and the code are built from one description.
  • Integrations without a separate project. Everything the user sees is available through the documented API.
  • Ordinary code as output. It is Yii 2 and React, readable by any PHP or React developer.

The honest limit: the generator covers the standard part of a system. The rules a business commissions a system for (costing an estimate from materials, planning workshop capacity, complex payment statuses) are designed together with the client and written by people or by CodeGen, under the control of the checks. How this breaks down into stages and budgets is set out in our app development strategy, and a Fractal prototype corresponds to the prototyping stage. The first generation of the generator is described in the Fractal case study.

In a free consultation, an Ingello architect will look at your task and show you which part of the system can be built from a description and which will need manual work. Afterwards you will receive a price and timeline estimate broken down by stage. Book a consultation.

Frequently asked questions

01What is Fractal 2 and how does it differ from a no-code builder?

Fractal 2 is Ingello's in-house generator. A system is described in three languages: SFL for data, IFL for screens and ISFL for the screen map. From that description the generator builds a MySQL database, a Yii 2 backend, a REST API with OpenAPI 3.1, an admin panel, React screens and a technical specification. Unlike a no-code builder, the output is ordinary code that developers extend and maintain.

02What stack does a system generated with Fractal 2 get?

The frontend uses React 19, TypeScript 7 and Material UI 9 with TanStack Query, built with Vite. The backend runs on PHP 8.4 and Yii 2 with a MySQL 8.4 database. The API is described in OpenAPI 3.1 and its documentation opens in Scalar. The infrastructure runs in Docker Compose with Caddy, and OpenTelemetry collects logs and metrics into ClickStack. Playwright handles the browser checks.

03Will manual changes be lost when the system is regenerated?

No. The generator overwrites only the base classes and the _generated folder. Stubs for custom components and services are created once and from then on belong to the developer. The manifest stores hashes of the generated files and deletes an outdated file only if nobody has edited it. The database structure changes through migrations with rollback, without deleting data.

04How does the generator use AI, and is it safe?

Claude Opus 5.5 works through the Agent SDK in two modes. In the first, it responds strictly to a JSON schema: a parser checks the response and, if there is an error, sends it back for correction up to two times. In the second, the agent reads only the project code and writes only to permitted files, followed by type checking and rollback of forbidden calls. The .env files, secrets and runtime are closed off to AI.

05How do you verify that a generated system actually works?

At three levels. Generator tests: 45 tests and 1,277 checks. Every generation type-checks the frontend and checks every API resource and every screen over HTTP. A Playwright browser run opens the screens, fills in forms and creates records: across ten projects on 27 October 2026 that came to 799 pages and 593 actions without a single error.