pgkiln 0.59.0 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -103,6 +103,9 @@ SQL inline), edit them, show the diff, and import them again in one transaction.
103
103
  claude mcp add pgkiln -- /path/to/pgkiln/bin/pgkiln.js mcp
104
104
  ```
105
105
 
106
+ Without a checkout, `npx -y pgkiln mcp` (with `DATABASE_URL` set) or, for the Docker installation,
107
+ `docker compose exec -T pgkiln node bin/pgkiln.js mcp` starts the same server.
108
+
106
109
  Then ask things like *"explain what happens when I press Save on page 3 of hr"* or *"add a hire
107
110
  date column to the employee report and show me the diff"*. Queries it runs are read-only. See
108
111
  [AI coding agents](docs/guide/20-ai-agents.md).
package/SECURITY.md CHANGED
@@ -112,6 +112,7 @@ first version (MVP). Every finding below has a regression test in
112
112
  | Builder language (sprint 121) | Only the codes of the builder's languages are accepted: anything else on a sign-in link is ignored (also a repeated parameter), the status bar's menu refuses it (400) and checks the CSRF token. A sign-in link sets only an HttpOnly, SameSite=Lax cookie that the sign-in page reads; a developer's stored choice changes only through their own signed-in session. Translated texts are escaped like the English ones; placeholders are filled with escaped values unless the code passes markup on purpose (`tx.rich`). |
113
113
  | Ask and smart filters set facets (sprint 122) | A phrase can only set facets of the faceted search and smart filters regions on the page that the user sees, on their configured columns; values and range bounds become the facets' own URL parameters (bounds checked as numbers or dates) and reach SQL as query parameters, never as text. Values in a phrase are looked up in the report's rows with a query parameter, as the application's role. A facet chip's Remove is checked against the chips the form showed (a tampered key is refused). Sample apps keep their demo accounts with known passwords: install them on development or demo instances only. |
114
114
  | Builder texts in the browser (sprint 123) | The builder's JavaScript gets its texts as JSON in an attribute (`<div id="builder-texts" data-texts>`), escaped like any attribute value, so builder pages still have no inline script. The texts are the fixed message files, never data; scripts put them into the page with `textContent` and attributes, not as HTML. |
115
+ | Two-factor sign-in for developers (0.60.0) | TOTP secrets (RFC 6238, 160 bits) are encrypted with `PGKILN_SECRET_KEY` and stored only after a code from the app confirms them; recovery codes (10 × 50 bits) are stored as SHA-256 and used up atomically; a code is accepted once (the last step is updated atomically) and only one 30-second step either side. The password step leaves only a pending sign-in in the session (5 minutes, no session for the developer yet); wrong codes count with wrong passwords for the per-user and per-IP lockout. Removing an app needs the password; another developer's factors can only be reset by an administrator, with a reason, which ends that developer's builder sessions. The require policy can only be turned on, and stays enforceable, with at least two administrators (or every one) holding an app; there is no setting, URL or variable that skips the second step: recovery is `pgkiln admin reset-2fa` / `set-2fa-policy off` on the server with the owner connection. Every enrolment, removal, reset, policy change and used recovery code is in the activity log; resets and policy changes are mailed to the administrators. The factor tables are closed to the runtime role. |
115
116
 
116
117
  ## Findings of the MVP review and their fixes
117
118
 
@@ -234,3 +235,4 @@ A second full review, mainly of what end users and API callers can reach. Regres
234
235
  8. With REST data sources: list only the hosts you need in `PGKILN_REST_ALLOWED_HOSTS` (avoid `*`), set a long random `PGKILN_SECRET_KEY` (32+ characters) kept outside the database and its backups, and use `PGKILN_REST_PRIVATE_HOSTS` only for internal services you mean to reach. Narrow it further per workspace under Administration → Network access (sprint 118).
235
236
  9. With header authentication: list only your proxy's addresses in `PGKILN_AUTH_HEADER_PROXIES`, make sure users can't reach pgkiln directly, and have the proxy remove any incoming copy of the header.
236
237
  10. With database-account authentication: list exact roles or use a dedicated membership role, and limit what those roles may connect to in `pg_hba.conf` (they can reach the database with their password outside pgkiln too).
238
+ 11. Turn on two-factor sign-in for the builder (Instance settings → Two-factor sign-in, at least for administrators) once two administrators have an authenticator app, keep `PGKILN_SECRET_KEY` backed up, and keep the recovery commands (`pgkiln admin reset-2fa`) for people with server access only.
@@ -0,0 +1,48 @@
1
+ -- ---------------------------------------------------------------------
2
+ -- 128: two-factor sign-in for developers (sprint 126, SEC-2 and SEC-6;
3
+ -- beyond APEX, which has no built-in second factor for the builder).
4
+ --
5
+ -- meta.developer_factor: a developer's second factors. This sprint: an
6
+ -- authenticator app (TOTP, RFC 6238), its secret encrypted with the
7
+ -- instance key (PGKILN_SECRET_KEY, like web credentials). last_step is the
8
+ -- last 30-second step a code was accepted for, so a code works only once.
9
+ --
10
+ -- meta.developer_recovery_code: ten one-time codes per developer, stored
11
+ -- as SHA-256 of the code (the codes are random, 50 bits each), so they keep
12
+ -- working when the instance key is lost. confirmed: the developer said they
13
+ -- saved them; until then the codes don't count as a factor.
14
+ --
15
+ -- The policy (meta.setting): mfa_required = off | admins | all,
16
+ -- mfa_required_since (when it was turned on) and mfa_grace_days (default 7):
17
+ -- developers without a factor must enrol within the grace period.
18
+ --
19
+ -- Owner-only, like meta.developer: the runtime role never reads them.
20
+ -- Installation data: not exported with an application or a workspace.
21
+ -- ---------------------------------------------------------------------
22
+ create table meta.developer_factor (
23
+ id int generated always as identity primary key,
24
+ username text not null references meta.developer on update cascade on delete cascade,
25
+ kind text not null check (kind in ('totp')),
26
+ name text not null check (length(name) between 1 and 60),
27
+ secret_enc text not null,
28
+ last_step bigint,
29
+ created_at timestamptz not null default now(),
30
+ last_used_at timestamptz
31
+ );
32
+ create index on meta.developer_factor (username);
33
+ comment on table meta.developer_factor is
34
+ 'A developer''s second factors (128): authenticator apps (TOTP) with the secret encrypted with the instance key.';
35
+
36
+ create table meta.developer_recovery_code (
37
+ username text not null references meta.developer on update cascade on delete cascade,
38
+ code_hash text not null,
39
+ confirmed boolean not null default false,
40
+ created_at timestamptz not null default now(),
41
+ used_at timestamptz,
42
+ primary key (username, code_hash)
43
+ );
44
+ comment on table meta.developer_recovery_code is
45
+ 'One-time recovery codes of developers (128), as sha256 hex of the normalised code.';
46
+
47
+ insert into meta.setting (name, value) values ('mfa_required', 'off'), ('mfa_grace_days', '7')
48
+ on conflict (name) do nothing;
@@ -7,7 +7,7 @@ open item and open an issue or pull request; see [CONTRIBUTING.md](../CONTRIBUTI
7
7
  Legend: ✅ available · 🟡 partial (see notes) · ❌ not yet · ➖ not planned (a deliberate choice,
8
8
  or better served by the PostgreSQL ecosystem; see the notes and [extensions](guide/15-extensions.md))
9
9
 
10
- Last reviewed: 2026-10-20 against **APEX 26.2** (sprint 120: the App Gallery's single-topic sample apps (charts, cards, calendar, interactive grids, dynamic actions, reporting), the UX Pattern Catalog and a Utility Apps tab with Lookup Lists, Release Notes and Announcements (WS-8); sprint 119: data security per table, a roles × columns matrix and masked values per application role in a masking view, the same identity for pages, AI tools, REST, AutoREST and MCP (WS-13); sprint 118: Administration → Mail queue with delivery per hour and per workspace, the slowest provider calls and failures with Retry and Purge, a workspace's own mail service, and workspace network access lists that narrow the installation's allow-list (WS-9); sprint 117: Pillar Light and Pillar Dark navigation appearances with a header strip, clearer navigation tree states, subtle colour utilities, RTL; sprint 116: the comparison moved from 26.1 to 26.2, with a section for the 26.2 workspace items WS-1 … WS-13 and OCI managed identities; the App Builder list with Updated by, working copies and the lock; `pgkiln import --only`, a file-level import; stale rows on facet menus and blueprints fixed; sprint 115: popup LOVs that load on scroll, Wait Popup dynamic actions and dynamic actions on menu entries; sprint 114: Workflow 26.2 with custom task outcomes, task events and notifications, Send E-Mail and draft steps, migrating running instances and the diagram as SVG / PNG; sprint 113: Team Development with issues, labels, milestones, templates, a board and a set-up wizard; sprint 112: AI interactive reports with chips, Undo, computed columns and a phrase parser that needs no AI service; sprint 111: AI Agents with tools as a shared component, a Navigate tool with checksummed URLs, Gemini and OpenAI-compatible services; sprint 110: Data Reporter as a workspace tool with datasets, reporting applications, editors and viewers, published reports with stable URLs and pins; sprint 109: the Workspace home above the App Builder and SQL Workshop, with a summary, top applications, users and developers, and an optional release check; sprint 108: the code editor's syntax colours in the builder's light and dark themes, read-only SQL highlighted, the Data Modeler in dark mode; sprint 107: a transaction mode in the SQL Worksheet with Commit and Rollback; DA-18: JavaScript (MLE) not planned, plv8 where installed; sprint 106: the change log of DDL change sets with Flyway, Liquibase and SQL downloads; sprint 104: RESTful Services modules, templates and handlers with PL/pgSQL and media handlers, privileges, OpenAPI and Try it; sprint 103: Schema Export / Import with pg_dump and pg_restore; sprint 102: the SQL Monitor with live sessions, Top SQL and a statement's plan; sprint 101: Scheduling of pg_cron jobs with a schedule builder, run now and run history; sprint 100: RESTful Services, tables and views published as REST endpoints with paging, filters, keys and OpenAPI; sprint 99: Administration → Database Users for PostgreSQL roles; sprint 98: the Data Modeler with relational diagrams, DDL and a data dictionary; sprint 97: charts of a query in the worksheet, saved charts and their dashboard; sprint 96: the SQL Workshop's Launchpad with pins and tool groups, the builder's search with Ctrl+K; sprint 95: Table Properties: create, edit or copy a table in a form with a DDL preview and Apply in one transaction; sprint 94: an object's menu with Open in a panel, Quick DDL, Add index / trigger / policy and Drop with dependents; sprint 93: worksheets saved as SQL Scripts with tabs and a Files list, Format, Convert case, find and replace, bind and substitution variables; sprint 92: the worksheet's Query Result with sort, value dialog, copy and downloads, plans as a tree with the slowest step and misestimates, SQL History with status, search and run again; sprint 91: the SQL Worksheet like Database Actions' SQL: navigator, Run Statement at the cursor and Run Script with a log per statement, Explain Plan, Autotrace, notices, history, Run as an application role; sprint 90: Comment Out in the page designer, gallery labels in title case; sprint 89: the Object Browser's schema, one row of tabs, blank NULLs, Modify column; sprint 88: home cards with colour bands and round icons, the hero on the page background, a page footer with the version and Back to top; sprint 87: the Create Application wizard reloads the page list for a schema, RLS badges, the alias from the name; sprint 86: the page designer by page number, HTML error pages in the builder; sprint 85: the Form Designer, beyond APEX; sprint 84: the date picker, facet menus; sprint 83: Component Settings and Component Groups; sprint 82: Report Queries; sprint 81: Application Computations and Shortcuts in Shared Components; sprint 80: the master grid's first row selected when the page opens and after a search; grid cells as text with their format mask until edited, with cell navigation by arrow keys, Enter, F2 and Escape; sprint 79: generated dashboards with sums, donuts and lines, leaving out charts that say nothing; applications open in their own light or dark mode until the user chooses, per application; a user menu with Appearance and Sign in when signed out; the developer toolbar's App and Page texts and debug state; the report search's column scope in the magnifier; sprint 78: generated faceted search reports with one column per foreign key, the faceted search's total row count, Show all and Yes/No values, one search field, friendly headings and number formats in generated grids and master-detail pages, friendly names in the Create Application wizard's page list; sprint 77: the Page Designer's layout and tree by display position, button positions, the tree's context menu with Duplicate and Copy to other page, Show Common / Show All, Go to group and the Template Options dialog; display positions, button positions and side-column page templates at runtime; sprint 76: the interactive report's menus and pagination, date items in the date format; sprint 75: the SQL Workshop's Object Browser and tabs; sprint 74: the builder's information architecture: Shared Components grid, Settings tabs, application home search and tasks; sprint 73: the Create Application wizard on one page with page types and features; sprint 72: the runtime chrome compared with APEX 26.2's: the developer toolbar, the Iris look, the navigation bar's Help menu and Install button; sprint 71: generated applications compared with APEX 26.2's: labels, foreign key names in reports, file columns, format masks, the Home page and the dashboard; sprint 70: treemap, sunburst and timeline charts; sprint 69: dragging tasks on a Gantt chart; sprint 68: the Data Reporter's welcome page, Find my workspace; sprint 67: REST source catalogs from OpenAPI documents, a workspace's export and import (two rows added); sprint 66: a blueprint from an existing application; sprint 65: facet charts; sprint 64: approval vacation rules and expiration policies; sprint 63: range, box plot and stock charts; sprint 62: workspace preferences (SQL Workshop and RESTful services per workspace), extension links, Manage backups across applications, SQL Workshop utilities with object reports, About Database and a database monitor; sprint 61: the builder's screens compared with APEX 26.1: the workspace sign-in page, the Administration menu with workspace message, environment banner and utilization, the SQL Workshop home, the App Gallery, application groups and cross application reports (four rows added); sprint 60: isolated workspaces with their own database logins, row-level security on pgkiln's tables and workspace database roles, workspace administrators; sprint 59: the Page Designer's help pane, Quick edit from the developer toolbar; sprint 58: page groups; sprint 57: region templates hero, title bar, buttons container, inline dialog and drawer, wizard with wizard progress, the carousel; sprint 56: Generate DDL and Schema Comparison in the SQL Workshop, `pgkiln ddl` and `pgkiln compare`; sprint 55: an editable login page with a Login region and the Minimal page template, Forgot password through the application's mail service; sprint 54: interactive grid views, the single row view, group by and chart; sprint 53: application settings, user preferences and items kept per user, dynamic translations, `meta.data_export` and data export downloads, display image and geocoded address items; sprint 52: every dynamic action event and action, Ajax callbacks, an error handling function, the session timeout warning; sprint 51: checked imports, application backups, availability and Run only, feedback, type-specific attribute help; sprint 50: lost update detection, warn on unsaved changes, the URL and search regions with search configurations, the developer toolbar with a session state viewer, and e-mail through SMTP with OAuth2, Microsoft Graph, Amazon SES and HTTP APIs; import checks, application availability, property help and e-mail compared again; 2026-10-06: pgkiln 0.31.0, in progress: static application files and the Execute JavaScript dynamic action; region, item, dynamic action and process plug-ins; conditional and dynamic theme styles; XML and Excel in `meta.parse_data`, zips in SQL, `meta.v_boolean`; file items in S3-compatible object storage; map layers by the visible area and as vector tiles; a graphical query builder; tenants for workflows and tasks; application files as YAML and region static IDs; Lucide icons and icon modifiers; PWA push notifications; 0.30.0: 136 icons and an icon picker; an axe-core accessibility audit; cropping pictures; session sharing between applications; twenty-two built-in languages; 0.29.0: workspaces; the Iris base style; drawers; built-in template components including the metric card; Theme Roller dark-mode colours, live preview and template options on items and report columns; report selection across pages; instance settings; fourteen built-in languages; 0.28.0: AI with Claude and OpenAI; 0.27.0: Data Reporter; sample data generator; create application from several sheets, pasted data or existing tables; 0.26.0: working copies with a three-way merge; theme, library and boilerplate applications with subscriptions; 0.25.0: Gantt, pyramid and polar charts; map layers, clustering and server-side spatial filters; REST data sources that write back from forms and grids and synchronise into tables, OAuth2 password and refresh-token grants; debug messages per request and an install/upgrade log; `meta.web_request()` and `meta.parse_data()`; Theme Roller style variants and template options; 0.24.0: automations with several actions, error handling per row and runs from SQL; invoke-API workflow steps; Unload Data in the Data Workshop; create page wizards for cards, calendar, chart, map, faceted search, form and master-detail; create an application from a file; 0.23.0: interactive grid aggregates, frozen/moved/resized columns, layouts and saved grid reports, master-detail, row actions and copy/paste; download processes, execution chains in the background, workflow processes, branches to a function's URL or another app, the Dialog Closed event; number format masks, automatic time zone, runtime messages in German, French and Spanish; SQL scripts, Quick SQL, a query builder, XML loading and data load definitions; custom authentication, lists, page and application locks with developer comments, supporting objects; 0.22.0: keyset paging, report PDFs and REST collections streamed from a cursor, database-account authentication; 0.21.0: HTTP-header authentication behind a reverse proxy; 0.20.0: a popup list of values with server-side search; 0.19.0: row-range pagination, maximum row counts and row limits, lazy loading and caching of regions, streamed CSV/Excel downloads; 0.18.0: calendar week/day/list views with drag and drop, bubble/gauge/funnel/radar charts and drill-down, smart filters, a region display selector and more facet types, computations, conditional branches, build options, menu buttons, REST data sources and web credentials, rich text/Markdown, rating, combobox, date range and QR code items; 0.17.0: an App Builder home, workspace dashboard and utilities like APEX's; 0.16.0: a Page Designer with drag-and-drop layout, a code editor with autocomplete, template components and plug-ins, parallel branches and versions of workflows, the `pgkiln` command line with one file per component; 0.15.0: drop and paste files, heat maps, filtering a report by the map area; 0.14.0: stacked, combo, scatter and pie charts, several files per upload item; 0.13.0: map and tree regions; 0.12.0: REST modules in the builder; 0.11.0: workflows and Progressive Web Apps; 0.10.0: LDAP, SAML, "Keep me signed in", document templates, JSON loading, approvals and the task list; pgkiln installs no application, HR is an example).
10
+ Last reviewed: 2026-10-21 against **APEX 26.2** (sprints 121, 123–125: the builder in Deutsch, English, Español, Français, Nederlands and Português, step by step: the frame, sign-in, Workspace home, App Builder, Page Designer menus, the SQL Workshop's home, SQL Worksheet, Object Browser and Table Properties, Shared Components, application settings, users, identity providers, developers and workspaces (WS-7); sprint 122: *Ask in your own words* sets faceted search and smart filter facets, smart filters read a typed phrase (WS-5), and Sample Maps, Sample Approvals, Sample Data Loading and Sample Files in the App Gallery (WS-8); sprint 120: the App Gallery's single-topic sample apps (charts, cards, calendar, interactive grids, dynamic actions, reporting), the UX Pattern Catalog and a Utility Apps tab with Lookup Lists, Release Notes and Announcements (WS-8); sprint 119: data security per table, a roles × columns matrix and masked values per application role in a masking view, the same identity for pages, AI tools, REST, AutoREST and MCP (WS-13); sprint 118: Administration → Mail queue with delivery per hour and per workspace, the slowest provider calls and failures with Retry and Purge, a workspace's own mail service, and workspace network access lists that narrow the installation's allow-list (WS-9); sprint 117: Pillar Light and Pillar Dark navigation appearances with a header strip, clearer navigation tree states, subtle colour utilities, RTL; sprint 116: the comparison moved from 26.1 to 26.2, with a section for the 26.2 workspace items WS-1 … WS-13 and OCI managed identities; the App Builder list with Updated by, working copies and the lock; `pgkiln import --only`, a file-level import; stale rows on facet menus and blueprints fixed; sprint 115: popup LOVs that load on scroll, Wait Popup dynamic actions and dynamic actions on menu entries; sprint 114: Workflow 26.2 with custom task outcomes, task events and notifications, Send E-Mail and draft steps, migrating running instances and the diagram as SVG / PNG; sprint 113: Team Development with issues, labels, milestones, templates, a board and a set-up wizard; sprint 112: AI interactive reports with chips, Undo, computed columns and a phrase parser that needs no AI service; sprint 111: AI Agents with tools as a shared component, a Navigate tool with checksummed URLs, Gemini and OpenAI-compatible services; sprint 110: Data Reporter as a workspace tool with datasets, reporting applications, editors and viewers, published reports with stable URLs and pins; sprint 109: the Workspace home above the App Builder and SQL Workshop, with a summary, top applications, users and developers, and an optional release check; sprint 108: the code editor's syntax colours in the builder's light and dark themes, read-only SQL highlighted, the Data Modeler in dark mode; sprint 107: a transaction mode in the SQL Worksheet with Commit and Rollback; DA-18: JavaScript (MLE) not planned, plv8 where installed; sprint 106: the change log of DDL change sets with Flyway, Liquibase and SQL downloads; sprint 104: RESTful Services modules, templates and handlers with PL/pgSQL and media handlers, privileges, OpenAPI and Try it; sprint 103: Schema Export / Import with pg_dump and pg_restore; sprint 102: the SQL Monitor with live sessions, Top SQL and a statement's plan; sprint 101: Scheduling of pg_cron jobs with a schedule builder, run now and run history; sprint 100: RESTful Services, tables and views published as REST endpoints with paging, filters, keys and OpenAPI; sprint 99: Administration → Database Users for PostgreSQL roles; sprint 98: the Data Modeler with relational diagrams, DDL and a data dictionary; sprint 97: charts of a query in the worksheet, saved charts and their dashboard; sprint 96: the SQL Workshop's Launchpad with pins and tool groups, the builder's search with Ctrl+K; sprint 95: Table Properties: create, edit or copy a table in a form with a DDL preview and Apply in one transaction; sprint 94: an object's menu with Open in a panel, Quick DDL, Add index / trigger / policy and Drop with dependents; sprint 93: worksheets saved as SQL Scripts with tabs and a Files list, Format, Convert case, find and replace, bind and substitution variables; sprint 92: the worksheet's Query Result with sort, value dialog, copy and downloads, plans as a tree with the slowest step and misestimates, SQL History with status, search and run again; sprint 91: the SQL Worksheet like Database Actions' SQL: navigator, Run Statement at the cursor and Run Script with a log per statement, Explain Plan, Autotrace, notices, history, Run as an application role; sprint 90: Comment Out in the page designer, gallery labels in title case; sprint 89: the Object Browser's schema, one row of tabs, blank NULLs, Modify column; sprint 88: home cards with colour bands and round icons, the hero on the page background, a page footer with the version and Back to top; sprint 87: the Create Application wizard reloads the page list for a schema, RLS badges, the alias from the name; sprint 86: the page designer by page number, HTML error pages in the builder; sprint 85: the Form Designer, beyond APEX; sprint 84: the date picker, facet menus; sprint 83: Component Settings and Component Groups; sprint 82: Report Queries; sprint 81: Application Computations and Shortcuts in Shared Components; sprint 80: the master grid's first row selected when the page opens and after a search; grid cells as text with their format mask until edited, with cell navigation by arrow keys, Enter, F2 and Escape; sprint 79: generated dashboards with sums, donuts and lines, leaving out charts that say nothing; applications open in their own light or dark mode until the user chooses, per application; a user menu with Appearance and Sign in when signed out; the developer toolbar's App and Page texts and debug state; the report search's column scope in the magnifier; sprint 78: generated faceted search reports with one column per foreign key, the faceted search's total row count, Show all and Yes/No values, one search field, friendly headings and number formats in generated grids and master-detail pages, friendly names in the Create Application wizard's page list; sprint 77: the Page Designer's layout and tree by display position, button positions, the tree's context menu with Duplicate and Copy to other page, Show Common / Show All, Go to group and the Template Options dialog; display positions, button positions and side-column page templates at runtime; sprint 76: the interactive report's menus and pagination, date items in the date format; sprint 75: the SQL Workshop's Object Browser and tabs; sprint 74: the builder's information architecture: Shared Components grid, Settings tabs, application home search and tasks; sprint 73: the Create Application wizard on one page with page types and features; sprint 72: the runtime chrome compared with APEX 26.2's: the developer toolbar, the Iris look, the navigation bar's Help menu and Install button; sprint 71: generated applications compared with APEX 26.2's: labels, foreign key names in reports, file columns, format masks, the Home page and the dashboard; sprint 70: treemap, sunburst and timeline charts; sprint 69: dragging tasks on a Gantt chart; sprint 68: the Data Reporter's welcome page, Find my workspace; sprint 67: REST source catalogs from OpenAPI documents, a workspace's export and import (two rows added); sprint 66: a blueprint from an existing application; sprint 65: facet charts; sprint 64: approval vacation rules and expiration policies; sprint 63: range, box plot and stock charts; sprint 62: workspace preferences (SQL Workshop and RESTful services per workspace), extension links, Manage backups across applications, SQL Workshop utilities with object reports, About Database and a database monitor; sprint 61: the builder's screens compared with APEX 26.1: the workspace sign-in page, the Administration menu with workspace message, environment banner and utilization, the SQL Workshop home, the App Gallery, application groups and cross application reports (four rows added); sprint 60: isolated workspaces with their own database logins, row-level security on pgkiln's tables and workspace database roles, workspace administrators; sprint 59: the Page Designer's help pane, Quick edit from the developer toolbar; sprint 58: page groups; sprint 57: region templates hero, title bar, buttons container, inline dialog and drawer, wizard with wizard progress, the carousel; sprint 56: Generate DDL and Schema Comparison in the SQL Workshop, `pgkiln ddl` and `pgkiln compare`; sprint 55: an editable login page with a Login region and the Minimal page template, Forgot password through the application's mail service; sprint 54: interactive grid views, the single row view, group by and chart; sprint 53: application settings, user preferences and items kept per user, dynamic translations, `meta.data_export` and data export downloads, display image and geocoded address items; sprint 52: every dynamic action event and action, Ajax callbacks, an error handling function, the session timeout warning; sprint 51: checked imports, application backups, availability and Run only, feedback, type-specific attribute help; sprint 50: lost update detection, warn on unsaved changes, the URL and search regions with search configurations, the developer toolbar with a session state viewer, and e-mail through SMTP with OAuth2, Microsoft Graph, Amazon SES and HTTP APIs; import checks, application availability, property help and e-mail compared again; 2026-10-06: pgkiln 0.31.0, in progress: static application files and the Execute JavaScript dynamic action; region, item, dynamic action and process plug-ins; conditional and dynamic theme styles; XML and Excel in `meta.parse_data`, zips in SQL, `meta.v_boolean`; file items in S3-compatible object storage; map layers by the visible area and as vector tiles; a graphical query builder; tenants for workflows and tasks; application files as YAML and region static IDs; Lucide icons and icon modifiers; PWA push notifications; 0.30.0: 136 icons and an icon picker; an axe-core accessibility audit; cropping pictures; session sharing between applications; twenty-two built-in languages; 0.29.0: workspaces; the Iris base style; drawers; built-in template components including the metric card; Theme Roller dark-mode colours, live preview and template options on items and report columns; report selection across pages; instance settings; fourteen built-in languages; 0.28.0: AI with Claude and OpenAI; 0.27.0: Data Reporter; sample data generator; create application from several sheets, pasted data or existing tables; 0.26.0: working copies with a three-way merge; theme, library and boilerplate applications with subscriptions; 0.25.0: Gantt, pyramid and polar charts; map layers, clustering and server-side spatial filters; REST data sources that write back from forms and grids and synchronise into tables, OAuth2 password and refresh-token grants; debug messages per request and an install/upgrade log; `meta.web_request()` and `meta.parse_data()`; Theme Roller style variants and template options; 0.24.0: automations with several actions, error handling per row and runs from SQL; invoke-API workflow steps; Unload Data in the Data Workshop; create page wizards for cards, calendar, chart, map, faceted search, form and master-detail; create an application from a file; 0.23.0: interactive grid aggregates, frozen/moved/resized columns, layouts and saved grid reports, master-detail, row actions and copy/paste; download processes, execution chains in the background, workflow processes, branches to a function's URL or another app, the Dialog Closed event; number format masks, automatic time zone, runtime messages in German, French and Spanish; SQL scripts, Quick SQL, a query builder, XML loading and data load definitions; custom authentication, lists, page and application locks with developer comments, supporting objects; 0.22.0: keyset paging, report PDFs and REST collections streamed from a cursor, database-account authentication; 0.21.0: HTTP-header authentication behind a reverse proxy; 0.20.0: a popup list of values with server-side search; 0.19.0: row-range pagination, maximum row counts and row limits, lazy loading and caching of regions, streamed CSV/Excel downloads; 0.18.0: calendar week/day/list views with drag and drop, bubble/gauge/funnel/radar charts and drill-down, smart filters, a region display selector and more facet types, computations, conditional branches, build options, menu buttons, REST data sources and web credentials, rich text/Markdown, rating, combobox, date range and QR code items; 0.17.0: an App Builder home, workspace dashboard and utilities like APEX's; 0.16.0: a Page Designer with drag-and-drop layout, a code editor with autocomplete, template components and plug-ins, parallel branches and versions of workflows, the `pgkiln` command line with one file per component; 0.15.0: drop and paste files, heat maps, filtering a report by the map area; 0.14.0: stacked, combo, scatter and pie charts, several files per upload item; 0.13.0: map and tree regions; 0.12.0: REST modules in the builder; 0.11.0: workflows and Progressive Web Apps; 0.10.0: LDAP, SAML, "Keep me signed in", document templates, JSON loading, approvals and the task list; pgkiln installs no application, HR is an example).
11
11
 
12
12
  ## At a glance
13
13
 
@@ -138,7 +138,7 @@ the 26.2 comparison.)
138
138
  | APEX accounts | ✅ | Instance-wide user directory, bcrypt, session rotation, idle and absolute timeouts |
139
139
  | Application Access Control (roles per app, any-user switch) | ✅ | Access control per application |
140
140
  | Social sign-in / OpenID Connect | ✅ | Any OIDC provider (Entra ID, Google, Okta, Keycloak, …): PKCE, group → role mapping, account linking, automatic accounts |
141
- | Multi-factor authentication | ✅ | As in APEX: through the identity provider (OpenID Connect) |
141
+ | Multi-factor authentication | ✅ | As in APEX: through the identity provider (OpenID Connect, SAML). Beyond APEX (sprint 126): the builder itself has two-factor sign-in with authenticator apps (TOTP) and recovery codes, a policy with a grace period and lockout recovery ([chapter 3](guide/03-builder.md#two-factor-sign-in)); passkeys and two-factor for application users follow (SEC-2, SEC-3) |
142
142
  | Change own password | ✅ | A built-in *My account* page (APEX offers the API `CHANGE_CURRENT_USER_PW`) |
143
143
  | Password expiry, change on first use, admin reset, complexity | ✅ | Lifetime in days, expire/unexpire, admin reset, length and letters+digits rules, unlock |
144
144
  | Lockout after failed sign-ins | ✅ | Per user and per IP, time-based (APEX: until an administrator unlocks) |
@@ -249,7 +249,7 @@ row above where there is one.
249
249
  | WS-4 AI Agents with tools | ✅ | (sprint 111) AI Agents and AI Tools as shared components, a Navigate tool, Gemini and OpenAI-compatible services ([Workflow, automation and AI](#workflow-automation-and-ai)) |
250
250
  | WS-5 AI interactive reports: chips, computed columns | ✅ | (sprint 112) *Ask in your own words* with chips, Undo and computed columns; a phrase parser that needs no AI service; (sprint 122) phrases set faceted search and smart filter facets |
251
251
  | WS-6 Workflow 26.2: outcomes, migrating running instances, drafts, diagram export | ✅ | (sprint 114) Custom task outcomes, task events, Send E-Mail and draft steps, migrating running instances, the diagram as SVG / PNG ([Workflow, automation and AI](#workflow-automation-and-ai)) |
252
- | WS-7 The builder in more languages | ✅ | (sprint 121) The builder in Deutsch, English, Español, Français, Nederlands and Português: links on the sign-in page, a language menu in the status bar, the choice stored per developer (migration 127). Translated: the builder's frame, sign-in page, Workspace home, App Builder home, an application's home and tabs, the Page Designer's toolbar, menus, tree and gallery, the SQL Workshop's home and tabs; other screens move over incrementally (English until then). Builder texts are keyed message files with a coverage check in CI (sprint 123) Also the SQL Worksheet, the Object Browser and Table Properties, with the texts of the browser code. (sprint 124) Shared Components and the application settings. (sprint 125) Users, identity providers, Developers and Workspaces. |
252
+ | WS-7 The builder in more languages | ✅ | (sprint 121) The builder in Deutsch, English, Español, Français, Nederlands and Português: links on the sign-in page, a language menu in the status bar, the choice stored per developer (migration 127); builder texts are keyed message files with a coverage check in CI, also for the builder's own JavaScript (sprint 123). Translated (sprints 121, 123–125): the builder's frame, sign-in page, Workspace home, App Builder home, an application's home and tabs, the Page Designer's toolbar, menus, tree and gallery, the SQL Workshop's home and tabs, the SQL Worksheet, Object Browser and Table Properties, Shared Components, an application's settings, Users, identity providers, Developers and Workspaces ([chapter 3](guide/03-builder.md#choosing-the-builder-language)). Still English: the rest of Administration (mail queue, network access, database users, dashboard, utilities, LDAP, instance settings), the other SQL Workshop tools and the region and report settings, until they move over; by design the property editor's and component forms' field names and help |
253
253
  | WS-8 App Gallery: more sample apps, Utility Apps | ✅ | (sprint 120) Four tabs with counts and a search that also works without JavaScript ([chapter 3](guide/03-builder.md#app-gallery)). *Sample Apps*: HR Demo, Tasks, ten single-topic apps (Sample Charts, Sample Cards, Sample Calendar, Sample Interactive Grids, Sample Dynamic Actions, Sample Reporting; sprint 122: Sample Maps, Sample Approvals, Sample Data Loading, Sample Files) and the **UX Pattern Catalog**, each with its own schema, data, demo account and explanatory texts, installed by administrators from one SQL file in one transaction; *Utility Apps*: Lookup Lists, Release Notes and Announcements as blueprints any developer installs into the workspace. APEX's 27 sample apps include topics pgkiln shows in HR Demo instead (REST, trees, collections); no remote catalogue |
254
254
  | WS-9 Mail queue reporting, workspace SMTP, workspace network ACLs | ✅ | (sprint 118) Administration → Mail queue (per hour and per workspace / application, the slowest provider calls, failures with the provider's answer, Retry and Purge), a workspace's own mail service, and a workspace's network access list that narrows the installation's allow-list for every outgoing call ([Administration](#administration)) |
255
255
  | WS-10 Universal Theme 26.2: Pillar appearances, navigation polish | ✅ | (sprint 117) Theme Roller → Navigation appearance Pillar Light / Pillar Dark per application or style, with a header strip colour for light and dark mode; the current page filled, its parents bold with an accent guide line; `u-color-*-subtle` utilities; a lighter processing indicator; RTL mirrored |
@@ -296,6 +296,9 @@ Small but real differences, for teams comparing the two:
296
296
  - Responsive layouts verified automatically at four screen sizes.
297
297
  - The theme follows the device's light/dark setting automatically, and the choice is saved per user.
298
298
  - A built-in *My account* page (own password, theme, language).
299
+ - (sprint 126) **Two-factor sign-in for the builder** without an identity provider: authenticator apps (TOTP),
300
+ recovery codes, a policy for administrators or all developers with a grace period, and lockout recovery on the
301
+ command line ([chapter 3](guide/03-builder.md#two-factor-sign-in)). APEX relies on the identity provider.
299
302
  - One RLS policy set protects both the web UI and the REST API.
300
303
  - An import can be checked before it commits (`pgkiln import --check`): SQL that names a missing
301
304
  table or column refuses the deployment instead of failing at run time.
@@ -37,6 +37,59 @@ developer accounts and [workspaces](#workspaces) and can break other developers'
37
37
  that existed before 0.23 and those made with the command line are administrators. A developer added on this page
38
38
  joins the workspace you are working in; one made with the command line or SQL joins the Default workspace.
39
39
 
40
+ ### Two-factor sign-in
41
+
42
+ (0.60) Developers can sign in to the builder with a second factor: a 6-digit code from an **authenticator app**
43
+ (Google Authenticator, Microsoft Authenticator, 1Password, Bitwarden, any app for TOTP codes per RFC 6238).
44
+ APEX has no built-in second factor for the builder; there it comes from an identity provider.
45
+
46
+ **Setting it up.** Your account menu → **Two-factor sign-in** opens **Security** (`/builder/security`):
47
+
48
+ 1. **Add an authenticator app** shows a QR code (and the key to type in by hand). Scan it with the app.
49
+ 2. Enter the code the app shows, give the app a name (*Phone*) and **Confirm and turn on**.
50
+ 3. You get **ten recovery codes**, shown once. Save them away from your phone and tick *I saved these codes*.
51
+
52
+ From then on, signing in asks for a code after the password. A recovery code works instead of an app code, once;
53
+ signing in with one opens Security, which shows how many are left and makes new ones (the old ones stop working).
54
+ Removing an app asks for your password. Each code is accepted once, and one 30-second step either side of the
55
+ server's clock.
56
+
57
+ The app's secret is stored encrypted with the instance key (`PGKILN_SECRET_KEY`, [chapter 1](01-installation.md));
58
+ without the key the page says so and you can't add an app. Recovery codes are stored as SHA-256 hashes, so they keep
59
+ working if the key is lost. Wrong codes count with wrong passwords for the [sign-in lockout](08-security.md#what-sign-in-protects-against).
60
+
61
+ **Requiring it.** Administrators set the policy in Workspace utilities → **Instance settings** → *Two-factor
62
+ sign-in*: **Nobody** (optional, the default), **Administrators** or **All developers**, with a **grace period**
63
+ (default 7 days). During the grace period a developer without an app sees a reminder on every page; after it, they
64
+ see only their Security page until they add one. The region lists the developers who have no app yet.
65
+
66
+ **So nobody is locked out:**
67
+
68
+ - The policy can be turned on only when **at least two administrators** have two-factor sign-in (or every
69
+ administrator, when there are fewer than two). While it is on, an administrator can't remove their last app, be
70
+ made a developer or be removed when that would leave fewer.
71
+ - An administrator **resets** another developer's two-factor sign-in on **Developers** (the *Two-factor* column →
72
+ *Reset*, with a reason): their apps and recovery codes are removed and their builder sessions end; they sign in with
73
+ the password and set up an app again.
74
+ - Resets, policy changes, new apps and used recovery codes are in the activity log (`2fa_reset`, `2fa_policy`,
75
+ `2fa_enrolled`, `2fa_recovery_used`), and resets and policy changes are mailed to the administrators when the
76
+ builder has a mail service (*Builder mail*).
77
+
78
+ ### Locked out?
79
+
80
+ | Situation | What to do |
81
+ |---|---|
82
+ | Lost your phone, still have recovery codes | Sign in with a recovery code, remove the old app on Security and add the new phone |
83
+ | Lost phone and codes | Ask another administrator to reset your two-factor sign-in on Developers |
84
+ | No administrator can sign in | On the server: `pgkiln admin reset-2fa <developer> --reason "…"` ([chapter 18](18-cli.md)), then sign in with the password |
85
+ | The policy locks everyone out | On the server: `pgkiln admin set-2fa-policy off` |
86
+ | Codes are always wrong | Check the time on the phone and on the server (codes allow 30 seconds either way) |
87
+ | The instance key was lost or changed | The apps' secrets can't be read: reset the developers (`pgkiln admin reset-2fa`); recovery codes still work |
88
+
89
+ The command line needs the owner's database connection (`DATABASE_URL`), so only someone with access to the server
90
+ can use it. It writes to the activity log and mails the administrators too. With Docker:
91
+ `docker compose exec pgkiln node bin/pgkiln.js admin reset-2fa admin`.
92
+
40
93
  ## Workspaces
41
94
 
42
95
  A workspace (APEX: a workspace) groups applications and the developers who build them, for example per team or
@@ -420,6 +420,10 @@ Applications of different groups, and applications without a group, sign in on t
420
420
 
421
421
  All sign-ins, failures and lockouts appear in the **Activity** monitor.
422
422
 
423
+ A second factor for an application's users comes from the identity provider ([OpenID Connect](#single-sign-on-openid-connect),
424
+ [SAML](#single-sign-on-saml-20)). Developers can use an authenticator app for the builder itself:
425
+ [two-factor sign-in](03-builder.md#two-factor-sign-in).
426
+
423
427
  ## Authorization: what may the user do?
424
428
 
425
429
  ### Authorization schemes
@@ -15,6 +15,13 @@ npx tsx src/cli/main.ts apps # directly
15
15
  ./bin/pgkiln.js apps # the package's bin entry (also after npm link)
16
16
  ```
17
17
 
18
+ Without a checkout, from the npm package or in the Docker container:
19
+
20
+ ```sh
21
+ npx -y pgkiln apps # npm (Node.js 20+); or npm install -g pgkiln, then: pgkiln apps
22
+ docker compose exec pgkiln node bin/pgkiln.js apps # the Docker installation (from the directory with compose.yaml)
23
+ ```
24
+
18
25
  It connects with `DATABASE_URL` (the owner role) from the environment or `.env`, the same as
19
26
  the server and `npm run db:migrate`; `--db <url>` overrides it. Every command has `--help`.
20
27
 
@@ -45,6 +52,8 @@ any (see [what is not exported](03-builder.md#export-format)).
45
52
  | `pgkiln users list [--developers]` | Accounts with their applications and roles, or builder developers |
46
53
  | `pgkiln users add <username> [--developer] [--app <alias> --roles a,b] [--name …] [--email …]` | Adds an account (optionally with access to an application) or a builder developer |
47
54
  | `pgkiln users password <username> [--developer]` | Sets a password and ends that user's sessions |
55
+ | `pgkiln admin reset-2fa <developer> [--reason <text>]` | (0.60) Removes a developer's authenticator apps and recovery codes and ends their builder sessions: [locked out?](03-builder.md#locked-out) |
56
+ | `pgkiln admin set-2fa-policy off\|admins\|all [--grace <days>]` | (0.60) Sets the builder's [two-factor policy](03-builder.md#two-factor-sign-in); `off` always works, the others need two administrators with an app |
48
57
 
49
58
  `users` reads the password from standard input (the first line, e.g. from a secret store:
50
59
  `printf '%s\n' "$PW" | pgkiln users add ops --developer`) or asks for it twice on a terminal. It is
@@ -29,6 +29,24 @@ claude mcp add pgkiln -- /path/to/pgkiln/bin/pgkiln.js mcp
29
29
  claude mcp add pgkiln -e DATABASE_URL=postgres://owner@host/db -- /path/to/pgkiln/bin/pgkiln.js mcp
30
30
  ```
31
31
 
32
+ **Without a checkout**: the npm package has the same command, so `npx` runs it (Node.js 20 or later). Give it
33
+ the owner connection of the database pgkiln runs on:
34
+
35
+ ```sh
36
+ claude mcp add pgkiln -e DATABASE_URL=postgres://pgkiln:secret@localhost:5432/pgkiln -- npx -y pgkiln mcp
37
+ ```
38
+
39
+ Pin a version (`npx -y pgkiln@0.59.0 mcp`) to match the server you run.
40
+
41
+ **With the Docker installation** ([chapter 1](01-installation.md#docker)) the container already has the connection;
42
+ the agent starts the server inside it, from the directory with `compose.yaml`:
43
+
44
+ ```sh
45
+ claude mcp add pgkiln -- docker compose -f /path/to/pgkiln/compose.yaml exec -T pgkiln node bin/pgkiln.js mcp
46
+ ```
47
+
48
+ (`-T`: no terminal, the protocol runs over standard input and output.) The database port stays closed to the host.
49
+
32
50
  **Other agents** take the same command in their MCP configuration, e.g. for Cursor
33
51
  (`.cursor/mcp.json`) or VS Code (`.vscode/mcp.json`, key `servers`):
34
52
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgkiln",
3
- "version": "0.59.0",
3
+ "version": "0.60.0",
4
4
  "description": "Open source low-code, SQL-driven application builder for PostgreSQL, inspired by Oracle APEX",
5
5
  "keywords": [
6
6
  "postgresql",
@@ -1563,3 +1563,11 @@ pre.wrap-pre { white-space: pre-wrap; overflow-wrap: anywhere; }
1563
1563
  @media (max-width: 640px) { .ide-status .ide-lang .menu-panel { left: 0.5rem; right: 0.5rem; min-width: 0; } }
1564
1564
  /* long compound words of other languages (Workspace-Dienstprogramme) wrap instead of widening a phone's page */
1565
1565
  .ab-tile > *, .stat span { min-width: 0; overflow-wrap: anywhere; hyphens: auto; }
1566
+
1567
+ /* (sprint 126) Security: two-factor sign-in */
1568
+ .mfa-qr { margin: .5rem 0 1rem; }
1569
+ .mfa-qr svg { width: 200px; max-width: 100%; height: auto; background: #fff; padding: 8px; border-radius: 6px; }
1570
+ .mfa-secret { word-break: break-all; font-size: .95em; letter-spacing: .05em; }
1571
+ .mfa-steps { padding-left: 1.25rem; }
1572
+ .mfa-codes { columns: 2; column-gap: 2rem; padding-left: 1.5rem; font-size: 1.05em; }
1573
+ @media (max-width: 480px) { .mfa-codes { columns: 1; } }
@@ -1711,4 +1711,77 @@ export const de: BuilderMessages = {
1711
1711
  'dev.not_found': 'Nicht gefunden.',
1712
1712
  'dev.role_changed': 'Rolle geändert.',
1713
1713
  'dev.removed': 'Entwickler entfernt.',
1714
+ // ------------------------------------------------------------ Security: two-factor sign-in (sprint 126)
1715
+ 'mfa.menu': 'Zwei-Faktor-Anmeldung',
1716
+ 'mfa.title': 'Sicherheit',
1717
+ 'mfa.intro': 'Melden Sie sich nach dem Passwort mit einem Code aus einer Authenticator-App an. Wiederherstellungscodes helfen, wenn Sie das Telefon verlieren.',
1718
+ 'mfa.required_you': 'Ihr Administrator verlangt die Zwei-Faktor-Anmeldung: Fügen Sie eine Authenticator-App hinzu.',
1719
+ 'mfa.banner': 'Die Zwei-Faktor-Anmeldung ist erforderlich. Richten Sie sie vor dem {date} ein: {link}',
1720
+ 'mfa.set_up_now': 'jetzt einrichten',
1721
+ 'mfa.apps': 'Authenticator-Apps',
1722
+ 'mfa.app_name': 'Name',
1723
+ 'mfa.app_default': 'Telefon',
1724
+ 'mfa.added': 'Hinzugefügt',
1725
+ 'mfa.last_used': 'Zuletzt verwendet',
1726
+ 'mfa.no_apps': 'Noch keine Authenticator-App: Sie melden sich nur mit Ihrem Passwort an.',
1727
+ 'mfa.add_app': 'Authenticator-App hinzufügen',
1728
+ 'mfa.no_key': 'Die Zwei-Faktor-Anmeldung braucht den Instanzschlüssel (PGKILN_SECRET_KEY), um das Geheimnis der App zu speichern.',
1729
+ 'mfa.scan': 'Scannen Sie den QR-Code mit einer Authenticator-App.',
1730
+ 'mfa.or_enter': 'Oder geben Sie diesen Schlüssel von Hand ein:',
1731
+ 'mfa.enter_code': 'Geben Sie den 6-stelligen Code der App ein.',
1732
+ 'mfa.qr_label': 'QR-Code für die Authenticator-App',
1733
+ 'mfa.confirm_app': 'Bestätigen und einschalten',
1734
+ 'mfa.cancel_setup': 'Abbrechen',
1735
+ 'mfa.setup_expired': 'Die Einrichtung hat zu lange gedauert: Beginnen Sie neu.',
1736
+ 'mfa.wrong_setup': 'Dieser Code passt nicht: Prüfen Sie die Uhrzeit Ihres Telefons und versuchen Sie den nächsten Code.',
1737
+ 'mfa.app_added': 'Authenticator-App hinzugefügt: Ab jetzt melden Sie sich auch mit einem Code an.',
1738
+ 'mfa.remove': 'Entfernen',
1739
+ 'mfa.remove_app': 'Diese App entfernen',
1740
+ 'mfa.your_password': 'Ihr Passwort',
1741
+ 'mfa.wrong_password': 'Falsches Passwort.',
1742
+ 'mfa.cannot_remove_required': 'Die Zwei-Faktor-Anmeldung ist für Sie erforderlich: Fügen Sie eine weitere App hinzu, bevor Sie diese entfernen.',
1743
+ 'mfa.cannot_remove_admin': 'Mindestens zwei Administratoren (oder alle, wenn es weniger sind) müssen die Zwei-Faktor-Anmeldung behalten, solange die Richtlinie gilt.',
1744
+ 'mfa.keep_admins': 'Jetzt nicht: Die Zwei-Faktor-Richtlinie braucht mindestens zwei Administratoren mit Zwei-Faktor-Anmeldung (oder alle, wenn es weniger sind).',
1745
+ 'mfa.removed': 'Authenticator-App entfernt.',
1746
+ 'mfa.codes_title': 'Wiederherstellungscodes',
1747
+ 'mfa.codes_once': 'Bewahren Sie diese Codes sicher und getrennt vom Telefon auf. Jeder Code ersetzt einmal einen App-Code. Sie werden nur jetzt angezeigt.',
1748
+ 'mfa.codes_saved': 'Ich habe diese Codes gespeichert',
1749
+ 'mfa.codes_done': 'Fertig',
1750
+ 'mfa.codes_kept': 'Wiederherstellungscodes gespeichert.',
1751
+ 'mfa.codes_left': 'Unbenutzte Wiederherstellungscodes: {n}.',
1752
+ 'mfa.codes_after': 'Sie erhalten Wiederherstellungscodes, wenn Sie eine Authenticator-App hinzufügen.',
1753
+ 'mfa.codes_low': 'Nur noch wenige Wiederherstellungscodes: Erstellen Sie neue.',
1754
+ 'mfa.codes_new': 'Neue Wiederherstellungscodes',
1755
+ 'mfa.codes_new_confirm': 'Neue Wiederherstellungscodes erstellen? Die alten gelten dann nicht mehr.',
1756
+ 'mfa.expired': 'Die Anmeldung hat zu lange gedauert: Melden Sie sich erneut an.',
1757
+ 'mfa.step_title': 'Zwei-Faktor-Anmeldung',
1758
+ 'mfa.step_intro': 'Geben Sie den Code aus Ihrer Authenticator-App für {user} ein.',
1759
+ 'mfa.code': 'Code',
1760
+ 'mfa.code_help': '6 Ziffern aus der App oder einer Ihrer Wiederherstellungscodes.',
1761
+ 'mfa.verify': 'Bestätigen',
1762
+ 'mfa.cancel': 'Zurück zur Anmeldung',
1763
+ 'mfa.locked_out': 'Telefon und Codes verloren? Bitten Sie einen Administrator, Ihre Zwei-Faktor-Anmeldung zurückzusetzen.',
1764
+ 'mfa.wrong': 'Dieser Code ist falsch oder wurde schon verwendet.',
1765
+ 'mfa.column': 'Zwei-Faktor',
1766
+ 'mfa.on': 'an',
1767
+ 'mfa.off': 'aus',
1768
+ 'mfa.reset': 'Zurücksetzen',
1769
+ 'mfa.reason': 'Grund',
1770
+ 'mfa.reset_help': 'Entfernt die Apps und Wiederherstellungscodes von {user} und meldet die Person ab. Protokolliert; die Administratoren erhalten eine E-Mail.',
1771
+ 'mfa.reset_btn': 'Zwei-Faktor-Anmeldung zurücksetzen',
1772
+ 'mfa.reason_needed': 'Geben Sie einen Grund für das Zurücksetzen an.',
1773
+ 'mfa.reset_done': 'Zwei-Faktor-Anmeldung von {user} zurückgesetzt.',
1774
+ 'mfa.policy_title': 'Zwei-Faktor-Anmeldung',
1775
+ 'mfa.policy_label': 'Zwei-Faktor-Anmeldung verlangen für',
1776
+ 'mfa.policy_off': 'Niemanden (freiwillig)',
1777
+ 'mfa.policy_admins': 'Administratoren',
1778
+ 'mfa.policy_all': 'Alle Entwickler',
1779
+ 'mfa.grace': 'Übergangsfrist (Tage)',
1780
+ 'mfa.grace_help': 'Entwickler ohne App sehen bis dahin eine Erinnerung, danach nur noch ihre Sicherheitsseite.',
1781
+ 'mfa.policy_help': 'Administratoren mit Zwei-Faktor-Anmeldung: {enrolled} von {admins}. Zum Verlangen braucht es mindestens zwei (oder alle, wenn es weniger sind).',
1782
+ 'mfa.policy_save': 'Speichern',
1783
+ 'mfa.policy_saved': 'Zwei-Faktor-Richtlinie gespeichert.',
1784
+ 'mfa.policy_needs_admins': 'Zuerst müssen mindestens zwei Administratoren (oder alle, wenn es weniger sind) die Zwei-Faktor-Anmeldung einrichten, damit niemand allein ausgesperrt wird.',
1785
+ 'mfa.without': 'Ohne Zwei-Faktor-Anmeldung: {list}.',
1786
+ 'mfa.cli_note': 'Ausgesperrt? Auf dem Server: pgkiln admin reset-2fa <developer> oder pgkiln admin set-2fa-policy off.',
1714
1787
  };
@@ -1714,4 +1714,77 @@ export const en = {
1714
1714
  'dev.not_found': 'Not found.',
1715
1715
  'dev.role_changed': 'Role changed.',
1716
1716
  'dev.removed': 'Developer removed.',
1717
+ // ------------------------------------------------------------ Security: two-factor sign-in (sprint 126)
1718
+ 'mfa.menu': 'Two-factor sign-in',
1719
+ 'mfa.title': 'Security',
1720
+ 'mfa.intro': 'Sign in with a code from an authenticator app after your password. Recovery codes get you in when you lose the phone.',
1721
+ 'mfa.required_you': 'Your administrator requires two-factor sign-in: add an authenticator app.',
1722
+ 'mfa.banner': 'Two-factor sign-in is required. Set it up before {date}: {link}',
1723
+ 'mfa.set_up_now': 'set up now',
1724
+ 'mfa.apps': 'Authenticator apps',
1725
+ 'mfa.app_name': 'Name',
1726
+ 'mfa.app_default': 'Phone',
1727
+ 'mfa.added': 'Added',
1728
+ 'mfa.last_used': 'Last used',
1729
+ 'mfa.no_apps': 'No authenticator app yet: you sign in with your password only.',
1730
+ 'mfa.add_app': 'Add an authenticator app',
1731
+ 'mfa.no_key': 'Two-factor sign-in needs the instance key (PGKILN_SECRET_KEY) to store the app’s secret.',
1732
+ 'mfa.scan': 'Scan the QR code with an authenticator app.',
1733
+ 'mfa.or_enter': 'Or enter this key by hand:',
1734
+ 'mfa.enter_code': 'Enter the 6-digit code the app shows.',
1735
+ 'mfa.qr_label': 'QR code for the authenticator app',
1736
+ 'mfa.confirm_app': 'Confirm and turn on',
1737
+ 'mfa.cancel_setup': 'Cancel',
1738
+ 'mfa.setup_expired': 'The setup took too long: start again.',
1739
+ 'mfa.wrong_setup': 'That code doesn’t match: check the time on your phone and try the next code.',
1740
+ 'mfa.app_added': 'Authenticator app added: from now on you sign in with a code too.',
1741
+ 'mfa.remove': 'Remove',
1742
+ 'mfa.remove_app': 'Remove this app',
1743
+ 'mfa.your_password': 'Your password',
1744
+ 'mfa.wrong_password': 'Wrong password.',
1745
+ 'mfa.cannot_remove_required': 'Two-factor sign-in is required for you: add another app before you remove this one.',
1746
+ 'mfa.cannot_remove_admin': 'At least two administrators (or every administrator, when there are fewer) must keep two-factor sign-in while the policy is on.',
1747
+ 'mfa.keep_admins': 'Not now: the two-factor policy needs at least two administrators with two-factor sign-in (or every administrator, when there are fewer).',
1748
+ 'mfa.removed': 'Authenticator app removed.',
1749
+ 'mfa.codes_title': 'Recovery codes',
1750
+ 'mfa.codes_once': 'Save these codes somewhere safe, away from your phone. Each one signs you in once instead of an app code. They are shown only now.',
1751
+ 'mfa.codes_saved': 'I saved these codes',
1752
+ 'mfa.codes_done': 'Done',
1753
+ 'mfa.codes_kept': 'Recovery codes saved.',
1754
+ 'mfa.codes_left': 'Unused recovery codes: {n}.',
1755
+ 'mfa.codes_after': 'You get recovery codes when you add an authenticator app.',
1756
+ 'mfa.codes_low': 'Few recovery codes left: make new ones.',
1757
+ 'mfa.codes_new': 'New recovery codes',
1758
+ 'mfa.codes_new_confirm': 'Make new recovery codes? The old ones stop working.',
1759
+ 'mfa.expired': 'The sign-in took too long: sign in again.',
1760
+ 'mfa.step_title': 'Two-factor sign-in',
1761
+ 'mfa.step_intro': 'Enter the code from your authenticator app for {user}.',
1762
+ 'mfa.code': 'Code',
1763
+ 'mfa.code_help': '6 digits from the app, or one of your recovery codes.',
1764
+ 'mfa.verify': 'Verify',
1765
+ 'mfa.cancel': 'Back to sign-in',
1766
+ 'mfa.locked_out': 'Lost your phone and codes? Ask an administrator to reset your two-factor sign-in.',
1767
+ 'mfa.wrong': 'That code is not right, or was already used.',
1768
+ 'mfa.column': 'Two-factor',
1769
+ 'mfa.on': 'on',
1770
+ 'mfa.off': 'off',
1771
+ 'mfa.reset': 'Reset',
1772
+ 'mfa.reason': 'Reason',
1773
+ 'mfa.reset_help': 'Removes the apps and recovery codes of {user} and signs them out. Logged; the administrators are told by mail.',
1774
+ 'mfa.reset_btn': 'Reset two-factor sign-in',
1775
+ 'mfa.reason_needed': 'Give a reason for the reset.',
1776
+ 'mfa.reset_done': 'Two-factor sign-in of {user} reset.',
1777
+ 'mfa.policy_title': 'Two-factor sign-in',
1778
+ 'mfa.policy_label': 'Require two-factor sign-in for',
1779
+ 'mfa.policy_off': 'Nobody (optional)',
1780
+ 'mfa.policy_admins': 'Administrators',
1781
+ 'mfa.policy_all': 'All developers',
1782
+ 'mfa.grace': 'Grace period (days)',
1783
+ 'mfa.grace_help': 'Developers without an app see a reminder until then; after it, only their Security page.',
1784
+ 'mfa.policy_help': 'Administrators with two-factor sign-in: {enrolled} of {admins}. Requiring it needs at least two of them (or every one, when there are fewer).',
1785
+ 'mfa.policy_save': 'Save',
1786
+ 'mfa.policy_saved': 'Two-factor policy saved.',
1787
+ 'mfa.policy_needs_admins': 'First, at least two administrators (or every administrator, when there are fewer) set up two-factor sign-in, so nobody is locked out alone.',
1788
+ 'mfa.without': 'Without two-factor sign-in: {list}.',
1789
+ 'mfa.cli_note': 'Locked out? On the server: pgkiln admin reset-2fa <developer> or pgkiln admin set-2fa-policy off.',
1717
1790
  } as const;
@@ -1711,4 +1711,77 @@ export const es: BuilderMessages = {
1711
1711
  'dev.not_found': 'No encontrado.',
1712
1712
  'dev.role_changed': 'Rol cambiado.',
1713
1713
  'dev.removed': 'Desarrollador quitado.',
1714
+ // ------------------------------------------------------------ Security: two-factor sign-in (sprint 126)
1715
+ 'mfa.menu': 'Inicio de sesión en dos pasos',
1716
+ 'mfa.title': 'Seguridad',
1717
+ 'mfa.intro': 'Inicie sesión con un código de una aplicación de autenticación después de su contraseña. Los códigos de recuperación le permiten entrar si pierde el teléfono.',
1718
+ 'mfa.required_you': 'Su administrador exige el inicio de sesión en dos pasos: añada una aplicación de autenticación.',
1719
+ 'mfa.banner': 'El inicio de sesión en dos pasos es obligatorio. Configúrelo antes del {date}: {link}',
1720
+ 'mfa.set_up_now': 'configurar ahora',
1721
+ 'mfa.apps': 'Aplicaciones de autenticación',
1722
+ 'mfa.app_name': 'Nombre',
1723
+ 'mfa.app_default': 'Teléfono',
1724
+ 'mfa.added': 'Añadida',
1725
+ 'mfa.last_used': 'Último uso',
1726
+ 'mfa.no_apps': 'Aún no hay aplicación de autenticación: inicia sesión solo con su contraseña.',
1727
+ 'mfa.add_app': 'Añadir una aplicación de autenticación',
1728
+ 'mfa.no_key': 'El inicio de sesión en dos pasos necesita la clave de la instancia (PGKILN_SECRET_KEY) para guardar el secreto de la aplicación.',
1729
+ 'mfa.scan': 'Escanee el código QR con una aplicación de autenticación.',
1730
+ 'mfa.or_enter': 'O introduzca esta clave a mano:',
1731
+ 'mfa.enter_code': 'Introduzca el código de 6 dígitos que muestra la aplicación.',
1732
+ 'mfa.qr_label': 'Código QR para la aplicación de autenticación',
1733
+ 'mfa.confirm_app': 'Confirmar y activar',
1734
+ 'mfa.cancel_setup': 'Cancelar',
1735
+ 'mfa.setup_expired': 'La configuración tardó demasiado: empiece de nuevo.',
1736
+ 'mfa.wrong_setup': 'Ese código no coincide: compruebe la hora del teléfono y pruebe el siguiente código.',
1737
+ 'mfa.app_added': 'Aplicación de autenticación añadida: a partir de ahora también inicia sesión con un código.',
1738
+ 'mfa.remove': 'Quitar',
1739
+ 'mfa.remove_app': 'Quitar esta aplicación',
1740
+ 'mfa.your_password': 'Su contraseña',
1741
+ 'mfa.wrong_password': 'Contraseña incorrecta.',
1742
+ 'mfa.cannot_remove_required': 'El inicio de sesión en dos pasos es obligatorio para usted: añada otra aplicación antes de quitar esta.',
1743
+ 'mfa.cannot_remove_admin': 'Al menos dos administradores (o todos, si hay menos) deben mantener el inicio de sesión en dos pasos mientras la política esté activa.',
1744
+ 'mfa.keep_admins': 'Ahora no: la política de dos pasos necesita al menos dos administradores con inicio de sesión en dos pasos (o todos, si hay menos).',
1745
+ 'mfa.removed': 'Aplicación de autenticación quitada.',
1746
+ 'mfa.codes_title': 'Códigos de recuperación',
1747
+ 'mfa.codes_once': 'Guarde estos códigos en un lugar seguro, lejos del teléfono. Cada uno sustituye una vez a un código de la aplicación. Solo se muestran ahora.',
1748
+ 'mfa.codes_saved': 'He guardado estos códigos',
1749
+ 'mfa.codes_done': 'Hecho',
1750
+ 'mfa.codes_kept': 'Códigos de recuperación guardados.',
1751
+ 'mfa.codes_left': 'Códigos de recuperación sin usar: {n}.',
1752
+ 'mfa.codes_after': 'Recibe códigos de recuperación al añadir una aplicación de autenticación.',
1753
+ 'mfa.codes_low': 'Quedan pocos códigos de recuperación: genere nuevos.',
1754
+ 'mfa.codes_new': 'Nuevos códigos de recuperación',
1755
+ 'mfa.codes_new_confirm': '¿Generar nuevos códigos de recuperación? Los antiguos dejan de funcionar.',
1756
+ 'mfa.expired': 'El inicio de sesión tardó demasiado: inicie sesión de nuevo.',
1757
+ 'mfa.step_title': 'Inicio de sesión en dos pasos',
1758
+ 'mfa.step_intro': 'Introduzca el código de su aplicación de autenticación para {user}.',
1759
+ 'mfa.code': 'Código',
1760
+ 'mfa.code_help': '6 dígitos de la aplicación o uno de sus códigos de recuperación.',
1761
+ 'mfa.verify': 'Verificar',
1762
+ 'mfa.cancel': 'Volver al inicio de sesión',
1763
+ 'mfa.locked_out': '¿Perdió el teléfono y los códigos? Pida a un administrador que restablezca su inicio de sesión en dos pasos.',
1764
+ 'mfa.wrong': 'Ese código no es correcto o ya se usó.',
1765
+ 'mfa.column': 'Dos pasos',
1766
+ 'mfa.on': 'activado',
1767
+ 'mfa.off': 'desactivado',
1768
+ 'mfa.reset': 'Restablecer',
1769
+ 'mfa.reason': 'Motivo',
1770
+ 'mfa.reset_help': 'Quita las aplicaciones y los códigos de recuperación de {user} y cierra su sesión. Se registra; los administradores reciben un correo.',
1771
+ 'mfa.reset_btn': 'Restablecer el inicio de sesión en dos pasos',
1772
+ 'mfa.reason_needed': 'Indique un motivo para el restablecimiento.',
1773
+ 'mfa.reset_done': 'Inicio de sesión en dos pasos de {user} restablecido.',
1774
+ 'mfa.policy_title': 'Inicio de sesión en dos pasos',
1775
+ 'mfa.policy_label': 'Exigir el inicio de sesión en dos pasos a',
1776
+ 'mfa.policy_off': 'Nadie (opcional)',
1777
+ 'mfa.policy_admins': 'Administradores',
1778
+ 'mfa.policy_all': 'Todos los desarrolladores',
1779
+ 'mfa.grace': 'Período de gracia (días)',
1780
+ 'mfa.grace_help': 'Los desarrolladores sin aplicación ven un aviso hasta entonces; después, solo su página de Seguridad.',
1781
+ 'mfa.policy_help': 'Administradores con inicio de sesión en dos pasos: {enrolled} de {admins}. Para exigirlo hacen falta al menos dos (o todos, si hay menos).',
1782
+ 'mfa.policy_save': 'Guardar',
1783
+ 'mfa.policy_saved': 'Política de dos pasos guardada.',
1784
+ 'mfa.policy_needs_admins': 'Primero, al menos dos administradores (o todos, si hay menos) deben configurar el inicio de sesión en dos pasos, para que nadie quede bloqueado solo.',
1785
+ 'mfa.without': 'Sin inicio de sesión en dos pasos: {list}.',
1786
+ 'mfa.cli_note': '¿Bloqueado? En el servidor: pgkiln admin reset-2fa <developer> o pgkiln admin set-2fa-policy off.',
1714
1787
  };