Files
komp_ac/web/CHANGELOG.md
2026-08-23 23:43:27 +02:00

255 lines
14 KiB
Markdown

# Changelog
All notable changes to the **komp_ac web** crate — the Axum SSR/HTMX web frontend
for the komp_ac gRPC backend — are documented in this file.
This changelog tracks only the **gRPC endpoints** the web crate consumes (the
browser never calls gRPC directly; Axum proxies to the backend through these
clients) and the extent to which each is used by the pages that mount them.
Other, non-API changes are intentionally out of scope.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
---
## [Unreleased]
### Changed
- **Editable empty-table definitions** — the table-definition column page now
calls `PutTableDefinition` to atomically remove selected columns and append
replacements, with stable column identities and optimistic revision checks.
Add-only changes continue to work for populated tables.
- **The shared profile is named by the backend** — `ProfileTreeResponse`
gained `shared_profile_name`, and every page that browses the shared tables
now reads the name from there instead of spelling `__global` itself. Catalog
discovery retains its global-only request, which does not require the shared
profile to have been created yet.
---
## [v0.8.46] — 2026-08-16
### Added
- **Role, user and permission administration** — `/permissions` consumes
`ListRoles`, `AddRole`, `RemoveRole`, `ListUsers`, `AssignUserRole`,
`ListRolePermissions`, `ListGrantableObjects`, `GrantPermission` and
`RevokePermission`. Direct and inherited grants are distinguished, and the
action controls come from each grantable object returned by the backend.
- **Table-family permissions in table definition** — selecting a table shows
its grant matrix for every editable data role. Creating a table redirects to
that table in the definition workspace so its initial grants can be assigned
immediately.
- **Password management** — `/password` consumes `ChangePassword` for the
signed-in user, while the user table consumes `ResetUserPassword` for
administrator resets allowed by the backend role hierarchy.
- **`TableDefinition.ListColumnTypes`** — called by the add-table and
table-definition loaders. The whole response is consumed: `name`, `group`,
`declarable`, `compound`, `spelling`, `requires_currency`, `creation_only`,
`allows_quantity_ledger` and `sql_type` are each read by a rule that used to
be hardcoded in `crate::schema`. The column vocabulary is now the backend's,
so a type it adds is offered by both screens without a change here.
### Changed
- **Permissions moved out of the admin panel into their own nav section, split
in three** — `/admin/permissions` is gone; the pages are `/permissions/roles`
(which roles exist), `/permissions/users` (who holds them) and
`/permissions/grants` (what a role may do). No new gRPC endpoint is consumed:
the same `GrantPermission` and `RevokePermission` calls now come from one
`POST /permissions/grants/apply`, which issues one call per `object|action`
pair so a shortcut — a whole row, a whole profile, everything — is a longer
list rather than a different request. Shortcuts grant the wildcard objects
`ListGrantableObjects` already returns (`data:*`, `data:<profile>/*`,
`journal:*`, `ecb:*`), so they keep covering profiles and tables created
later, and `AddRole` may be followed by a starter set of those grants in the
same submission. Revoking tolerates the `NOT_FOUND` a pair the role does not
hold directly answers with, which is what makes "remove all of this"
idempotent.
- **Web authorization follows permission objects, not role names** — structural
pages check their `struct:<area>/manage` permission from `GetAuthorization`,
so inherited `superadmin` authorization works and data roles are no longer
treated as administrators. Login redirects structural users to the admin
workspace and data users to analytics.
- **Import and export are their own grant actions** — the import page requires
the caller's `import` grant and the export page the caller's `export` grant,
on top of the underlying row action each transfer performs (`insert` for
import, `read` for export). A table is offered only when the caller holds
both, so the menu never leads to a transfer the backend would refuse halfway
through. Profile-tree discovery for these pages is authenticated.
- **CSV transfer system columns and header normalizing** — the import page
gained a "File includes system columns" checkbox (so `deleted` loads back as
it left) and a "Normalize headers" action that rewrites header rows into the
backend's column spellings before anything is posted; the export page gained
an "Include system columns" checkbox that adds `id`, `deleted`, and
`row_revision`. No new gRPC endpoint is consumed — these reuse
`PostTableDataBulk`, `GetTableDataByPosition`, and `GetTableDataCount`.
- **Permission mutations keep the browser session** — grants, role changes and
assignments now reload the live authorization state without replacing the
identity-only JWT. The permissions workspace reloads in place and shows the
updated effective policy.
- **The column-type picker is the server's list** — it no longer carries its
own. Types the web crate never offered are now reachable: `numeric` and the
`ACCOUNTING_TRANSFER` compound column. Server-generated companion types
(`phone_country`, `iban_bban`, the transfer connectors) are listed by the
endpoint but never offered, and are refused if one is posted anyway.
- **Creation-only types are refused on the append panel by rule, not by name** —
`POST /admin/table-definition/columns` used to exclude `accounting` alone;
it now excludes every type the response marks `creation_only`, which is what
`AddTableColumns` rejects.
- **Compound columns are staged as the backend expands them** — a compound
column takes its type's name, cannot be indexed, and is not offered as a row
display column, since no column of that name survives the expansion.
- **Currency and quantity-ledger rules come from the response** —
`requires_currency` decides which types carry a currency (previously MONEY
and ACCOUNTING by name), and `allows_quantity_ledger` both validates the
choice and writes the hint under the input.
- **`GetProfileDetails` columns show the SQL type behind them** — the
workspace's column list renders `sql_type` from the catalog beside each
logical type, including for the companion columns the backend generates.
- **`TableDefinition.GetProfileTree``depends_on` is one entry per link** —
each dependency now carries the target `table_name` and the `column_name`
holding the reference. Both the admin panel and the table-definition
workspace render each entry as `table (column)`, so a table that points at
one target twice shows as two links.
- **`AuthService.Register` — the `role` field is gone** — the request no
longer carries a client-chosen role; every registration lands as `guest`.
The register page dropped the role input and its suggestion list.
- **`EcbService.GetEcbPipelineStatus`** — a new `/admin/ecb` page (with a
polling `/admin/ecb/status` card) renders the recent ECB import batches and
their state. The page is gated on the caller's `ecb:*` read permission, and
the backend stays the authority: a caller who slips past the page check gets
`PermissionDenied` from the RPC.
- **`TableDefinition.GetTableCatalog`** — the form catalog now feeds the
add-table, table-definition, import/export and admin loaders, replacing
locally assembled table lists. Global tables appear in the catalog and are
selectable as link targets from any profile; a global table may only link to
other global tables.
- **Link columns are declarable** — the add-table page picks a link target
table from the profile's offered targets and writes `link(table)` for the
column type. A link is never indexed by the form: the server indexes it, and
the draft refuses a tampered `indexed` flag for one.
- **Columns can be made required** — add-table gained a required toggle that
travels with the column into `PostTableDefinition`.
- **`TablesData.GetTableDataCount`** — the CSV export asks for the row count
before downloading, so the export loop knows how many
`GetTableDataByPosition` pages to read.
### Not covered
The endpoints and fields below are part of the current proto surface but the
web crate does not implement them. They are listed so it stays visible what
the backend gained that this client has not wired up yet.
- **`TableValidation.DisplayMask.storage_mode`** — the new `MaskStorageMode`
option is always left absent (raw); there is no formatted-storage choice in
the validation UI.
- **`TableScript.ScriptDependency.link_column` / `name_in_script`** — the new
dependency fields are not read; the web only surfaces the id and warnings
`PostTableScript` returns.
- **`TablesData` account as a string** — accounting-enabled tables now take a
slash-delimited `account` path instead of the `account_id` reference, and
the structure endpoint exposes the column as `account`. The bulk-import and
CSV-export paths treat columns generically and were not changed; the web has
no accounting data-entry surface of its own.
## [v0.8.38] — 2026-08-05
The web crate wires up seven gRPC services and calls the following endpoints.
Coverage notes describe which pages exercise each call and how deeply its
response is consumed.
### Auth (`AuthServiceClient`)
- **`AuthService.Login`** — called by `POST /login`. Exchanges identifier and
password for an access token; the token and `expires_in` are written into the
`analytics_token` HTTP-only cookie that every subsequent gRPC call is signed
with. Fully covered end-to-end.
- **`AuthService.Register`** — called by `POST /register`. Submits the full
`RegisterRequest` surface (username, email, password, password_confirmation,
role, timezone, phone_country). Only the success/error message is shown; it
does not create a session.
- **`AuthService.GetAuthorization`** — called by every admin page loader
(`/admin`, table-definition, add-table, add-logic, add-validation,
import/export). Returns the caller's role; the web crate uses it for two
things: gating the admin panel to `role == "admin"` and rendering the navbar
with the current role. Response fields beyond `role` are not used.
### Table definition (`TableDefinitionClient`)
- **`TableDefinition.GetProfileTree`** — called by the analytics, admin, table
definition, add-table, add-logic, and add-validation loaders. Populates the
profile selectors (profile name + table count) and, in the admin panel, the
per-profile table list including `depends_on` and `row_display_columns`.
Response is consumed fairly deeply.
- **`TableDefinition.PostTableDefinition`** — called by `POST /admin/tables`
(add-table page). Creates a table from the draft; the returned `success`,
`sql`, and `message` are surfaced. Full form → endpoint mapping.
- **`TableDefinition.GetProfileDetails`** — called by the table-definition
workspace loader. Returns per-table columns (name, type, currency,
quantity-ledger, rounding, generated/read-only behaviors and `generated_from`
for Steel scripts), scripts (target column/type/description/source), row
display columns, and table kind. The most deeply consumed definition endpoint.
- **`TableDefinition.GetColumnAliasRenameHistory`** — called by the
table-definition workspace loader. Returns rename history entries
(table, old/new column names, timestamp); only those four fields are rendered.
- **`TableDefinition.AddTableColumns`** — called by
`POST /admin/table-definition/columns`. Adds columns to an existing table.
- **`TableDefinition.SetColumnPresentation`** — called by
`POST /admin/tables/presentation`. Atomically changes column aliases and order.
- **`TableDefinition.DeleteTable`** — called by
`POST /admin/table-definition/delete`. Deletes a table definition.
- **`TableDefinition.CopyProfile`** — called by
`POST /admin/table-definition/copy`. Copies a profile.
- **`TableDefinition.CreateInvoiceTemplateTable`** — called by
`POST /admin/table-definition/invoice-template`. Creates a table from the
invoice template contract.
### Table script (`TableScriptClient`)
- **`TableScript.PostTableScript`** — called by `POST /admin/logic`
(add-logic page). Creates a Steel table script; the returned id and warnings
are surfaced to the user.
### Table validation (`TableValidationServiceClient`)
- **`TableValidationService.UpdateFieldValidation`** — called by
`POST /admin/validation`. Creates/updates a field validation.
- **`TableValidationService.UpsertValidationRule`** — called by
`POST /admin/validation/rules`. Creates/updates a reusable validation rule.
- **`TableValidationService.ApplyValidationSet`** — called by
`POST /admin/validation/sets`. Applies a validation set.
- **`TableValidationService.UpsertValidationSet`** — called by
`POST /admin/validation/sets`. Creates/updates a reusable validation set.
Each validation POST maps the submitted form into the corresponding request and
renders only the returned `success`/`message`.
### Table structure (`TableStructureServiceClient`)
- **`TableStructureService.GetTableStructure`** — called by the admin panel,
CSV import, and CSV export. Returns table structures used three ways: the
admin column browse (name, type, nullable, primary key, quantity-ledger),
import header validation, and export column ordering. Only the structure for
the selected/imported/exported tables is requested at a time.
### Tables data (`TablesDataClient`)
- **`TablesData.PostTableDataBulk`** — called by `POST /admin/import`. Chunked
bulk insert of parsed CSV rows into a table, with per-chunk requests.
- **`TablesData.GetTableDataByPosition`** — called by `POST /admin/export.csv`.
Reads table rows by position for CSV download, one request per table.
### Analytics (`AnalyticsServiceClient`)
- **`AnalyticsService.GetAnalyticsCatalog`** — called by `POST /api/catalog`.
Returns the live public analytics catalog for a profile (tables, columns,
types, links); rendered in the sidebar and used to generate starter queries
and LLM schema context.
- **`AnalyticsService.ExecuteAnalyticsQuery`** — called by `POST /api/query`.
Runs a read-only analytics SQL query; the result columns/rows feed the
ECharts charts and table view.
- The analytics profile selector is fed by `TableDefinition.GetProfileTree`
(see above), not by a dedicated analytics profile endpoint.