PRDCT-692: make the Apps section survive the launch — OIDC entry, the Google console as it is, two build paths - #1139
Conversation
Michal's 40-minute run through the Google tab, checked against Google's own docs, turned up one wrong claim and a row of snags: - Testing does not gate sign-in for Keboola apps. The proxy requests only openid, email and profile (oauth2-proxy default; keboola-as-code sets no scope), and Google exempts exactly those scopes from the test-user list. The page said the opposite. Now: Internal limits sign-in to the org, External lets any Google account in, publishing is irrelevant. - Step 1 starts from an existing app, however it was built; Kai keeps the OIDC settings on later changes (MCP authentication_type=default). - Direct links to the Google Auth Platform pages; both states of the consent screen (Get started vs already configured); the exact redirect URI field with a filled-in example; the error headline Google actually shows and where Request details lives; the encrypted KBC::ProjectSecureGKMS:: value after Save; Start App vs Redeploy App; test in a private window. - Admin-rights prerequisite up front; Kai and kbagent cannot do this part. - "You now have" checkpoints on every provider tab. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Deliverables 3, 4 and 5 of the Apps GA docs review, text first (screenshots follow the 25 Sep UI freeze): - What are Keboola apps: a "Two ways to run an app" section that explains the managed-repository-with-Kai path against your-own-repository, with a comparison table. Its anchor is the target for the "learn more" link the Builder will show on non-managed-git apps (AJDA-3319). - New page Operate and update an app: reading the state, shipping a change on either path, changing settings and why a redeploy is needed, sleep vs stop, the encrypted secret value, versions, copy/automate/delete. - New page Troubleshooting: where the evidence is (job log, Terminal Logs, kbagent runs/logs, Kai), start failures led by the missing keboola-config folder (AJDA-3334), runtime misbehaviour, sign-in, sleeping. - Overview links the two-paths section; both new pages sit under Run & share in the nav. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Drop the unverified claim that Kai preserves the OIDC settings; only the MCP server's default path is known to. - Show the Overview-tab screenshot that actually has the tab bar and the App URL block in view. - Publishing gates the app name as well as the logo. - The propagation note covers audience changes again, not only the redirect URI. - The fresh-window advice names the real reason: the proxy's own session cookie, not a skipped Google sign-in (the proxy sends prompt=select_account). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e what each build path needs Three gaps left after the Google-tab and two-paths work, all from the launch call: a reader must know whether a hard path is even theirs before they start, and third-party steps are ours to keep correct. * The OIDC section opens with the question instead of the procedure. Only company-account sign-in justifies it; password, GitHub, GitLab and JumpCloud need nothing outside Keboola. OIDC is the only method that needs admin rights in someone else's console, and the note says so. * Each provider tab now carries the date its console steps were last walked through: 2026-09-22 for Google, 2026-09-14 for Entra ID, Okta and Auth0, with a warning on the three older ones that menu names drift. Honest dates, not a blanket claim. * "Two ways to build" says what each path costs before the reader picks: a project and nothing else for Kai, a Git account and about half an hour the first time for the local path. Build clean, 369 pages, broken internal links 0, missing images 0. The four Google console deep links added earlier all resolve. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…gainst my own note Cold-read of the OIDC path found no blocker but six majors. Five are fixed here; the sixth needs a console. * **The entry note was wrong.** It claimed OIDC is the only method needing admin rights outside Keboola. GitHub sends you to Developer Settings, GitLab to Settings > Applications, JumpCloud to its Admin Console. A reader taking the note at face value would pick GitHub to dodge "the hard one" and spend the same effort. Now: Basic is the only method needing nothing outside Keboola; the other three need an OAuth app but no consent screen and no audience decision. * **Step 1 invited the page's own most common failure.** It said "copy its callback URL", but the copy button in the App URL block yields the app URL. Copy, paste into Authorized redirect URIs, and you get the redirect_uri_mismatch this page lists first. The step now names the button, says what it gives you, and says to append /_proxy/callback. * **Google SSO cannot restrict below the whole audience.** Entra has assignment, Okta has assignments, Google has neither, and the page did not admit it. Someone could ship an internal-finance app to all 800 people in the org believing it was scoped. Stated in the Google tab, with the alternatives. * **The negative test had no pass signature.** A blocked outside account looks like a fault, and the page's only nearby lever was "switch to External" — which turns a correctly closed app into a public one. Both signatures are now spelled out, with the trap called out. * **One URL, two placeholder vocabularies.** GitHub, GitLab and JumpCloud used `<dataAppId>` three times before it was defined at the bottom, and it does not mean the App ID the screenshot shows. All call sites now use Step 1's spelling. * Time estimate was "a few minutes" against a measured 40; now about 15, longer with no consent screen. The scopes the Internal/External decision rests on are named (openid, email, profile). Left for a human: whether Google shows **Authorized domains** on an Internal-audience project. Hedged in the step and flagged TODO(human-review) in an MDX comment, which does not ship to the built HTML (verified: 0 occurrences in dist). Build clean, 369 pages, broken internal links 0, missing images 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Walked the whole Google tab against a real Google Cloud project (keboola-docs-test) and a real app in project 264. What the run changed: - The central claim is now proven, not inferred: the sign-in request the proxy sends carries scope=openid+email+profile, and an External app in Testing status with an empty test-user list let the account straight in. Google's own Audience page says the opposite, so the guide now names that text and says it does not apply here. - Authorized domains are no longer a prerequisite: the client form states that domains from the redirect URI are added to the consent screen automatically. That step is now optional. - The Get started branch was wrong: Branding, Audience and Clients are in the left menu even on an unconfigured project, so they cannot be the signal. The content area is. - The Audience page shows publishing status, user cap and test users only for an External app. - The secret field is masked after saving; the encrypted KBC::ProjectSecureGKMS:: value appears only behind the eye icon. - The deploy wizard asks for three things, not two. - The consent screen appears on first sign-in for Internal apps too, and the app page can still read stopped until reloaded. - Added /_proxy/sign_out as the way to end the app session between tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Seen on a real app in project 264 while cleaning up after the OIDC run: the menu reads Suspend app, Copy app, Automate, Debug mode, Delete app, and suspending asks for confirmation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Google tab said the revealed secret starts with KBC::ProjectSecureGKMS::. That prefix is GCP-only: extend/encryption documents KBC::ProjectSecureKV:: on Azure and KBC::ProjectSecure:: on AWS, and the three are not interchangeable. A reader on an AWS stack who didn't see the documented string had no way to tell whether the save had worked. Name the common stem and link the encryption page instead. Found by the fact-checker agent while reviewing the wave-2 Apps pages, which carried the same sentence. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both agents ran over the three new pages. Three things they found were wrong rather than unclear: - The cipher prefix KBC::ProjectSecureGKMS:: is GCP-only. Name the common stem and link extend/encryption, so a reader on AWS or Azure can still tell the save worked. - "Every app runs from a Git repository" is false for Streamlit, which the same page keeps in scope four lines earlier. Say so. - A Keboola-managed repository does not require Kai: kbagent data-app create --use-managed-git-repo provisions the same repo empty. The table's "Who writes the code" row had ruled that combination out. The rest were reachability and accuracy: - Two ways to run an app now answers "why is my builder missing" in its first two lines, because that is the question AJDA-3319 will send readers here with, and says the choice is made at creation. - validate-repo is printed with its required --git-repo, and the contract links carry the app-building skill's reference alongside build-locally, which only gains the contract when #1128 lands. - Redeploy no longer claims a gapless swap; the MCP server says the app may report stopped while it restarts. - Versions gains the way back: an app is a component configuration, so rollback works, and a redeploy puts the old settings in service. - Dropped the unsourced App Info "owner" field and the unverified suspend confirmation; settled the backend-size contradiction (wizard, not page); added the Storage Access failure row, the GitHub/GitLab/ JumpCloud sign-in pointer, and terminal equivalents for each task. - Operate and Troubleshooting were orphans: publish-and-share now points at them, as do index and the end of getting-started. - The deploy wizard asks three things, not two (seen live 22.09), so getting-started says three. Its screenshot still shows two and needs reshooting after the UI freeze. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The re-check caught three things I introduced yesterday and today: - "Every task here can also be done from a terminal with kbagent" is false, and the same commit added the counterexample. There is no rollback, copy, debug-mode or draft command in the CLI reference. Say which tasks have a terminal equivalent and which don't. - App Info does have an owner field. The committed screenshot shows Backend Version, Backend Size, Auto Sleep, Last Change, Owner, App ID. Restored, with Last Change. - Suspend app isn't in the ⋯ menu screenshot, which shows a stopped app. The menu is state-dependent, so say that rather than propagating a five-item list onto a page whose picture shows four. And three that were already wrong on main: - The deploy wizard screenshot has shown three fields all along. Four places described two. getting-started's alt text, publish-and-share and reference now match the picture, so nothing needs reshooting here. - reference.md's App actions listed five of the eight actions, in casing the UI doesn't use, and claimed a suspended app's URL is no longer available while the CLI says stop preserves it. Rewritten to the current labels, with the contested URL claim dropped from both pages rather than asserted on one. - The Storage Access row needed the project-level feature toggle, which comes before the per-app setting. Also dropped an unsupported generalization about GitHub, GitLab and JumpCloud sign-in failures, replaced with the restriction fields each provider actually has. JumpCloud has only allowed roles, so the original sentence didn't even fit the provider it was attached to. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
#1138 kept moving after this branch forked from it: 0addba2 carries corrections from a live Google run, and 3d97aec stops naming a GCP-only cipher prefix as the one every reader sees. One conflict, in the consent-screen steps, resolved toward #1138 because its side came from the live run and settles the question this branch was carrying as a TODO: Authorized domains is optional, since Google adds the domain itself when you save the redirect URI. The TODO(human-review) is dropped with it. Their side also names the exact empty-state string ("Google Auth Platform not configured yet") and what Internal vs External actually shows on the Audience page. Everything this branch adds survived: the "Do you actually need OIDC?" note, the per-tab verification dates, the copy-button fix in Step 1, the missing group-filter caveat for Google, the expected-rejection signature, and the single placeholder vocabulary (dataAppId is gone from the page). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
These three were written from vendor documentation in September and have never been run against a live tenant. A documentation pass found one critical gap and several things that would cost a reader time. Okta, the critical one: on an Integrator Free Plan org the `default` authorization server ships without an access policy, so every token request fails until you add one, and nothing in our troubleshooting list matched that symptom. Also, the menu parenthetical was backwards (Applications and Resources is the Identity Engine label, Applications > Applications is Classic), the wizard may ask which experience to use, and `/login/signout` is not an endpoint Okta documents anywhere. The logout guidance now uses the end_session_endpoint from discovery, and step 4 no longer tells readers to delete the Sign-out redirect URI that the logout flow needs. The org authorization server is presented as Okta's own recommendation for plain SSO rather than as a fallback, because custom authorization servers need a paid add-on. Entra: the assignment flow stopped one click short of Assign, so nothing was saved. And testing the restriction as a Global Administrator gives a false pass, because the requirement does not apply to them, which is exactly the account a reader is likely signed in as. The role sentence named a floor where Microsoft documents alternatives. The claim most suspected of being stale, P1 or P2 for group assignment, turned out to be current and is unchanged. Auth0: a post-logout redirect has to be registered under Allowed Logout URLs or Auth0 refuses it, which we never mentioned. And the instruction to copy the issuer from discovery broke for custom-domain tenants, who have two domains and would have copied the wrong one. Discovery is now the primary instruction rather than the hedge; the trailing slash was confirmed against two real discovery documents. Still unverified and waiting on live runs: Okta's two error strings, which Okta does not publish, and whether either redirect-URI field arrives prefilled. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
| 1. In your Keboola project, open **Apps**, click **+ Create App**, and [create the app manually](/data-apps/getting-started/#create-an-app-manually). The app opens on its configuration page. (Adding sign-in to an existing app? Open its configuration instead.) | ||
| 2. Scroll to the **App URL** block. It shows the app's host as a URL prefix plus a generated part, for example `toy-store-sales` and `-74016144.hub.europe-west3.gcp.keboola.com`. Your callback URL is `https://`, that whole host, and `/_proxy/callback`: | ||
| 1. In your Keboola project, open **Apps** and click the app. It doesn't matter whether Kai built it or you created it yourself. No app yet? [Create one manually](/data-apps/getting-started/#create-an-app-manually) first; it opens on its configuration page. | ||
| 2. On the app's **Overview** tab, scroll to the **App URL** block. It shows the app's host as a URL prefix plus a generated part, for example `toy-store-sales` and `-74016144.hub.europe-west3.gcp.keboola.com`. Click the block's copy button — it gives you the app's URL, **not** the callback URL. Paste it where you need it and add `/_proxy/callback` to the end: |
There was a problem hiding this comment.
Just reading this it reminded me how much I hate that I need to manually append some stupid url path. It should be in the UI in the first place. So let's change it to this https://github.com/keboola/ui/pull/9112
There was a problem hiding this comment.
Done in c26a01e, and you found more than you were aiming at.
Step 1 now sends people to the Callback URL field first, and the GitHub, GitLab and JumpCloud steps no longer say "the whole host from the App URL block plus /_proxy/callback" either. Manual construction stays underneath as a "no such field?" fallback, since ui#9112 has not shipped everywhere yet and this page has to work on both sides of that.
Two things came out of your issue that the page was getting wrong on its own:
- An app created without a URL prefix has no hyphenated part, so its callback URL is
https://<app-id>.hub.<stack-host>/_proxy/callback. No version of this page had ever mentioned that. - The Callback URL format section ended mid-sentence on an open parenthesis.
mainhas the complete text, so it was lost in one of this branch's merges. Restored.
That was the last unticked box on UT-5646.
David's review makes the same point his Linear issue does: nobody should be reconstructing a URL path by hand. keboola/ui#9112 adds a read-only Callback URL with a copy button under Authentication, for OIDC, GitHub, GitLab and JumpCloud. Step 1 now sends readers there first, and the four provider sections that used to say "the whole host from the App URL block plus /_proxy/callback" now say to copy the field. Manual construction stays as the fallback, phrased as "no such field?", because the UI change has not shipped everywhere yet and the page has to work on both. It also now covers an app created without a URL prefix, whose callback URL has no hyphenated part at all. That case came out of UT-5646's acceptance criteria and was missing from every version of this page. Separately, the Callback URL format section ended mid-sentence, on an open parenthesis, where main has the complete text. Restored and extended with the no-prefix form. Closes the last unticked box on UT-5646. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The step already pointed at the Callback URL field, but the reference section at the bottom still opened with the hand-assembled format and mentioned the field only in its last line. That is the same order David objected to: manual work first, the easy way as an afterthought. Turned round. The section now opens with "copy it from the field", says why copying beats typing (one wrong character reads as a redirect mismatch, not as a typo, which is exactly how the usability test ended), and keeps the format for reading a URL you already have or for a stack where the field has not appeared yet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three links promised a repository layout contract on Build locally. Jordan asked (#1128) to refer readers to the skill files instead, so the contract stays in references/python-js-apps.md in keboola/ai-kit and the links go straight there. This PR no longer depends on #1128. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PEKnDNvPqkNrBonYN6S61r
…erate Build locally never mentions kbagent, on main or here. The kbagent data-app commands live on Operate and update an app, so the sentence points there. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PEKnDNvPqkNrBonYN6S61r
|
Pushed 8ef0962, 9dea446 (merge of
@davidesner the Generated by Claude Code |
Linear: PRDCT-692 · closes the first checkbox of PRDCT-472 (OIDC accuracy) · follows #1127
Why
Apps GA publishes on 1 October, with the docs review due 25 September (AJDA-3380). A usability test says people can't follow these pages on day one: Michal took 40 minutes on Google SSO and stalled in the Google console, looking for a Get started button that wasn't there because the project already had a consent screen. Our guide had no branch for the state he was in.
The bar from the launch call: a reader who knows nothing gets through with minimal errors in minimal time, and it's our job that they don't fail. Third-party console steps count as ours — the reader doesn't care whose side the problem is on.
This PR now carries the whole wave
It started as the launch-polish commit on top of two local branches and has since absorbed both of those branches' later work, so there is one PR for the Apps wave rather than three:
AJDA-3380-oidc-google-tab) — the Google tab rewrite, plus its two later commits: corrections from a live Google run, and a fix that stopped naming a GCP-only cipher prefix as the one every reader sees. AJDA-3380: fix the Google OIDC tab after the usability test #1138 can be closed; nothing in it is missing here.AJDA-3380-two-paths— "Two ways to run an app", the menu-label corrections, and two fact-check passes.The one merge conflict, in the consent-screen steps, was resolved toward #1138 because its side came from the live run — and it settles a question this branch had been carrying as a
TODO: Authorized domains is optional, since Google adds the domain itself when you save the redirect URI. That TODO is gone.What changed
The OIDC section now opens with the question, not the procedure. A reader learns before investing 40 minutes whether this path is even theirs: only company-account sign-in justifies OIDC; Basic (Password), GitHub, GitLab and JumpCloud need nothing outside Keboola. OIDC is the only method that needs admin rights in someone else's console, and the note says so.
The Google tab is rewritten around what the console actually shows. The missing branch is in: if the page shows Get started the project has no consent screen; if it shows Branding / Audience / Clients, it already does — carry on. Direct deep links to all four console screens (each verified to resolve). "You now have:" checkpoints so a reader can tell they're on track. Corrected External/Testing behaviour: for the scopes Keboola requests, Google does not restrict an External app to its test users, so "publish the app" is not a prerequisite — the old text sent people down that path for nothing. Testing instructions say to use a fresh private window, because the app's own session cookie makes a second try in the same window prove nothing.
Every provider tab carries the date its console steps were last walked through — 2026-09-22 for Google, 2026-09-14 for Entra ID, Okta and Auth0, with a note on those three that menu names drift. Honest per-tab dates rather than a blanket claim.
"Two ways to run an app" (
what-are-apps.md) explains the thing that actually decides how you work: where the code lives. Kai with a Keboola-managed repository gives you the live preview, drafts and Modify with Kai; your own repository gives you your editor and review process but no Kai builder. A comparison table, and everything after the code is identical on both paths.index.mdnow states what each path costs before you pick: a project and nothing else for Kai, a Git account and about half an hour the first time for the local path.Two new pages for the lifecycle the section was thin on:
operate.md(read the app's state, ship a code change, change settings, stop/start/sleep, rotate a secret, delete) andtroubleshooting.md(won't start, misbehaves, sign-in problems, sleeping and waking).Verification
npm run build && node scripts/audit-phase2.mjsnpm run buildaudit-phase2broken internal links/auth/overview,/auth/branding,/auth/audience,/auth/clients)/data-apps/operate/,/data-apps/troubleshooting/guide-tester (repo agent, cold-read)
No blocker. A first-time reader with a Keboola project and Google Cloud admin gets from the top of the page to a working Google sign-in without leaving the page or guessing a value.
Six majors, five fixed in
7cbabd24:redirect_uri_mismatchthis page lists first/_proxy/callback<dataAppId>used three times before being defined, and it isn't the App ID the screenshot showsPlus: the time estimate was "a few minutes" against a measured 40 (now about 15), and the scopes the Internal/External decision rests on are named.
The sixth needs a console, and it's the one to watch. Google's Authorized domains may be an External-audience control; if so, an Internal reader hunts for a field that isn't there — Michal's failure mode again — and the checkpoint after it is unreachable. Hedged in the step and flagged
TODO(human-review)in an MDX comment (which does not ship to the built HTML — verified, 0 occurrences indist). Someone with a console should open Branding on an Internal-audience project and either confirm the field or keep the branch.Not addressed here, worth a follow-up: there is no screenshot of the Keboola OIDC form itself, so Provider, Domain/Org URL and Issuer URL are prose-only; the encrypted-secret note (
KBC::ProjectSecureGKMS::) lives inside the Google tab although it is true for all five providers; and the Entra, Okta and Auth0 tabs lack the checkpoints and failure modes Google now has.One open item
Entra ID, Okta and Auth0 keep the 2026-09-14 date because walking those consoles needs admin rights in real tenants — a human pass, not something this PR can claim. Their structure is also thinner than Google's now: no "You now have:" checkpoints, fewer failure modes. If someone walks them before Thursday, the dates and the gaps close in one commit.
Not in this PR
Deliberately held for the follow-up, so the launch-critical changes can land on their own: the private-Git how-to (the Git Repository form field by field, PAT scopes vs deploy key), the Claude Code how-to (
dataapp-developerskill,kbagent data-app), and the usability test with Viki whose findings will drive both.🤖 Generated with Claude Code
Update, 23 Sep: this PR now carries #1138 and #1140 in full
Merge
de406ab7brought in the one commit this branch was missing. Both superseded branches are now ancestors of this head, checked withgit merge-base --is-ancestorrather than by reading diffs, so #1138 and #1140 are closed as duplicates. Their evidence is below, because it is what the claims on these pages rest on.The Google tab was run live, 22 Sep
Against real infrastructure: a Google Cloud project
keboola-docs-testin theext.keboola.comorganization, OAuth clientdocs-test-google-2026-09-22, and a throwaway Streamlit app in project 264.Test 2 is what the Internal versus External rule rests on. The sign-in URL the proxy generates carries
scope=openid+email+profilein the address bar, so Google's documented exemption for basic scopes applies by its own rule rather than by inference from the source.Seven things that run corrected: authorized domains are added from the redirect URI automatically, so Branding is optional; the "Get started" branch has to key off the content area, because Branding, Audience and Clients sit in the left menu either way; the Audience page shows publishing status, user cap and test users only for External; the secret field is masked after saving and the encrypted value hides behind the eye icon; the deploy wizard asks three things; the consent screen also appears on first sign-in for an Internal app;
/_proxy/sign_outends an app session between tests.Still from report rather than reproduction: the Request details label on Google's error page and the
redirect_uri_mismatchwording come from Michal's session, since the typo was never re-created during the run.The other three tabs were checked against the vendors' docs, 23 Sep
This supersedes the One open item section above: Entra, Okta and Auth0 no longer carry the 2026-09-14 date, and they no longer claim a console walkthrough that never happened. Each now says it was checked against the vendor's documentation on 2026-09-23 and that a live run is still outstanding. They also have the "You now have" checkpoints now.
Okta, the one that mattered. On an Integrator Free Plan org the
defaultauthorization server ships without an access policy, so every token request fails until you add one. A reader on the most common free org type would have followed the page exactly and hit a failure with nothing in the troubleshooting list matching it. Three more from the same check: the menu parenthetical was backwards, since Applications and Resources is the Identity Engine label and Applications → Applications the Classic one; the wizard may ask which experience to use; and/login/signoutis not an endpoint Okta documents anywhere, so the logout guidance now uses theend_session_endpointfrom discovery, and the sign-out redirect URI the logout flow needs is no longer thrown away.Entra. The assignment flow stopped one click short of Assign, so nothing was saved. Worse, testing the restriction while signed in as a Global Administrator gives a false pass, because the requirement does not apply to them, and that is the account a reader is likely to be using. The role sentence named a floor where Microsoft documents alternatives. The claim most suspected of being stale, P1 or P2 for group assignment, is still current and unchanged.
Auth0. A post-logout redirect has to be registered under Allowed Logout URLs or Auth0 refuses it, which the page never mentioned. And copying the issuer from discovery broke for custom-domain tenants, who have two domains and would have copied the wrong one. Discovery is now the primary instruction, and the trailing slash was confirmed against two real discovery documents rather than prose.
The encrypted-secret note is also fixed rather than just relocated:
KBC::ProjectSecureGKMS::is the GCP prefix only, and naming it as the one every reader sees left anyone on AWS or Azure unable to tell whether the save had worked.Merge order
This PR no longer depends on #1128 (24 Sep). The three links that promised a repository layout contract, two in the troubleshooting table and one in the two-paths section, now go straight to the app-building skill's
references/python-js-apps.mdinkeboola/ai-kit, where Jordan asked on #1128 that the contract stay. A small follow-up PR will cut Build locally down the same way and supersede #1128; it merges after this one.What a live run still owes us
Okta's two error strings, which Okta publishes nowhere, and whether either Okta redirect-URI field arrives prefilled. Tenants for Entra, Okta and Auth0 are being set up for exactly this.