Overview
Genie is a low-code framework: you describe your data and screens in small XML files, and Genie turns them into working, model-driven tables and forms backed by a real database — with auth, RBAC, workflow, wizards, sequences, imports/exports and notifications already built in.
This repository is a re-platform of the original server-rendered Genie (mr-aybee/zed) into a
JSON API + React front end. The single rule that shapes the whole codebase follows from that:
Structure and values come from the engine; layout, DOM and presentation are owned by the UI.
The mental model
Section titled “The mental model” author XML compile + run render *.entity.xml ─┐ ┌─ Genie.Source (source gen) ─┐ ┌─ genie-engine-ui (React) *.view.xml ─┼──────▶ │ → EF entities + tables │ JSON │ GenieTable / GenieForm / *.sql ─┤ ├─ Genie.Engine (runtime) │ ─────▶ │ GenieView / GenieNavbar *.navbar.xml ─┘ └─ → metadata + data + RBAC ─┘ └─ from createGenieApp({...})- You write XML models — entities (tables), views (grids/forms), navigation, and SQL objects.
Genie.Source(a Roslyn source generator + the schema types + the XML parsers) turns*.entity.xmlinto strongly-typed EF Core entities at compile time, so a normaldotnet ef migrations addmaterialises real tables.Genie.Engine(the runtime) loads the views/entities at startup (model migration), resolves them per request, runs the SQL, enforces RBAC, and returns JSON (metadata + values).genie-engine-ui(React) consumes that JSON and renders the tables, forms, views, navbar, auth screens and theme — configured entirely in code viacreateGenieApp({...}).
A view is one unified object
Section titled “A view is one unified object”A *.view.xml file (root element <Table>) describes one object. Whether it behaves as a
grid, an editable form, or a read-only view is inferred from which SQL blocks it declares — there
is no separate “table view” vs “form view” type. Internally this is the unified ObjectView, and the
runtime is a facade over focused query / form / action services.
Endpoints: structure vs data
Section titled “Endpoints: structure vs data”A boundary worth knowing up front — the React client reads the schema once, then loads data:
GET /api/v1/genie/object/{name}/metadata— the object’s SQL-free schema (type, capabilities, columns, fields, layout). Static and cacheable; no SQL, no per-user row values. The UI decides table vs form vs view from this.POST /api/v1/genie/object/{name}/table— a page of grid rows (+ pagination + per-user permission facts).POST /api/v1/genie/object/{name}/form//view— a single record’s field values, editable or read-only.POST /api/v1/genie/object/{submit,delete-row,execute-row-action,export-data,import-data,…}— mutations and bulk operations, behind the RBAC data-disclosure gate.
Every response is wrapped in a SuccessDataResult<T> envelope. See the
API Reference for the full list.
Where to go next
Section titled “Where to go next”- Quickstart — run the sample and add your first entity + view in minutes.
- The three packages — what
Genie.Source,Genie.Engineandgenie-engine-uieach do. - Model Authoring — the complete XML authoring reference (every field type, layout, action, filter, badge).
- Integration — drop Genie into your own backend + frontend.