Framework Overview
Liberty Next sits on six configuration files under config/. Each file defines one layer of the platform; together they describe a fully working application.
| Layer | File | What it carries |
|---|---|---|
| Pools | connectors.toml ([pools.*]) | Database connections — URL, dialect, optional password / schemas / max_rows. |
| Connectors | connectors.toml ([connectors.*]) | SQL connectors (named queries) and API connectors (named endpoints). |
| Dictionary | dictionary.toml | Per-column metadata: labels, formats, BOOLEAN / ENUM / LOOKUP rules. |
| Screens | screens.toml | One screen per business object: which query to read, edit, insert, delete; the dialog tabs and fields. |
| Dashboards | dashboards.toml | Charts, KPIs and grouped layouts over the same named queries. |
| Menus | menus.toml | The sidebar tree — folders, items, permissions. |
Everything is hot-reloadable. POST /admin/reload rebuilds the registry; in-flight requests keep the version they started with.
At a glance
licensed = true connectors (nomasx1 · nomajde). The framework runs without one — just without those apps.
Layers
Pools
A pool is one SQLAlchemy async engine — postgresql+asyncpg://…, oracle+oracledb://…, sqlite+aiosqlite://…. Defined under [pools.<name>] in connectors.toml:
[pools.myapp]
url = "postgresql+asyncpg://myapp@db:5432/myapp"
password = "ENC:…" # ENC: blob, ${ENV} ref, or plaintext
pool_size = 10
max_rows = 5000 # default SELECT row cap for this pool
[pools.myapp.schemas]
PROD = "myapp_prod" # `#SCHEMA.PROD#` in a query becomes `myapp_prod` at execute time
The default pool is special — it is the framework pool and the home of the ly2_* auth tables when [auth] backend = "db". A fresh checkout points it at a local SQLite file so the app boots without a database.
Connectors
A connector is the named target a screen, a dashboard or the assistant talks to. Two types:
- SQL connector — list of named queries against a pool. Schema is discovered from
cursor.description; the dictionary supplies labels and rules per column. - API connector — list of named endpoints against an
httpx.AsyncClient. Auth:none/basic/bearer/api_key/oauth2(token-endpoint POST + dot-path extraction + TTL cache + one refresh on 401).
See Connectors for the full reference.
Dictionary
The dictionary defines per-column metadata: labels (with per-language translations), formats and display rules. Each entry pins a column's identity once; every screen that returns that column inherits them automatically:
[entries.USER_STATUS]
label = "Status"
[entries.USER_STATUS.l]
fr = "Statut"
[enums.USER_STATUS]
values = [
{ value = "Y", label = "Active", l = { fr = "Actif" } },
{ value = "N", label = "Inactive", l = { fr = "Inactif" } },
]
A column.dd = "USER_STATUS" on the query lifts the label and the ENUM rule onto the grid — the cell renders the localized label, the per-column filter offers the multi-select picker, no further code. See Dictionary.
Screens
A screen is the definition of one business object: the read query that drives the grid, the optional write queries, and the inline modal form. Defined under [screens.<app>.<id>] in screens.toml:
[screens.myapp.users]
label = "Users"
read_query = "users_get"
update_query = "users_put"
audit = true
auto_load = true
[[screens.myapp.users.dialog.tabs]]
id = "main"
label = "General"
cols = 2
fields = [
{ column = "ID", hidden = true },
{ column = "NAME", required = true },
{ column = "STATUS", colspan = 2 },
]
Clicking a row in the grid opens a typed modal form built from this. The widget per field is picked from the read query's column rule (BOOLEAN → checkbox, ENUM → searchable dropdown, LOOKUP → searchable dropdown narrowed by lookup_param_binds, plus date / number / text from format / type). See Screens.
Dashboards
A dashboard is a grid of KPIs and charts over the same named queries. Each panel binds to a query, picks an aggregation, and lays out under one of the standard chart types. See Dashboards.
Menus
The sidebar tree. Folders nest; leaves bind to a query (TableView), a dashboard (DashboardView), an endpoint (HttpRunner) or a static slug. The tree is pruned to what the caller may run — a leaf without the corresponding sql:{conn}:{name} / api:{conn}:{name} permission is dropped, and a folder left empty collapses away. See Menus.
Auth
Two backends, picked in [auth]:
| Backend | Where users live | Why |
|---|---|---|
toml (default) | config/auth.toml | No database needed at startup. Hot-reloaded on every call. Right for small deployments and tests. |
db | The ly2_* tables on the framework pool | Operator-managed users via the React Settings → Users editor. argon2 password hashes. |
Tokens are JWTs signed with LIBERTY_JWT_SECRET (or an ephemeral key when unset). OIDC against any provider is wired via authlib.
The permissions list on a role gates what the caller may run: sql:<connector>:<query>, api:<connector>:<endpoint>, admin:*. The same gate applies on the menu tree, so the operator never sees a leaf they cannot click.
License
The framework is free. Licensed connectors (licensed = true in connectors.toml) are unlocked by LIBERTY_LICENSE_KEY — an RS256-signed JWT generated by the vendor. The same JWT shape and key-pair as NomaUBL's license. A configured-but-broken key (expired or bad signature) surfaces a banner in the React UI; no key at all simply hides the licensed connectors.
This is what gates nomasx1 and nomajde — both bundled under a single key.
Frontend in one paragraph
React 19 + Vite + TypeScript, built once into frontend/dist and served as static by the backend. Dark default with a light theme swap, react-i18next EN / FR, lucide-react icons, DM Sans, @tanstack/react-table for the grid, react-markdown + remark-gfm for the assistant, @monaco-editor/react for the raw TOML escape hatch. Visual model is the same "liquid-glass" look used by NomaUBL — @emotion/styled themed components.