How table definitions work
Table definitions are managed from the admin panel’s three-pane browser. Once a profile and table are selected there, five dedicated pages carry out the individual actions. Creating a table is a separate builder page, because its form is long enough to deserve its own screen.
Every page here requires the struct:table manage permission. A missing
session redirects to /login; a session without the permission receives
403 with a table-management message.
The pages
Section titled “The pages”| Action | Route | Page |
|---|---|---|
| Add columns to a table | GET/POST /admin/tables/columns |
Columns and appending |
| Rename a column | POST /admin/tables/rename |
Renaming columns |
| Delete a table | GET/POST /admin/tables/delete |
Deleting tables |
| Copy a profile | GET/POST /admin/profiles/copy |
Copying profiles |
| Generate from an invoice template | GET/POST /admin/tables/from-template |
Invoice templates |
| Read rename history | GET /admin/profiles/history |
Rename history |
The old combined /admin/table-definition workspace responds with a permanent
redirect to /admin.
How a selection travels
Section titled “How a selection travels”The table-scoped pages (columns, delete, history) are entered with
?profile=<name>&table=<name>. The profile-scoped pages (copy, template) drop
the table, because they act on a whole profile. The write forms carry the
selection in hidden fields, since a write answers with the page re-read from
the backend rather than whatever the browser still had on screen.
After a successful write, each page re-reads itself from the backend and shows
the definition as it now is — not the form you submitted. A refused write
answers the same way but with 422 and the backend’s own message.
Scope rules
Section titled “Scope rules”A profile’s own tables come from the profile tree; the Global scope’s tables
come from the table catalog. The Global scope is labeled “Global — all
profiles” in page headings instead of its internal name __global.
System tables are backend-managed. The server refuses every structural write on them, so the pages do not offer the write panels for a system table.
The column vocabulary
Section titled “The column vocabulary”The add-column panel and the create-table builder share one vocabulary, read
live from the backend’s ListColumnTypes endpoint. A type the server adds is
offered by both screens without a change here, and a type it stops accepting
disappears from both.
Notable rules of that vocabulary:
- Groups collapse related types into one picker choice —
temporalfor the date/time types andgtinfor the GTIN lengths — resolved by a follow-up field. - Parameterised types must spell their arguments, such as
decimal(12,3). - Link types must name their target, such as
link(customer). - Creation-only types (
accounting,accounting_transfer) can be chosen only while a table is being created, not when appending to an existing table. - Compound types are definition rows that expand into schema-managed companion columns and leave no column of their own name behind; they cannot be indexed or identify a row.
- Currency and quantity-ledger rules come from the response, so
moneyandaccountingrequire a currency, while quantity-ledger is limited to the types the server marks as allowing it.
System column names (id, deleted, created_at, row_revision) stay
reserved for user columns too, because they share one namespace in a data
request.