pgkiln 0.78.0 → 0.80.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.
@@ -0,0 +1,186 @@
1
+ -- Sprint 149 (WS-6 leftover; APEX 26.2: in-flight workflow migration): running instances inside parallel branches
2
+ -- move to a newer version too. Migration 123 refused them ("let them reach their join first").
3
+ --
4
+ -- An instance inside branches is at several steps at once: its main path waits at a join (or, nested, a branch
5
+ -- waits at an inner join), and each open branch (active, waiting or faulted) is at a step of its own. Each of these
6
+ -- positions is mapped like the main path was (p_map: old step → new step) and checked with the same rules (a task
7
+ -- step stays a task step of the same task definition, a wait stays a wait, a join stays a join, no draft step, no
8
+ -- call in flight). Branch rows also keep the parallel step that split them and the join they end at: the join is
9
+ -- renamed through the mapping (it must be a join step of the new version; a branch can't be mapped onto its own
10
+ -- join), the split through the mapping or else to the one parallel step of the new version that joins there. Branches that are already done keep their state, so a join counts them as before.
11
+ --
12
+ -- meta.migrate_workflows returns one row per position (the column branch: the branch's first step, null for the
13
+ -- main path); applying moves every position of every instance in one transaction, or nothing.
14
+
15
+ drop function meta.migrate_workflows(int, text, bigint[], jsonb, boolean, text);
16
+
17
+ /** The problem that stops one position (a main path or a branch) from moving to p_to; null: it can move. */
18
+ create function meta.workflow_position_problem(p_state text, p_from_steps jsonb, p_from text, p_to_steps jsonb, p_to text,
19
+ p_waiting_task bigint, p_task_name text, p_to_version text)
20
+ returns text language plpgsql stable set search_path = meta, pg_catalog as $$
21
+ declare
22
+ v_to jsonb := (select s from jsonb_array_elements(p_to_steps) s where s->>'name' = p_to limit 1);
23
+ v_from jsonb := (select s from jsonb_array_elements(p_from_steps) s where s->>'name' = p_from limit 1);
24
+ begin
25
+ if p_to is null or p_to = '' then
26
+ return format('no step of version %s is mapped to %s', p_to_version, coalesce(p_from, '(none)'));
27
+ elsif v_to is null then
28
+ return format('version %s has no step %s', p_to_version, p_to);
29
+ elsif v_to->>'type' = 'draft' then
30
+ return format('%s is a draft step', p_to);
31
+ elsif p_waiting_task is not null and v_to->>'type' <> 'task' then
32
+ return format('waits for a task: %s must be a task step', p_to);
33
+ elsif p_waiting_task is not null and upper(v_to->>'task') is distinct from p_task_name then
34
+ return format('waits for a task of %s, but %s creates %s', p_task_name, p_to, coalesce(v_to->>'task', '(none)'));
35
+ elsif p_state = 'waiting' and p_waiting_task is null and v_from->>'type' = 'invoke_api' then
36
+ return 'is calling a web service: try again when the call is done';
37
+ elsif p_state = 'waiting' and p_waiting_task is null and v_from->>'type' = 'wait' and v_to->>'type' <> 'wait' then
38
+ return format('waits at a wait step: %s must be a wait step', p_to);
39
+ elsif p_state = 'waiting' and p_waiting_task is null and v_from->>'type' = 'join' and v_to->>'type' <> 'join' then
40
+ return format('waits at a join: %s must be a join step', p_to);
41
+ end if;
42
+ return null;
43
+ end
44
+ $$;
45
+ revoke all on function meta.workflow_position_problem(text, jsonb, text, jsonb, text, bigint, text, text) from public;
46
+
47
+ /**
48
+ * Move running instances (p_ids) of a definition to a newer version (p_to_version: the active version or a later
49
+ * inactive one), each position at the step p_map gives for its current step. Returns one row per position (branch:
50
+ * the branch's first step, null for the main path) with the problem that stops it (null: it can move). With p_apply,
51
+ * nothing changes unless every position of every instance can move; then all move in this transaction, with a
52
+ * "migrated" event each and a row in meta.workflow_migration.
53
+ */
54
+ create function meta.migrate_workflows(p_definition_id int, p_to_version text, p_ids bigint[], p_map jsonb, p_apply boolean, p_by text)
55
+ returns table (workflow_id bigint, branch text, from_version text, from_step text, to_step text, problem text)
56
+ language plpgsql set search_path = meta, pg_catalog as $$
57
+ declare
58
+ d meta.workflow_definition;
59
+ v_order text[];
60
+ v_target int;
61
+ v_steps jsonb;
62
+ w record;
63
+ b record;
64
+ v_rows jsonb := '[]';
65
+ v_bad text[] := '{}';
66
+ v_id bigint;
67
+ v_join text;
68
+ v_split text;
69
+ r jsonb;
70
+ begin
71
+ select * into d from workflow_definition where id = p_definition_id;
72
+ if not found then
73
+ raise exception 'Workflow definition % does not exist.', p_definition_id;
74
+ end if;
75
+ if coalesce(cardinality(p_ids), 0) = 0 then
76
+ raise exception 'Choose the instances to migrate.';
77
+ end if;
78
+ if jsonb_typeof(coalesce(p_map, '{}')) <> 'object' then
79
+ raise exception 'The step mapping is a JSON object.';
80
+ end if;
81
+ -- versions from the oldest to the active one
82
+ v_order := array(select x->>'version' from jsonb_array_elements(d.inactive_versions) with ordinality o(x, i) order by i) || d.version;
83
+ v_target := array_position(v_order, p_to_version);
84
+ if v_target is null then
85
+ raise exception 'Workflow % has no version % to migrate to (the active version or an inactive one).', d.name, p_to_version;
86
+ end if;
87
+ v_steps := case when p_to_version = d.version then d.steps
88
+ else (select x->'steps' from jsonb_array_elements(d.inactive_versions) x where x->>'version' = p_to_version limit 1) end;
89
+
90
+ foreach v_id in array (select array_agg(distinct x order by x) from unnest(p_ids) x) loop
91
+ select wf.id, wf.app_id, wf.definition_id, coalesce(wf.version, '1') as version, wf.state, wf.current_step, wf.steps, wf.waiting_task,
92
+ (select td.name from task tk join task_definition td on td.id = tk.definition_id where tk.id = wf.waiting_task) as task_name
93
+ into w from workflow wf where wf.id = v_id for update;
94
+ -- the main path
95
+ workflow_id := v_id;
96
+ branch := null;
97
+ from_version := w.version;
98
+ from_step := w.current_step;
99
+ to_step := case when w.current_step is not null then p_map->>w.current_step end;
100
+ problem := null;
101
+ if w.id is null or w.definition_id is distinct from d.id or w.app_id <> d.app_id then
102
+ problem := 'not an instance of this workflow';
103
+ from_version := null;
104
+ from_step := null;
105
+ to_step := null;
106
+ elsif w.state not in ('active', 'waiting', 'faulted') then
107
+ problem := format('is %s', w.state);
108
+ elsif coalesce(array_position(v_order, w.version), 0) >= v_target then
109
+ problem := format('runs version %s, which is not older than %s', w.version, p_to_version);
110
+ else
111
+ problem := meta.workflow_position_problem(w.state, w.steps, w.current_step, v_steps, to_step, w.waiting_task, w.task_name, p_to_version);
112
+ end if;
113
+ if problem is not null then
114
+ v_bad := v_bad || format('%s %s', v_id, problem);
115
+ end if;
116
+ v_rows := v_rows || jsonb_build_object('id', v_id, 'branch_id', null, 'branch', null, 'from_version', from_version, 'from_step', from_step, 'to_step', to_step);
117
+ return next;
118
+ continue when w.id is null or w.definition_id is distinct from d.id or w.app_id <> d.app_id
119
+ or w.state not in ('active', 'waiting', 'faulted') or coalesce(array_position(v_order, w.version), 0) >= v_target;
120
+
121
+ -- (144) each open branch, at a step of its own; its join and split through the mapping
122
+ for b in
123
+ select br.id, br.name, br.state, br.current_step, br.waiting_task, br.split_step, br.join_step,
124
+ (select td.name from task tk join task_definition td on td.id = tk.definition_id where tk.id = br.waiting_task) as task_name
125
+ from workflow_branch br where br.workflow_id = v_id and br.state in ('active', 'waiting', 'faulted') order by br.id
126
+ loop
127
+ branch := b.name;
128
+ from_step := b.current_step;
129
+ to_step := case when b.current_step is not null then p_map->>b.current_step end;
130
+ v_join := coalesce(nullif(p_map->>b.join_step, ''), b.join_step);
131
+ -- the parallel step that split it: mapped, else the one step of the new version that joins at its new join
132
+ v_split := coalesce(nullif(p_map->>b.split_step, ''),
133
+ (select min(s->>'name') from jsonb_array_elements(v_steps) s where s->>'type' = 'parallel' and s->>'join' = v_join
134
+ having count(*) = 1),
135
+ b.split_step);
136
+ problem := meta.workflow_position_problem(b.state, w.steps, b.current_step, v_steps, to_step, b.waiting_task, b.task_name, p_to_version);
137
+ if problem is null and not exists (select 1 from jsonb_array_elements(v_steps) s where s->>'name' = v_join and s->>'type' = 'join') then
138
+ problem := format('ends at the join %s: version %s has no join step %s', b.join_step, p_to_version, v_join);
139
+ elsif problem is null and to_step = v_join then
140
+ problem := format('a branch can''t be mapped onto its own join %s', v_join);
141
+ end if;
142
+ if problem is not null then
143
+ v_bad := v_bad || format('%s (branch %s) %s', v_id, b.name, problem);
144
+ end if;
145
+ v_rows := v_rows || jsonb_build_object('id', v_id, 'branch_id', b.id, 'branch', b.name, 'from_version', w.version, 'from_step', b.current_step,
146
+ 'to_step', to_step, 'join', v_join, 'split', v_split);
147
+ from_version := w.version;
148
+ return next;
149
+ end loop;
150
+ end loop;
151
+
152
+ if not p_apply then
153
+ return;
154
+ end if;
155
+ if cardinality(v_bad) > 0 then
156
+ raise exception 'Nothing was migrated: instance %.', array_to_string(v_bad, '; instance ');
157
+ end if;
158
+ for r in select * from jsonb_array_elements(v_rows) loop
159
+ if r->>'branch_id' is null then
160
+ update workflow set steps = v_steps, version = p_to_version, current_step = r->>'to_step', updated_at = now()
161
+ where id = (r->>'id')::bigint;
162
+ perform meta.workflow_log((r->>'id')::bigint, r->>'to_step', 'migrated',
163
+ format('version %s → %s: %s → %s (by %s)', r->>'from_version', p_to_version, r->>'from_step', r->>'to_step', p_by));
164
+ else
165
+ update workflow_branch set current_step = r->>'to_step', updated_at = now() where id = (r->>'branch_id')::bigint;
166
+ perform meta.workflow_log((r->>'id')::bigint, r->>'to_step', 'migrated',
167
+ format('version %s → %s: branch %s: %s → %s (by %s)', r->>'from_version', p_to_version, r->>'branch', r->>'from_step', r->>'to_step', p_by));
168
+ end if;
169
+ end loop;
170
+ -- every branch of a moved instance (done ones too: a join counts them) ends at and was split by the mapped steps
171
+ update workflow_branch br
172
+ set join_step = j.name,
173
+ split_step = coalesce(nullif(p_map->>br.split_step, ''),
174
+ (select min(s->>'name') from jsonb_array_elements(v_steps) s where s->>'type' = 'parallel' and s->>'join' = j.name
175
+ having count(*) = 1),
176
+ br.split_step)
177
+ from (select b2.id, coalesce(nullif(p_map->>b2.join_step, ''), b2.join_step) as name from workflow_branch b2) j
178
+ where j.id = br.id and br.workflow_id in (select distinct (x->>'id')::bigint from jsonb_array_elements(v_rows) x);
179
+ insert into workflow_migration (app_id, definition_name, to_version, mapping, workflow_ids, detail, migrated_by)
180
+ values (d.app_id, d.name, p_to_version, coalesce(p_map, '{}'),
181
+ array(select distinct (x->>'id')::bigint from jsonb_array_elements(v_rows) x order by 1), v_rows, p_by);
182
+ -- active ones go on with their new step
183
+ perform pg_notify('pgkiln_workflow', 'migrated');
184
+ end
185
+ $$;
186
+ revoke all on function meta.migrate_workflows(int, text, bigint[], jsonb, boolean, text) from public;
@@ -0,0 +1,41 @@
1
+ -- Sprint 150 (AP-7 leftover; APEX: REST Enabled SQL services, regions on another database): remote databases.
2
+ --
3
+ -- A remote database is another PostgreSQL database whose tables applications query as if they were local: pgkiln
4
+ -- makes a postgres_fdw server for it, a user mapping (the remote user and password: kept by PostgreSQL in
5
+ -- pg_user_mapping, which only superusers and the server's owner can read; pgkiln itself never stores the password),
6
+ -- and imports the remote schema's tables (all, or the ones named) as foreign tables into a local schema of their
7
+ -- own. Regions, lists of values, reports, forms and grids then use <local schema>.<table> like any table: as the
8
+ -- application's database role, in its transaction, with the grants given here (SELECT, optionally INSERT, UPDATE,
9
+ -- DELETE). The remote side's own rights decide what the remote user may do there.
10
+ --
11
+ -- Administrators manage them (Workspace utilities → Remote databases); the rows are installation data, never
12
+ -- exported with an application (the foreign tables are database objects, like the application's own tables).
13
+
14
+ create table meta.remote_database (
15
+ id serial primary key,
16
+ -- the static id: upper case, used in messages and the server's name
17
+ name text not null unique check (name ~ '^[A-Z][A-Z0-9_]{0,29}$'),
18
+ description text check (length(description) <= 1000),
19
+ host text not null check (length(host) between 1 and 253),
20
+ port int not null default 5432 check (port between 1 and 65535),
21
+ dbname text not null check (length(dbname) between 1 and 63),
22
+ user_name text not null check (length(user_name) between 1 and 63),
23
+ remote_schema text not null default 'public' check (length(remote_schema) between 1 and 63),
24
+ -- the schema the foreign tables go into; pgkiln's own (marked by its comment), dropped with the remote database
25
+ local_schema text not null unique check (local_schema ~ '^[a-z_][a-z0-9_]{0,62}$'),
26
+ -- the remote tables to import; empty: all of the remote schema's tables and views
27
+ tables text[] not null default '{}',
28
+ -- application database roles granted USAGE on the schema and SELECT (and with writable INSERT, UPDATE, DELETE)
29
+ grant_roles text[] not null default '{}',
30
+ writable boolean not null default false,
31
+ -- the postgres_fdw server: pgkiln_rdb_<name in lower case>
32
+ server_name text not null unique,
33
+ imported_at timestamptz,
34
+ imported int,
35
+ error text,
36
+ created_by text not null,
37
+ updated_by text not null,
38
+ updated_at timestamptz not null default now()
39
+ );
40
+ revoke all on meta.remote_database from public;
41
+ comment on table meta.remote_database is 'Remote PostgreSQL databases imported as foreign tables (postgres_fdw) into a local schema (150); installation data, administrators only, never exported. Passwords live only in the user mapping.';
@@ -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-11-05 against **APEX 26.2** (sprint 145: the texts that offered AI with "Claude or OpenAI" name all four providers: Claude, OpenAI, Gemini and OpenAI-compatible services (AP-11); sprint 144: `pgkiln advise` for CI with text, JSON and SARIF output (APEXlang static analysis / SQLcl CodeScan), security checks in the Advisor, and working copies and locks from the command line and MCP (the Working Copy APIs) (AP-10); sprint 143: the interactive report's 26.2 dialogs: *is one of* / *is not one of* filters with the column's values and counts, *is between* two values (dates with the date picker in the application's format), relative periods on date columns, and the column order by drag and drop or arrow buttons, followed by downloads and the PDF (AP-9); sprint 142: JSON sources with a data profile and updatable views whose arrays are rows, document views of a table with its children (APEX's duality views), JSON path columns in reports (AP-8); sprint 141: static workspace files (`#WORKSPACE_FILES#`), remote servers for REST data sources, catalogs and AI services (an environment variable per environment), and workspace-level web credentials (AP-7); sprint 140: the items Shuttle (ordered), Select One and Select Many, the regions Classic Report (report templates, pagination types), Breadcrumb and Help Text with a page help text, and a [mapping of every APEX item and region type](#item-and-region-types-one-by-one) (AP-4); sprint 139: OpenTelemetry, traces with a span per SQL statement, web call, AI request and tool call, logs, metrics and `/metrics` for Prometheus, browser spans relayed by pgkiln, per workspace off or its own collector (AP-6); sprint 138: an application's Utilities tab with a dashboard, database object dependencies, change history per component, Upgrade application, UI defaults (APEX's Attribute Dictionary), application and page checksums and an icon browser (AP-5); sprint 137: Create page as a grid of page types with previews, the page types interactive report, smart filters, search page, data loading, tree, timeline, media list, content row, comments, dashboard, wizard, unified task list and workflow console, a Feature tab with nine features that install once, and Create page as copy with shared components mapped or copied (AP-3); sprint 136: vector providers (an AI service with an embedding model or a SQL function), `meta.embed`, *Add vector column* in Table Properties with an HNSW index and a queue that keeps embeddings current, search types vector and hybrid (reciprocal rank fusion with full-text) and a Retrieve (RAG) tool for AI agents, all as the app's role through RLS, on pgvector (AP-1); sprint 135: full-text search configurations, APEX's Oracle Text search type on PostgreSQL full-text search with stemming, ranking, highlights, *Did you mean* and *Add full-text search* in Table Properties (AP-2); sprint 134: the builder also in Italiano, 中文 (简体), 中文 (繁體), 日本語 and 한국어, APEX's ten builder languages plus Nederlands (SEC-5); 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).
10
+ Last reviewed: 2026-11-05 against **APEX 26.2** (sprint 150: remote databases, another PostgreSQL database's tables as foreign tables the applications query (REST Enabled SQL, AP-7 leftover); sprint 149: running workflow instances inside parallel branches migrate to a newer version (WS-6 leftover); sprint 148: the AI assistant streams its answers as the model writes them (WS-4 leftover); sprint 147: `pgkiln advise --offline` checks an export's files without a database (AP-10 leftover); sprint 146: the Advisor checks JSON sources' views against their data profile (AP-8 leftover); sprint 145: the texts that offered AI with "Claude or OpenAI" name all four providers: Claude, OpenAI, Gemini and OpenAI-compatible services (AP-11); sprint 144: `pgkiln advise` for CI with text, JSON and SARIF output (APEXlang static analysis / SQLcl CodeScan), security checks in the Advisor, and working copies and locks from the command line and MCP (the Working Copy APIs) (AP-10); sprint 143: the interactive report's 26.2 dialogs: *is one of* / *is not one of* filters with the column's values and counts, *is between* two values (dates with the date picker in the application's format), relative periods on date columns, and the column order by drag and drop or arrow buttons, followed by downloads and the PDF (AP-9); sprint 142: JSON sources with a data profile and updatable views whose arrays are rows, document views of a table with its children (APEX's duality views), JSON path columns in reports (AP-8); sprint 141: static workspace files (`#WORKSPACE_FILES#`), remote servers for REST data sources, catalogs and AI services (an environment variable per environment), and workspace-level web credentials (AP-7); sprint 140: the items Shuttle (ordered), Select One and Select Many, the regions Classic Report (report templates, pagination types), Breadcrumb and Help Text with a page help text, and a [mapping of every APEX item and region type](#item-and-region-types-one-by-one) (AP-4); sprint 139: OpenTelemetry, traces with a span per SQL statement, web call, AI request and tool call, logs, metrics and `/metrics` for Prometheus, browser spans relayed by pgkiln, per workspace off or its own collector (AP-6); sprint 138: an application's Utilities tab with a dashboard, database object dependencies, change history per component, Upgrade application, UI defaults (APEX's Attribute Dictionary), application and page checksums and an icon browser (AP-5); sprint 137: Create page as a grid of page types with previews, the page types interactive report, smart filters, search page, data loading, tree, timeline, media list, content row, comments, dashboard, wizard, unified task list and workflow console, a Feature tab with nine features that install once, and Create page as copy with shared components mapped or copied (AP-3); sprint 136: vector providers (an AI service with an embedding model or a SQL function), `meta.embed`, *Add vector column* in Table Properties with an HNSW index and a queue that keeps embeddings current, search types vector and hybrid (reciprocal rank fusion with full-text) and a Retrieve (RAG) tool for AI agents, all as the app's role through RLS, on pgvector (AP-1); sprint 135: full-text search configurations, APEX's Oracle Text search type on PostgreSQL full-text search with stemming, ranking, highlights, *Did you mean* and *Add full-text search* in Table Properties (AP-2); sprint 134: the builder also in Italiano, 中文 (简体), 中文 (繁體), 日本語 and 한국어, APEX's ten builder languages plus Nederlands (SEC-5); 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
 
@@ -20,11 +20,11 @@ Last reviewed: 2026-11-05 against **APEX 26.2** (sprint 145: the texts that offe
20
20
  | Security | 22 | 0 | 0 | 0 | An editable login page and Forgot password; a session timeout warning; On par or stricter (CSP without `unsafe-inline`); OIDC, SAML and LDAP; header authentication behind a proxy; database accounts; custom authentication |
21
21
  | User interface | 12 | 0 | 0 | 0 | Region templates incl. hero, inline dialog and drawer, wizard and carousel; Universal Theme-like and responsive; a Theme Roller with style variants and conditional, dynamic styles; about 1,700 icons with Font APEX-like modifiers |
22
22
  | Globalization | 6 | 0 | 0 | 0 | One translated app like 26.1 with dynamic translations of table values; number format masks and automatic time zone; twenty-two built-in languages |
23
- | Data and integration | 16 | 0 | 0 | 1 | Remote servers, static workspace files and workspace web credentials; REST source catalogs from OpenAPI documents; Generate DDL and schema comparison; `meta.data_export` and data export downloads (CSV, JSON, XML, HTML, Excel, PDF); e-mail through SMTP (password or OAuth2), Microsoft Graph, Amazon SES and HTTP APIs; REST APIs via PostgREST, REST data sources that write back and synchronise, web credentials with OAuth2 grants, CSV/XLSX/JSON/XML loading with saved definitions and unloading, SQL scripts and Quick SQL, report PDFs and document templates |
23
+ | Data and integration | 17 | 0 | 0 | 0 | Remote servers, static workspace files and workspace web credentials; REST source catalogs from OpenAPI documents; Generate DDL and schema comparison; `meta.data_export` and data export downloads (CSV, JSON, XML, HTML, Excel, PDF); e-mail through SMTP (password or OAuth2), Microsoft Graph, Amazon SES and HTTP APIs; REST APIs via PostgREST, REST data sources that write back and synchronise, web credentials with OAuth2 grants, CSV/XLSX/JSON/XML loading with saved definitions and unloading, SQL scripts and Quick SQL, report PDFs and document templates |
24
24
  | Workflow, automation and AI | 6 | 0 | 0 | 0 | Scheduled automations with several actions and runs from SQL, approvals, a task list and workflows with parallel branches, versions and invoke-API steps; AI with Claude, OpenAI, Gemini or an OpenAI-compatible service: *Generate text with AI*, an assistant region with tools, natural-language report filters and blueprints |
25
25
  | Administration | 15 | 0 | 0 | 0 | OpenTelemetry traces, logs and metrics to the team's own monitoring and `/metrics` for Prometheus (24.2); An APEX-like sign-in with a workspace and a Workspace home; a mail queue dashboard, a workspace's own mail service and network access list (26.1 / 26.2); a workspace's components exported and imported as one file; workspace message, environment banner and utilization; isolated workspaces with their own database logins and roles, and workspace administrators; application availability and Run only, automatic backups, user feedback; a developer toolbar with a session state viewer and debug per session; Top SQL per app; debug messages per request; an install/upgrade log |
26
26
  | APEX 26.2 workspace (WS-1 … WS-13) | 13 | 0 | 0 | 1 | Workspace home, Data Reporter as a workspace tool, Team Development, AI Agents, AI interactive reports, Workflow 26.2, the mail queue, workspace mail and network access, the 26.1 component details, the App Builder list's details, the Pillar navigation appearances and data security per table (rows, columns and masked values), the App Gallery's single-topic sample apps, UX Pattern Catalog and Utility Apps; the builder in eleven languages (APEX's ten and Nederlands) |
27
- | **Total** | **171** | **0** | **0** | **3** | 174 APEX features compared: 98% available, none missing, 3 deliberately not planned |
27
+ | **Total** | **172** | **0** | **0** | **2** | 174 APEX features compared: 99% available, none missing, 2 deliberately not planned |
28
28
 
29
29
  (Counts are of the rows in the tables below. A review on 2026-10-06 added 18 rows for APEX features that were
30
30
  not compared before, one on 2026-10-12 added two more (property help, application availability), and one on
@@ -48,7 +48,7 @@ database links row and added static workspace files with workspace web credentia
48
48
  | Shared components | ✅ | (sprint 74) A grid of ten groups with counts like APEX's, a searchable, sortable list per type with Create, and Settings-backed types linking to their Settings tab ([mapping below](#shared-components-apex-links-and-pgkiln)). Navigation menu, **lists** (static entries with nesting, badges, conditions, authorization and build options, or a query; for list regions, the navigation menu and the navigation bar), authorization schemes, build options, lists of values, application items and processes, access control, globalization, template components and plug-ins, web credentials, REST data sources, data load definitions, supporting objects |
49
49
  | Export / import | ✅ | `meta.export_app()` / `meta.import_app()`: portable JSON, also in the builder (new applications; `pgkiln import --replace` and the MCP `import_app` update one in place, live for every user at the commit). (sprint 51) **Checked imports**: `pgkiln import --check` (`--dry-run`, `--force`), the MCP import (by default) and the builder's import run the Advisor inside the import's transaction (SQL planned as the application's role: missing tables, columns, functions, types, grants; references) and refuse on errors, so nothing changes; APEX doesn't check. The version an import replaces is [backed up](guide/03-builder.md#backups) first ([chapter 18](guide/18-cli.md#checking-before-an-import)) |
50
50
  | APEXlang: human-readable, diffable app files; static IDs (26.1) | ✅ | `pgkiln export --format dir`: one JSON file per component with sorted keys, SQL and HTML in sibling files, references by static id instead of database ids; `pgkiln import --replace` updates an app in place, `pgkiln diff` compares ([chapter 18](guide/18-cli.md)). (0.31) **`--format text`**: the same files as YAML (a strict subset any YAML tool reads) with the SQL and templates inline, read back losslessly ([text files](guide/18-cli.md#text-files-apexlang)); regions have a stored **Static ID** (exported as their key, rendered as `data-static-id`), other components are named by their stored names. The syntax is YAML rather than APEXlang's own, so APEXlang files don't import. (sprint 116, 26.2 **file-level import**) `pgkiln import <dir> --replace --only pages/12` (or `--only shared/lovs/jobs.yaml`, repeatable) imports one page or shared component from a directory export and leaves the rest of the application as it is ([chapter 18](guide/18-cli.md#importing-one-page-or-component)) |
51
- | Static analysis of exports in CI (APEXlang / SQLcl CodeScan), Working Copy APIs (26.2) | ✅ | (sprint 144, AP-10) **`pgkiln advise <export \| alias>`** runs the Advisor outside the builder: an export is imported under a temporary alias in a transaction that is always rolled back (code never runs) and checked there; every SQL fragment is planned as the application's role (stronger than CodeScan's file-only checks: unknown tables, columns, functions, types, missing grants), references are followed, and security defaults are checked (pages that write data without sign-in or an authorization scheme, unrestricted page protection, long sessions, administrators without a second factor). Output as text, JSON or **SARIF 2.1.0** with each finding at the file of its page or component, so GitHub code scanning annotates pull requests; `--fail-on` sets the exit code ([chapter 18](guide/18-cli.md#pgkiln-advise-in-ci)). **`pgkiln working-copy list\|create\|compare\|merge\|refresh\|delete`** and **`pgkiln lock` / `unlock`** for scripts and CI, and the MCP tools `advise_app`, `working_copy` and `lock_app` for coding agents ([working copies and locks](guide/18-cli.md#working-copies-and-locks)). It needs a database (pgkiln's migrations and the application's tables), not the files alone |
51
+ | Static analysis of exports in CI (APEXlang / SQLcl CodeScan), Working Copy APIs (26.2) | ✅ | (sprint 144, AP-10) **`pgkiln advise <export \| alias>`** runs the Advisor outside the builder: an export is imported under a temporary alias in a transaction that is always rolled back (code never runs) and checked there; every SQL fragment is planned as the application's role (stronger than CodeScan's file-only checks: unknown tables, columns, functions, types, missing grants), references are followed, and security defaults are checked (pages that write data without sign-in or an authorization scheme, unrestricted page protection, long sessions, administrators without a second factor). Output as text, JSON or **SARIF 2.1.0** with each finding at the file of its page or component, so GitHub code scanning annotates pull requests; `--fail-on` sets the exit code ([chapter 18](guide/18-cli.md#pgkiln-advise-in-ci)). **`pgkiln working-copy list\|create\|compare\|merge\|refresh\|delete`** and **`pgkiln lock` / `unlock`** for scripts and CI, and the MCP tools `advise_app`, `working_copy` and `lock_app` for coding agents ([working copies and locks](guide/18-cli.md#working-copies-and-locks)). The full check needs a database (pgkiln's migrations and the application's tables); (sprint 147) **`--offline`** checks the files alone like CodeScan: references, security defaults, workflow steps and JSON source profiles, without SQL planning |
52
52
  | Working copies, merge, team development | ✅ | **Working copies** of an application ([chapter 3](guide/03-builder.md#working-copies)): a second app on the same schema and data, compared three ways per component (settings, each shared component, page, region, item, …) with the main app as it was when copied; changes on one side merge, conflicts are chosen per component with a line diff; merge into the main app or refresh the copy, keeping users, sessions, saved reports, secrets and automation switches; locks respected. Conflicts are resolved per component, not per property |
53
53
  | Team Development: issues, labels, milestones, templates, feedback | ✅ | (sprint 113) Builder → **Team Development** ([chapter 3](guide/03-builder.md#team-development)): issues per workspace with labels in groups, milestones, assignees, application and page links, Markdown comments with in-app @mentions and a history; a filtered list with saved views and a board by label group or milestone (no JavaScript needed); a set-up wizard installs sample labels, templates, canned responses and milestones. Users' feedback and developer comments become issues; open issues show in the Page Designer, on App Home and on the Workspace home; issues travel in the workspace export. Not included: e-mail notifications, GitHub sync |
54
54
  | Application lock (26.1), page locks, comments | ✅ | Page and application locks, enforced on the server for every builder change; the owner or an administrator unlocks, and an administrator breaking a lock is logged. Developer comments per page and per app ([chapter 3](guide/03-builder.md)) |
@@ -282,10 +282,10 @@ review is a diff. Not counted in [At a glance](#at-a-glance): the rows above com
282
282
  | SQL Workshop utilities: schema comparison, generate DDL | ✅ | (sprint 56) SQL Workshop → **DDL**: a schema's objects (types, sequences, tables, functions, views, constraints, indexes, triggers, RLS and policies, comments, grants) from the catalog, in an order that runs, unqualified so it also creates them in another schema. **Compare**: two schemas by their DDL (only in one, different, with a diff) and a change script that makes the target like the source (tables column by column; drops commented out for review). Also `pgkiln ddl`, `pgkiln compare` and the MCP tools `generate_ddl`, `compare_schemas` ([chapter 3](guide/03-builder.md#sql-workshop)). Two schemas of the same database only (APEX: also within one workspace) |
283
283
  | Data Reporter: self-service reports for business users (26.1) | ✅ | A **Data Reporter** region ([chapter 4](guide/04-pages-and-regions.md#data_reporter-data-reporter)): the developer offers tables and views with chosen columns, labels and format masks; signed-in users pick columns, filter, group with totals (count, sum, average, minimum, maximum), sort and chart, and save reports privately or shared with the app's users. Runs as the app's role (grants and RLS apply); works without JavaScript and fits phones. (sprint 68) A **welcome page** like 26.1's: a greeting (the developer's own, or pgkiln's), the sources as cards that start a report, the user's reports latest first, shared ones, and a search. One source per report (offer a view to combine tables); no downloads from a reporter yet (sprint 110) **A workspace tool too**: App Builder → **Data Reporter** ([chapter 3](guide/03-builder.md#data-reporter-datasets-and-reporting-applications)) keeps **datasets** (tables and views of one schema with joins proposed from foreign keys, offered columns with labels, masks and descriptions, a row filter; files and the workspace export) and makes a **reporting application** on them in two clicks: viewers open published reports by a stable URL and pin them, editors build and publish, administrators moderate; every report runs as the application's SELECT-only role through RLS. |
284
284
  | REST Source Catalogs (Workspace Utilities) | ✅ | (sprint 67) Workspace utilities → **REST Source Catalogs**: a workspace's web services with a base URL and services, from an **OpenAPI 3 / Swagger 2.0** document (file, pasted or read from a URL on the allow-list), a catalog file or by hand: parameters (under the service's own names), row selector, typed columns and write-back operations from the response schemas and collection/item paths, with notes on what can't be used. An application's *REST data sources → From a REST source catalog* makes a data source from a service, with its own web credential ([chapter 19](guide/19-rest-data-sources.md#rest-source-catalogs)). **Missing:** YAML documents (convert to JSON), APEX's built-in catalogs (e.g. Oracle Fusion) |
285
- | JSON sources, duality views (24.2) | ✅ | (sprint 142, AP-8) Shared Components → **JSON Sources** ([chapter 19](guide/19-rest-data-sources.md#json-sources-and-document-views)): a `jsonb` column with a data profile proposed from the documents; `security_invoker` views with a typed column per path and a view per array (stable row keys), whose triggers write only the changed paths, so unknown keys stay; forms, reports, grids, master-detail, AutoREST and MCP use them like tables; Create page makes a form with detail grids. Table Properties → **Document view**: a row and its child rows as one `jsonb` document, written back in one statement (the duality view). JSON path columns in reports |
285
+ | JSON sources, duality views (24.2) | ✅ | (sprint 142, AP-8) Shared Components → **JSON Sources** ([chapter 19](guide/19-rest-data-sources.md#json-sources-and-document-views)): a `jsonb` column with a data profile proposed from the documents; `security_invoker` views with a typed column per path and a view per array (stable row keys), whose triggers write only the changed paths, so unknown keys stay; forms, reports, grids, master-detail, AutoREST and MCP use them like tables; Create page makes a form with detail grids. Table Properties → **Document view**: a row and its child rows as one `jsonb` document, written back in one statement (the duality view). JSON path columns in reports. (sprint 146) The Advisor names views that no longer match their profile |
286
286
  | Remote Servers (Workspace Utilities): a named base URL per environment for REST data sources, catalogs and AI services | ✅ | (sprint 141, AP-7) Workspace utilities → **Remote servers** ([chapter 19](guide/19-rest-data-sources.md#remote-servers)): a static id, this installation's base URL and/or an environment variable `PGKILN_SERVER_<NAME>` that wins when set, and a default web credential. REST data sources (a server and a path), REST source catalogs and AI services name a server, so changing it moves every source at once; the resolved URL passes the allow-list, the workspace's network access list (which shows each server's host) and the address checks. In the workspace export (an existing server keeps its local URL) |
287
287
  | Static Workspace Files (`#WORKSPACE_FILES#`), workspace-level Web Credentials | ✅ | (sprint 141, AP-7) Workspace utilities → **Static workspace files**: CSS, JavaScript, images and fonts with the static application files' types (no HTML), size limit and headers, served to each application of the workspace at `/a/<alias>/workspace-files/<name>`, loaded with `#WORKSPACE_FILES#name` and written as `#WORKSPACE_FILES#` / `#APP_FILES#` in HTML and templates ([chapter 16](guide/16-files.md#static-workspace-files)). **Web credentials** of the workspace, used by name by its applications (an application's own of the same name wins); secrets encrypted, write-only, never exported. Both in the workspace export |
288
- | Remote database regions (REST Enabled SQL), database links | ➖ | Not built: regions on another database were left out of sprint 141. `postgres_fdw` or `dblink` bring another PostgreSQL database's tables into the application's own |
288
+ | Remote database regions (REST Enabled SQL), database links | ✅ | (sprint 150, AP-7 leftover) Workspace utilities → **Remote databases** ([chapter 3](guide/03-builder.md#remote-databases)), administrators: another PostgreSQL database's tables (all of a schema, or the ones named) as `postgres_fdw` foreign tables in a local schema of their own, granted (read only, or also INSERT / UPDATE / DELETE) to chosen application roles; regions, reports, forms, grids and lists of values use them like the application's own tables, as its role in its transaction. The password lives only in PostgreSQL's user mapping; *Test the connection* imports in a transaction that is rolled back; *Import again* picks up remote changes. Other databases than PostgreSQL: their own foreign data wrapper (e.g. `oracle_fdw`, `mysql_fdw`) by hand |
289
289
  | E-mail: `APEX_MAIL`, the Send E-Mail process, e-mail templates | ✅ | (sprint 50) `meta.send_mail`, `meta.send_mail_template`, `meta.add_mail_attachment` and `meta.mail_status`, queued in the caller's transaction and sent by the server after the commit with retries; the **send_email** process; Shared Components → **E-mail templates** (`#NAME#` escaped in HTML, `#NAME!RAW#`; exported). Further than APEX (SMTP with a password only, through `UTL_SMTP`): **mail services** for SMTP with a password or **OAuth2** (XOAUTH2, e.g. Exchange Online after the end of basic authentication), **Microsoft 365 through Graph**, **Amazon SES**, **Resend, Postmark, SendGrid and Mailgun**, or log only; encrypted write-only secrets, allowed senders, a service, From address and daily limit per application, a mail log with retry and cancel ([chapter 6](guide/06-processing.md#sending-e-mail)). No bounce or delivery webhooks, no mail in workflows other than from SQL steps |
290
290
 
291
291
  ## Workflow, automation and AI
@@ -462,7 +462,7 @@ Sources: [APEX 26.2 new features](https://docs.oracle.com/en/database/oracle/ape
462
462
  | Progressive Web App | Settings → Progressive Web App |
463
463
  | Static Application Files, Static Workspace Files | Static Application Files; Static workspace files in Workspace utilities (sprint 141) |
464
464
  | Report Layouts, Report Queries | The same names (Files and Reports, sprint 82): a report query is one query printed as PDF with a report layout, Excel, CSV, JSON, XML or HTML (`?doc=NAME`, document buttons); APEX's several queries for one layout: a document template's JSON columns |
465
- | REST Data Sources, Web Credentials, REST Enabled SQL, Data Load Definitions, JSON Sources | The same names (Data Sources; JSON Sources since sprint 142); web credentials of the workspace and Remote Servers in Workspace utilities (sprint 141); REST Enabled SQL ➖ not planned (one database) |
465
+ | REST Data Sources, Web Credentials, REST Enabled SQL, Data Load Definitions, JSON Sources | The same names (Data Sources; JSON Sources since sprint 142); web credentials of the workspace and Remote Servers in Workspace utilities (sprint 141); REST Enabled SQL: Remote databases (`postgres_fdw`, sprint 150) |
466
466
  | Workflows, Task Definitions, Automations | The same names |
467
467
  | Text Messages, Translate, Dynamic Translations, Globalization Attributes | Translations and Text Messages, Dynamic Translations, Settings → Globalization |
468
468
  | Map Backgrounds | ➖ Not planned per application: the installation's map tile server (`MAP_TILE_URL`) is every map's background |
@@ -385,6 +385,38 @@ another workspace's file is never served to an application, its servers and cred
385
385
  one). Secrets are encrypted with `PGKILN_SECRET_KEY`, write-only, never exported and never readable by the runtime
386
386
  role; `pgkiln admin rotate-key` and the lockout checks include them.
387
387
 
388
+ ### Remote databases
389
+
390
+ (sprint 150; APEX: *REST Enabled SQL*, regions on another database) Workspace utilities → **Remote databases**
391
+ (`/builder/remote-databases`, administrators): another PostgreSQL database whose tables the applications query as if
392
+ they were their own. pgkiln uses PostgreSQL's [`postgres_fdw`](15-extensions.md): a superuser runs `create extension
393
+ postgres_fdw` once (the page offers it when pgkiln's owner connection is a superuser) and, when the owner role is not
394
+ one, `grant usage on foreign data wrapper postgres_fdw to` it.
395
+
396
+ A remote database has a **name** (a static id, `CRM`), the **host**, **port** and **database** as the *database
397
+ server* reaches them (it makes the connection, not pgkiln), the remote **user** and **password**, the **remote schema**
398
+ (`public`), a new **local schema** (`crm`), the **tables** to import (comma separated; empty: every table and view of
399
+ the remote schema) and the **application database roles** to grant them to, read only or also INSERT, UPDATE and
400
+ DELETE. *Add and import* makes, in one transaction:
401
+
402
+ - a foreign server `pgkiln_rdb_crm` with the host, port and database, and a user mapping with the user and password.
403
+ The password is kept by PostgreSQL alone (`pg_user_mapping`, which only superusers and the server's owner can read):
404
+ pgkiln never stores it, never shows it, and needs it again only to rename the remote database or move it to
405
+ another local schema;
406
+ - the local schema (marked as this remote database's by its comment: an existing schema of anything else is refused),
407
+ with the remote tables as foreign tables (`import foreign schema … limit to (…)`);
408
+ - the grants: USAGE on the schema and SELECT (and INSERT, UPDATE, DELETE) on its tables to the chosen roles, and to
409
+ nobody else.
410
+
411
+ Regions, reports, forms, grids, lists of values and processes then use `crm.customers` like any table, as the
412
+ application's role in its transaction; what the remote user may read or change on the other side is what they may.
413
+ **Test the connection** does the same in a transaction that is rolled back (a wrong password or host says so, and
414
+ nothing stays). **Import again** drops the foreign tables and imports them again (new tables or columns on the remote
415
+ side; a view of yours on one of them stops it and says which). **Delete** drops the local schema with its foreign
416
+ tables and the server. Remote databases are installation data: they are not exported with an application (the
417
+ foreign tables are database objects, like the application's own tables). For other databases, a foreign data wrapper
418
+ of their own (`oracle_fdw`, `mysql_fdw`, `tds_fdw`) works the same way, set up by hand.
419
+
388
420
  ### Isolated workspaces
389
421
 
390
422
  On a workspace's page an administrator chooses **Isolate this workspace** (Workspace utilities → Workspaces → the
@@ -1616,6 +1648,11 @@ Database code (views, functions, RLS policies) isn't part of the application, so
1616
1648
  when it writes data (hidden items never take posted values, so the URL is the way to set them); the installation's
1617
1649
  session idle time above 120 minutes or session length above 24 hours is a warning; and, as before, administrators
1618
1650
  who sign in with only a password.
1651
+ - **JSON sources** (sprint 146): each [JSON source](19-rest-data-sources.md#json-sources-and-document-views)'s views against its data
1652
+ profile, as the catalog has them. A view that doesn't exist is an error (pages on it fail); a view the source didn't
1653
+ make (no `json_source_write` trigger), a column the profile has and the view lacks (or the other way round), a
1654
+ column of another type, or a path, read-only flag or key the view writes back differently is a warning: *Create
1655
+ views* (or *Make the views again*) makes them from the profile.
1619
1656
  - **PL/pgSQL functions:** when the `plpgsql_check` extension is installed, the functions in the
1620
1657
  schemas the application's role can use are checked with `plpgsql_check_function_tb` (see
1621
1658
  [extensions](15-extensions.md)).
@@ -1424,8 +1424,14 @@ decides who may use the region; tools may also be PL/pgSQL functions, JavaScript
1424
1424
  pages), or the developer gives the region a system prompt and, optionally,
1425
1425
  **context queries** and **tools**; the model then answers questions about the application's data,
1426
1426
  calling the tools when it needs to, like an agent. It works without JavaScript (the message is
1427
- posted and the page comes back with the answer); with JavaScript the Send button shows that the
1428
- assistant is thinking and Ctrl+Enter sends.
1427
+ posted and the page comes back with the answer); with JavaScript the answer **streams** (sprint 148): the
1428
+ message appears in the conversation, the answer is written into it as the model produces it (as plain text), the
1429
+ tool being used is named under it, and when the answer is complete the page loads with it formatted, with its links
1430
+ and the agent's browser actions. Ctrl+Enter sends. Streaming uses server-sent events (`Accept: text/event-stream` on
1431
+ the same Send URL: `text` pieces as JSON strings, `tool` names, then `done` with the page to load); a proxy in front of
1432
+ pgkiln must not buffer the response (pgkiln sends `X-Accel-Buffering: no` for nginx). OpenAI, Gemini and
1433
+ OpenAI-compatible services are asked to stream with their usage; an endpoint that refuses streaming (HTTP 400) gets
1434
+ the ordinary request once.
1429
1435
 
1430
1436
  - **Conversations** are kept per session and region (`meta.ai_conversation`): a follow-up question
1431
1437
  sends the earlier messages along. *New conversation* starts over; signing out (or the session's
@@ -1212,10 +1212,21 @@ they wait for and their wait, logged in each instance's history (*migrated*, `ve
1212
1212
  - a step without a mapping, or mapped to a step the version doesn't have (or a draft);
1213
1213
  - an instance waiting for a task must go to a task step that creates a task of the same definition;
1214
1214
  one at a `wait` step to a `wait` step (its wait goes on), one at a join to a join;
1215
- - an instance inside parallel branches, or calling a web service at that moment: try again later.
1215
+ - an instance calling a web service at that moment: try again later.
1216
+
1217
+ **Inside parallel branches** (sprint 149, migration 144) an instance is at several steps at once: its main path
1218
+ waits at the join, and each open branch (active, waiting or faulted) is at a step of its own. The page lists those
1219
+ steps with the instance (*branches at A, B*) and asks a mapping for each; the preview has a row per path (*main*,
1220
+ *branch A*), and the instance moves only as a whole. Each branch follows the rules above, and the join it ends at
1221
+ must map to a join step of the new version (a branch can't be mapped onto its own join). The branches' rows then name
1222
+ the new join and the parallel step that splits there (the mapped one, else the one parallel step of the new version
1223
+ that joins at that join), so the join counts them as before, done branches included; each moved branch has its own
1224
+ *migrated* event (`version 1 → 2: branch A: A → A2 (by admin)`). A branch the new version adds to a parallel step does
1225
+ not start for an instance already past its split.
1216
1226
 
1217
1227
  The database function is `meta.migrate_workflows(definition_id, version, ids, mapping, apply, by)` (the owner's,
1218
- for the builder and scripts; not for applications).
1228
+ for the builder and scripts; not for applications): one row per path, with the column `branch` (null for the main
1229
+ path).
1219
1230
 
1220
1231
  <a id="diagram-export"></a>**The diagram as a file.** Under the diagram, **Download SVG** downloads the whole model
1221
1232
  of the version shown (`/builder/apps/<app>/shared/workflow_definition/<id>/diagram.svg?v=<version>`), a standalone
@@ -22,7 +22,7 @@ setup`) and on practically every managed service. Install with `create extension
22
22
  | **pg_stat_statements** | Which SQL is slow or called most, per role, so per app (`db_role`) | Monitor Activity → Top SQL; SQL Workshop → SQL Monitor (Top SQL, a statement's totals) |
23
23
  | **tablefunc** | `crosstab()` for pivot tables | Interactive report *Pivot* |
24
24
  | **ltree** | Hierarchies (org charts, categories, menus) with fast subtree queries | Tree region, `CONNECT BY` |
25
- | **postgres_fdw**, **file_fdw** | Query another PostgreSQL database, or a CSV file, as if it were a table | Remote servers / database links |
25
+ | **postgres_fdw**, **file_fdw** | Query another PostgreSQL database, or a CSV file, as if it were a table; Workspace utilities → [Remote databases](03-builder.md#remote-databases) sets postgres_fdw up (sprint 150) | REST Enabled SQL / database links |
26
26
  | **dblink** | Run a statement on a separate connection, the usual stand-in for Oracle's **autonomous transactions** (e.g. error logging that survives a rollback) | `PRAGMA AUTONOMOUS_TRANSACTION` |
27
27
  | **amcheck**, **pg_buffercache** | Integrity checks and cache insight for DBAs | |
28
28
 
@@ -44,7 +44,7 @@ any (see [what is not exported](03-builder.md#export-format)).
44
44
  | `pgkiln export <alias> [--format json\|dir\|text] [--out <path>]` | `json` (default): the `pgkiln/2` document with sorted keys, to `--out` or standard output. `dir`: a directory (default `./<alias>`), see below. `text`: the same directory in YAML with the code inline ([text files](#text-files-apexlang)) |
45
45
  | `pgkiln import <path> [--alias <alias>] [--replace [--only <file>]…] [--check [--force] \| --dry-run]` | Imports a JSON export, an application directory or a `.zip` of one. `--alias` gives the copy another alias. `--replace` updates the application with that alias in place (after a [backup](03-builder.md#backups)); with `--only pages/12` (repeatable) only that page or component file ([below](#importing-one-page-or-component)). `--check` checks the application before it commits, `--dry-run` only checks ([below](#checking-before-an-import)) |
46
46
  | `pgkiln diff <alias> <path> [--name-only \| --quiet]` | What differs between the application in the database and a directory (or JSON file, or zip) |
47
- | `pgkiln advise <path\|alias> [--format text\|json\|sarif] [--fail-on error\|warning\|info\|never] [-o <file>] [--base <dir>]` | (0.77) The [Advisor](03-builder.md#advisor) for CI: an export is imported into a transaction that is always rolled back and checked there; an alias checks the application in the database. SARIF points each finding at its file, so pull requests get annotations. Exit code 1 from `--fail-on` (default `error`) ([below](#pgkiln-advise-in-ci)) |
47
+ | `pgkiln advise <path\|alias> [--offline] [--format text\|json\|sarif] [--fail-on error\|warning\|info\|never] [-o <file>] [--base <dir>]` | (0.77) The [Advisor](03-builder.md#advisor) for CI: an export is imported into a transaction that is always rolled back and checked there; an alias checks the application in the database. `--offline` checks an export's files without a database. SARIF points each finding at its file, so pull requests get annotations. Exit code 1 from `--fail-on` (default `error`) ([below](#pgkiln-advise-in-ci)) |
48
48
  | `pgkiln working-copy list\|create\|compare\|merge\|refresh\|delete <alias> [<name>] [--prefer copy\|main] [--take <component>]… [--as <developer>]` | (0.77) [Working copies](03-builder.md#working-copies) from the command line ([below](#working-copies-and-locks)) |
49
49
  | `pgkiln lock <alias> [--page <n>] [--note <text>]` / `pgkiln unlock <alias> [--page <n>] [--force]` | (0.77) The builder's application and page locks; another developer's lock is broken only with `--force` (logged) |
50
50
  | `pgkiln ddl <schema> [--no-comments] [--no-grants] [--out <file>]` | The DDL of a schema's objects, in an order that runs (as SQL Workshop → DDL, [chapter 3](03-builder.md#sql-workshop)) |
@@ -315,10 +315,27 @@ jobs:
315
315
  with: { sarif_file: advise.sarif }
316
316
  ```
317
317
 
318
+ **Without a database** (sprint 147): `pgkiln advise <path> --offline` reads the export's files and runs the checks that
319
+ need no database: references between components (pages, items, lists of values, authorization schemes, build options,
320
+ report layouts, regions, workflow definitions and steps, processes in chains), the login page and page groups, the
321
+ pages' security defaults (writing without sign-in or a scheme, unrestricted protection), process settings and JSON
322
+ source profiles. It never connects (`DATABASE_URL` may be unset), so it fits a quick step before the full check, or a
323
+ repository without a database in CI:
324
+
325
+ ```yaml
326
+ - run: npx pgkiln advise apps/sales --offline --format sarif -o advise.sarif
327
+ ```
328
+
329
+ Offline, SQL is not planned (it needs the application's tables and role), nothing is read from the catalog (vector and
330
+ full-text columns, JSON source views, `plpgsql_check`), and the workspace's remote servers and credentials, branches to
331
+ other applications, the installation's session limits and the administrators' second factor are not checked. The
332
+ summary line says *checked offline*, and JSON output has `"offline": true`. The findings are the same as the full
333
+ check's for everything it does check.
334
+
318
335
  | Format | What it gives |
319
336
  |---|---|
320
337
  | `text` (default) | one finding per line with its file under it, and a summary line |
321
- | `json` | `{ alias, checked, counts: { error, warning, info }, findings: [{ severity, where, field, message, page, kind, file }] }` |
338
+ | `json` | `{ alias, checked, offline, counts: { error, warning, info }, findings: [{ severity, where, field, message, page, kind, file }] }` |
322
339
  | `sarif` | SARIF 2.1.0: a result per finding with its level (error, warning, note), a stable rule id (`pgkiln/region/source`) and the file of its page or component in the export (`apps/sales/pages/0002-orders/regions/0010-order-list.yaml`), so GitHub code scanning annotates the pull request |
323
340
 
324
341
  The paths are relative to the current directory. With an alias there is no directory: `--base apps/sales` names
@@ -385,7 +385,8 @@ Shared Components → Data Sources → **JSON Sources** → *Add JSON source*:
385
385
  **Create views** (the source's page) makes them in one transaction with your SQL Workshop connection and records
386
386
  the statements in the [Change Log](03-builder.md#change-log); *Open in the SQL Worksheet* shows them first. After
387
387
  changing the profile, *Make the views again* drops and makes them (a view other objects depend on can't be
388
- dropped: the error says which). The views are ordinary database objects of your application, like the table:
388
+ dropped: the error says which). The [Advisor](03-builder.md#advisor) names a source whose views no longer match
389
+ its profile, e.g. after a column was added to the profile but the views weren't made again. The views are ordinary database objects of your application, like the table:
389
390
  put the statements in your own migration scripts for the other environments (the source itself travels with the
390
391
  application's export as `json_sources`).
391
392
 
@@ -75,7 +75,7 @@ directory the agent started the server in (the project).
75
75
  | `recent_errors` | the latest errors and refused requests from the activity log | no |
76
76
  | `export_app` | writes an application to a directory (default `apps/<alias>`, format `text`) | files on disk |
77
77
  | `diff_app` | what an import of a directory would change (A/D/M with unified diffs); also reports files it can't read | no |
78
- | `advise_app` | (0.77) the Advisor on an application or an export (imported and rolled back): SQL planned as the application's role, references, security checks, each finding with its file | no |
78
+ | `advise_app` | (0.77) the Advisor on an application or an export (imported and rolled back): SQL planned as the application's role, references, security checks, each finding with its file; `offline: true` with a `path` checks the files without the database (0.79) | no |
79
79
  | `working_copy` | (0.77) `list`, `create`, `compare`, `merge`, `refresh` or `delete` working copies; conflicts need `prefer` (copy or main) or `take` (component ids); a merge is refused while another developer has a lock on it | the database |
80
80
  | `lock_app` | (0.77) locks an application or a page (`unlock: true` removes it; another developer's lock only with `force: true`, logged) | the database |
81
81
  | `import_app` | imports a directory, zip or JSON file; `replace: true` updates the application in place. It checks the application first (the Advisor, in the import's transaction): errors refuse the import and are listed; `force: true` imports anyway, `dry_run: true` only checks | the database |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgkiln",
3
- "version": "0.78.0",
3
+ "version": "0.80.0",
4
4
  "description": "Open source low-code, SQL-driven application builder for PostgreSQL, inspired by Oracle APEX",
5
5
  "keywords": [
6
6
  "postgresql",
package/public/app.css CHANGED
@@ -1877,6 +1877,8 @@ td.to-col-center, th.to-col-center { text-align: center; }
1877
1877
  .assistant-text p, .assistant-text ul, .assistant-text ol { margin: 0 0 0.4rem; }
1878
1878
  .assistant-text > :last-child { margin-bottom: 0; }
1879
1879
  .assistant-text ul, .assistant-text ol { padding-left: 1.25rem; }
1880
+ /* (sprint 148) an answer while it streams: plain text, its line breaks kept, until the page shows it formatted */
1881
+ .assistant-text .assistant-streaming { white-space: pre-wrap; overflow-wrap: anywhere; }
1880
1882
  .assistant-tools { display: block; margin-top: 0.25rem; }
1881
1883
  .assistant-input textarea { width: 100%; box-sizing: border-box; }
1882
1884
  .assistant-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.4rem 0; }