diff --git a/_data/navigation.yml b/_data/navigation.yml index a9e37f969..09c43c718 100644 --- a/_data/navigation.yml +++ b/_data/navigation.yml @@ -127,6 +127,10 @@ items: title: Authentication - url: /data-apps/publish-and-share/ title: Publish and share + - url: /data-apps/operate/ + title: Operate and update + - url: /data-apps/troubleshooting/ + title: Troubleshooting - url: /data-apps/reference/ title: Reference - url: /data-apps/streamlit/ diff --git a/src/content/docs/data-apps/authentication.mdx b/src/content/docs/data-apps/authentication.mdx index 321087119..0805b39e0 100644 --- a/src/content/docs/data-apps/authentication.mdx +++ b/src/content/docs/data-apps/authentication.mdx @@ -37,18 +37,24 @@ Once an app is deployed, its URL is publicly available. Protect it so only the r ## OIDC (single sign-on) +:::note[Do you actually need OIDC?] +Only set this up if people must sign in with their **company accounts** — so that access follows your directory, and someone who leaves the company loses it. **Basic (Password)** is the only method that needs nothing outside Keboola: it shares one password and you're done. **GitHub**, **GitLab** and **JumpCloud** also restrict access by organization or team, and they still need an OAuth app in that provider's console, but no consent screen and no audience decision — noticeably less work than OIDC. +::: + OIDC lets users log into your app through your single sign-on (SSO) provider. Keboola has ready-made provider options for Google (**Google SSO**), Microsoft Entra ID (**Azure OIDC**), **Okta**, and **Auth0**, plus **Generic OIDC** for any other OpenID Connect provider. Users sign in with the provider you configured; if an app has more than one provider, they first pick an **Authentication Provider**. ![The app's sign-in page asking the user to select an authentication provider, one button per configured provider](/data-apps/auth-select-oidc-provider.png) -The flow is the same everywhere: create the app in Keboola, register it with your provider using the app's callback URL, paste the provider's credentials into the app's **Authentication** settings, and deploy. +The flow is the same everywhere: open the app in Keboola, register it with your provider using the app's callback URL, paste the provider's credentials into the app's **Authentication** settings, and deploy. Expect about 15 minutes of clicking in two browser tabs, and longer the first time in a Google Cloud project that has no consent screen yet. It needs admin rights in the provider's console: for Google, the **Owner** or **OAuth Config Editor** role on a Google Cloud project; for the others, the right to register applications in your tenant. Kai and kbagent can't do this part for you. + +### Step 1 — Open the app and copy its callback URL -### Step 1 — Create the app and copy its callback URL +Your provider needs the app's callback URL, so start in Keboola. -Your provider needs the app's callback URL, so create the app first. +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. Under **Authentication**, find the read-only **Callback URL** field and click its copy button. That is the exact value your provider needs. It appears for OIDC, GitHub, GitLab and JumpCloud, and not for None or Basic, which need no callback. -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`: + No such field? Build the URL yourself from the **App URL** block on the **Overview** tab. That block 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`, and its copy button gives you the app's URL rather than the callback URL. Add `/_proxy/callback` to the end: ``` https://-.hub./_proxy/callback @@ -56,11 +62,15 @@ Your provider needs the app's callback URL, so create the app first. For example: `https://toy-store-sales-74016144.hub.europe-west3.gcp.keboola.com/_proxy/callback` - The block is there from the moment the app exists; you don't have to deploy first. + An app created without a URL prefix has no hyphenated part, so its callback URL is `https://.hub./_proxy/callback`. + + Either way, the value exists from the moment the app does; you don't have to deploy first. -![The app's configuration page with the App URL block: the URL prefix, the generated host, and a copy button](/data-apps/publish-config.png) +The block sits below **Authentication**: -Keep this tab open. Each app has its own callback URL, so register every app with your provider separately. +![The app's Overview tab: Description, Authentication, and Git Repository cards, then the App URL block, with the App Info panel on the right](/data-apps/build-in-ui-config.png) + +Keep this tab open. You now have the callback URL; each app has its own, so register every app with your provider separately. ### Step 2 — Set up your identity provider @@ -70,61 +80,70 @@ Pick your provider: Let people sign in with their Google account. - **Before you start** — you need a Google Cloud project where you can manage the consent screen and OAuth clients: the project **Owner** role, or the **OAuth Config Editor** role. Decide who should get in, too. To limit sign-in to your Google Workspace organization, the Google Cloud project must belong to that organization and you pick the **Internal** audience below. Otherwise the audience is **External**: any Google account can sign in once you publish the app. + **Before you start.** The OAuth client lives in a Google Cloud project, not in the Google Workspace admin console, so you need a project where you can manage the consent screen and OAuth clients: the **Owner** role, or the **OAuth Config Editor** role. Decide who should get in, too. With the sign-in scopes Keboola requests (`openid`, `email`, `profile`), an **Internal** audience limits sign-in to your Google Workspace organization (the project must belong to that organization), and an **External** audience lets in anyone with a Google account. + + **Set up the consent screen.** Google keeps it under **Google Auth Platform**; open it directly at [console.cloud.google.com/auth/overview](https://console.cloud.google.com/auth/overview) and pick your project. + + 1. If the page says **Google Auth Platform not configured yet** and offers **Get started**, the project has no consent screen yet. Click it and fill in the wizard: **App name** and **User support email**, the **Audience** (**Internal** or **External**, see above), a contact email, then tick the User Data Policy box and click **Create**. If the page shows your app's details instead, the consent screen already exists; carry on. (**Branding**, **Audience** and **Clients** sit in the left menu either way, so they don't tell you which case you're in.) + 2. Optional: open [**Branding**](https://console.cloud.google.com/auth/branding) and add `keboola.com` under **Authorized domains**. Google adds it for you when you save the redirect URI in the next step ("The domains of the URIs you add below will be automatically added to your OAuth consent screen as authorized domains"), so this is only worth doing if you want it in place beforehand. + 3. Check [**Audience**](https://console.cloud.google.com/auth/audience). An **Internal** app shows only its user type; an **External** one also shows **Publishing status**, an **OAuth user cap** and a **Test users** list. Ignore all three. Google's own text there says that while the status is Testing "only test users are able to access the app", and that is not true for a Keboola app: the proxy asks for the `openid`, `email` and `profile` scopes only, and Google exempts exactly that set from the test-user rule, so an External app lets any Google account in whether or not you publish it. Publishing only matters if you want your app name and logo shown on the consent screen, and then Google asks for branding details and a verification review. - **Set up the consent screen:** + 4. Know what the audience buys you: it is the only access control Google SSO offers here. Anyone in the audience you chose can open the app — there is no group or user filter, and Keboola takes only a Client ID and secret for this provider. To narrow it further, use Microsoft Entra ID or Okta, which do have assignment, or check the signed-in user inside the app itself. - 1. Open the [Google Cloud console](https://console.cloud.google.com/), select your project, and open **Google Auth Platform** (search for it in the console's top bar). - 2. First time in this project? Click **Get started** and fill in the wizard: **App name** and **User support email**, the **Audience** (**Internal** for your Google Workspace organization only, **External** for any Google account), and a contact email, then click **Create**. - 3. Open **Branding**. Under **Authorized domains**, add `keboola.com`, the domain your App URL belongs to, and save. If Google refuses the redirect URI in the next step, it's because the domain is missing here. - 4. Chose **External**? Open **Audience** and add yourself and your testers under **Test users** (up to 100), or click **Publish app** to let anyone with a Google account sign in. Until you do one of these, Google turns everyone else away. + You now have: a consent screen with `keboola.com` authorized and the audience you want. **Create the OAuth client:** - 1. Open **Clients** and click **Create client**. + 1. Open [**Clients**](https://console.cloud.google.com/auth/clients) and click **Create client**. 2. Set **Application type** to **Web application** and give the client a name, for example `Keboola app - Toy store sales`. - 3. Under **Authorized redirect URIs**, click **Add URI** and paste the callback URL from step 1. It has to match exactly: `https`, the full host, and `/_proxy/callback` with no trailing slash. + 3. Under **Authorized redirect URIs**, click **Add URI** and paste the callback URL from step 1, for example `https://toy-store-sales-74016144.hub.europe-west3.gcp.keboola.com/_proxy/callback`. It has to match exactly: `https`, the full host, `/_proxy/callback`, no trailing slash, no stray spaces. 4. Click **Create**. Copy the **Client ID** and the **Client secret** now; Google shows the secret only at creation. If you lose it, open the client and click **Add Secret**. - **Back in Keboola** — on the app's configuration page, under **Authentication**, set **Authentication Type** to **OIDC (Custom)**, select **Google SSO** in the **Provider** dropdown, and paste the **Client ID** and **Client secret**. There's no issuer field for this option; Keboola uses `https://accounts.google.com`. Click **Save**. + You now have: a Client ID and a Client secret. + + **Back in Keboola.** On the app's configuration page, under **Authentication**, set **Authentication Type** to **OIDC (Custom)**, select **Google SSO** in the **Provider** dropdown, paste the **Client ID** and **Client secret** (this option has no issuer field), and click **Save**. After saving, the secret field is masked. Reveal it with the eye icon and you'll see an encrypted value starting with `KBC::ProjectSecure` rather than what you pasted. That is your secret stored [encrypted](/extend/encryption/), not a replacement; the rest of the prefix depends on which cloud your stack runs on. To change it later, paste a new value over it. **If sign-in fails:** - - `Error 400: redirect_uri_mismatch` — the URI in the OAuth client differs from the app's callback URL. Compare them character by character (scheme, host, `/_proxy/callback`, no trailing slash) and fix the client. - - "Access blocked: … has not completed the Google verification process", or a colleague can't get past Google — the audience is External and the app is still in **Testing**, so only listed **Test users** can sign in. Add them on the **Audience** page, or click **Publish app**. + - **Access blocked: This app's request is invalid**, with `Error 400: redirect_uri_mismatch` — the URI in the OAuth client differs from the app's callback URL. Open **Request details** on that page: it shows the `redirect_uri` Google received. Compare it with the **App URL** block character by character (a stray space or a missing character is the usual cause) and fix the client. - Someone outside your organization can't sign in — expected with the Internal audience. Switch to External on the **Audience** page if that's not what you want. + - Someone outside your organization *can* sign in — the audience is External. For the scopes Keboola uses, Google doesn't limit an External app to its test users, even in Testing. Switch to Internal. - `invalid_client`, or a token error right after signing in — the Client ID or Client secret in Keboola doesn't match the OAuth client. Paste them again, or add a new secret in Google Cloud and update the app. Changed the redirect URI or the audience on Google's side later? No redeploy needed; Google says such changes take from a few minutes to a few hours to apply. + *Console steps walked through on 2026-09-22.* Let people sign in with their Microsoft work account. - **Before you start** — you need permission to register applications in your tenant; the **Application Developer** role is enough for the registration itself. Restricting who can sign in needs **Cloud Application Administrator** or higher. + **Before you start** — you need permission to register applications in your tenant; the **Application Developer** role is enough for the registration itself. Restricting who can sign in needs **Cloud Application Administrator**, **Application Administrator**, or ownership of the app's service principal. **Register the app:** 1. Sign in to the [Microsoft Entra admin center](https://entra.microsoft.com/) and go to **Entra ID → App registrations → New registration**. 2. Enter a **Name** your users will recognize. - 3. Under **Supported account types**, keep **Single tenant only** (the option names your tenant): only users and guests of your tenant can sign in. + 3. Under **Supported account types**, keep the single-tenant option, which names your tenant: **Single tenant only**, or **Accounts in this organizational directory only** in older portal builds. Only users and guests of your tenant can sign in. 4. Under **Redirect URI (optional)**, choose **Web** and paste the callback URL from step 1. 5. Click **Register**. The app's **Overview** page opens. Copy the **Application (client) ID** and the **Directory (tenant) ID**; Keboola needs both. **Create a client secret:** 1. Under **Manage**, open **Certificates & secrets** and click **New client secret**. - 2. Enter a description, pick an expiry, and click **Add**. + 2. Enter a description, pick an expiry, and click **Add**. Microsoft caps the lifetime at 24 months and recommends under 12. 3. Copy the secret's **Value** right away; Entra hides it once you leave the page. Note the expiry, too: before it passes, create a new secret and update the app's authentication settings, or sign-in stops working. - **Optional — restrict who can sign in.** Out of the box, anyone in your tenant can open the app. To let in only specific people or groups, go to **Entra ID → Enterprise apps**, open your app, and under **Manage → Properties** set **Assignment required?** to **Yes**. Then, under **Manage → Users and groups**, click **Add user/group** and pick who may sign in. Assigning groups, rather than single users, needs a Microsoft Entra ID P1 or P2 license. Everyone else now gets `AADSTS50105` at sign-in. + You now have: an Application (client) ID, a Directory (tenant) ID, and a client secret Value. + + **Optional — restrict who can sign in.** Out of the box, anyone in your tenant can open the app. To let in only specific people or groups, go to **Entra ID → Enterprise apps**, open your app, and under **Manage → Properties** set **Assignment required?** to **Yes**. Then, under **Manage → Users and groups**, click **Add user/group**, pick who may sign in, leave **Select a role** on its default, and click **Assign**. Nothing is saved until you do. Assigning groups, rather than single users, needs a Microsoft Entra ID P1 or P2 license. Everyone else now gets `AADSTS50105` at sign-in, with one exception that will mislead you: the requirement doesn't apply to Global Administrators, so test with an ordinary account rather than your own. **Back in Keboola** — on the app's configuration page, under **Authentication**, set **Authentication Type** to **OIDC (Custom)**, select **Azure OIDC** in the **Provider** dropdown, and paste the **Client ID**, **Client secret**, and **Tenant ID**. Keboola builds the issuer from the tenant ID (`https://login.microsoftonline.com//v2.0`). Click **Save**. **If sign-in fails:** - `AADSTS50011: The redirect URI … does not match` — the redirect URI in the registration differs from the app's callback URL. Fix it under **Manage → Authentication**. - - `AADSTS7000215: Invalid client secret provided` — you pasted the secret's **Secret ID** instead of its **Value**, or the secret expired. Create a new one and update the app. + - `AADSTS7000215: Invalid client secret is provided` — the secret expired, or you pasted the secret's **Secret ID** instead of its **Value**. Create a new one and update the app. - `AADSTS50105: … is not assigned to a role for the application` — you required assignment and this user isn't assigned. Add them under **Enterprise apps → your app → Users and groups**. + *Checked against Microsoft's documentation on 2026-09-23. Not yet walked through a live tenant, and the Entra admin center changes often, so check the menu names as you go.* Let people sign in with their Okta account. @@ -133,20 +152,24 @@ Pick your provider: **Create the app integration:** - 1. In the Okta Admin Console, go to **Applications → Applications** (in newer orgs the menu is called **Applications and Resources**) and click **Create App Integration**. + 1. In the Okta Admin Console, go to **Applications and Resources → Applications** (**Applications → Applications** in Classic Engine orgs) and click **Create App Integration**. If Okta asks which experience to use, choose **Classic experience**. 2. Choose **OIDC - OpenID Connect** as the **Sign-in method** and **Web Application** as the **Application type**, then click **Next**. 3. Enter an **App integration name**, for example `Keboola app - Toy store sales`. - 4. Under **Sign-in redirect URIs**, replace the default value with the callback URL from step 1. You can remove the default **Sign-out redirect URIs** entry. + 4. Under **Sign-in redirect URIs**, enter the callback URL from step 1. Leave an entry under **Sign-out redirect URIs** if you plan to set a **Logout URL** in Keboola later; Okta only returns people to a URI registered there. 5. Under **Assignments**, decide who can sign in: **Allow everyone in your organization to access** or **Limit access to selected groups** (or skip the assignment for now and add people later). 6. Click **Save**. On the **General** tab, under **Client Credentials**, copy the **Client ID** and the **Client secret**. - **Back in Keboola** — on the app's configuration page, under **Authentication**, set **Authentication Type** to **OIDC (Custom)**, select **Okta** in the **Provider** dropdown, and paste the **Client ID** and **Client secret**. Set **Domain/Org URL** to `https:///oauth2/default`; your Okta domain is shown in the Admin Console when you click your name at the top right, for example `https://acme.okta.com/oauth2/default`. The `default` authorization server comes with the Integrator Free Plan and with API Access Management; if **Security → API → Authorization Servers** doesn't list it, use the org authorization server instead: `https://` with no path. **Logout URL** is optional: `https:///login/signout` also ends the Okta session when someone signs out of the app. Click **Save**. + You now have: a Client ID and a Client secret, and Okta knows your callback URL. + + **Back in Keboola** — on the app's configuration page, under **Authentication**, set **Authentication Type** to **OIDC (Custom)**, select **Okta** in the **Provider** dropdown, and paste the **Client ID** and **Client secret**. Set **Domain/Org URL** to the issuer of the authorization server you want to use; your Okta domain is shown in the Admin Console when you click your name at the top right. For plain single sign-on, Okta points you at the **org authorization server**, whose issuer is the bare domain with no path, for example `https://acme.okta.com`. Custom authorization servers need API Access Management, a paid add-on in production orgs. If your org has one, its issuer is `https://acme.okta.com/oauth2/default`, which is also what the field's example shows, and you can check under **Security → API → Authorization Servers**. One trap on an Integrator Free Plan org: the `default` server there ships **without an access policy**, and every token request fails until you add one. Open **Security → API → default → Access Policies** and add a policy that applies to your app. **Logout URL** is optional: use the `end_session_endpoint` from the discovery document of whichever server you chose, at `https:///oauth2/default/.well-known/openid-configuration` or `https:///.well-known/openid-configuration` for the org server. Okta returns people to a URI registered under **Sign-out redirect URIs**, so keep one there that matches. Click **Save**. **If sign-in fails:** - "The 'redirect_uri' parameter must be a Login redirect URI in the client app settings" — the URI in the integration differs from the app's callback URL. Fix **Sign-in redirect URIs** on the integration's **General** tab. - "User is not assigned to the client application" — the user, or their group, isn't assigned to the integration. Add them on the **Assignments** tab. - - Issuer or discovery error when the app starts the sign-in — check **Domain/Org URL**: `https://`, your Okta domain, `/oauth2/default`, no trailing slash. If your org has no `default` authorization server, use `https://` instead. + - Issuer or discovery error when the app starts the sign-in — check **Domain/Org URL** against the `issuer` in that server's discovery document, character for character, with no trailing slash. If sign-in reaches Okta and then fails on a free-plan org, check that the `default` authorization server has an access policy. + + *Checked against Okta's documentation on 2026-09-23. Not yet walked through a live org, so check the menu names as you go.* Let people sign in through Auth0, with whatever connections your tenant offers: username and password, social logins, or enterprise identity providers. @@ -158,16 +181,19 @@ Pick your provider: 1. In the [Auth0 Dashboard](https://manage.auth0.com/), go to **Applications → Applications** and click **Create Application**. 2. Name it, choose **Regular Web Applications**, and click **Create**. 3. Open the **Settings** tab. Under **Basic Information**, copy the **Domain**, **Client ID**, and **Client Secret**. - 4. Scroll down to **Application URIs** and paste the callback URL from step 1 into **Allowed Callback URLs**. + 4. Scroll down to **Application URIs** and paste the callback URL from step 1 into **Allowed Callback URLs**. If you plan to set a **Logout URL** in Keboola, add the app's URL to **Allowed Logout URLs** in the same block; Auth0 refuses any post-logout redirect that isn't registered there. 5. Click **Save Changes** at the bottom of the page. - **Back in Keboola** — on the app's configuration page, under **Authentication**, set **Authentication Type** to **OIDC (Custom)**, select **Auth0** in the **Provider** dropdown, and paste the **Client ID** and **Client secret**. Set **Issuer URL** to your tenant **Domain** with `https://` in front and a trailing slash, for example `https://acme.us.auth0.com/` (or a custom domain such as `https://login.acme.com/`). The field's example omits the slash, but Auth0's issuer ends with one; when in doubt, copy the `issuer` value from `https:///.well-known/openid-configuration`. **Logout URL** is optional: `https:///oidc/logout` also ends the Auth0 session when someone signs out of the app. Click **Save**. + You now have: your tenant Domain, a Client ID, and a Client Secret. + + **Back in Keboola** — on the app's configuration page, under **Authentication**, set **Authentication Type** to **OIDC (Custom)**, select **Auth0** in the **Provider** dropdown, and paste the **Client ID** and **Client secret**. Set **Issuer URL** to the `issuer` value from your tenant's discovery document, at `https:///.well-known/openid-configuration`. That's your custom domain if you have one, otherwise the **Domain** from step 3, and the two produce different issuers. Copy it character for character. Auth0 issuers normally end in a slash, for example `https://acme.us.auth0.com/` or `https://login.acme.com/`, while the field's own example omits it. **Logout URL** is optional: `https:///oidc/logout` also ends the Auth0 session when someone signs out of the app. Click **Save**. **If sign-in fails:** - - "Callback URL mismatch" on an Auth0 error page — the URL in **Allowed Callback URLs** differs from the app's callback URL. Fix it under **Settings → Application URIs**. + - "Callback URL Mismatch" on an Auth0 error page, with a line reading "{URL} is not in the list of allowed callback URLs" — the URL in **Allowed Callback URLs** differs from the app's callback URL. Fix it under **Settings → Application URIs**. - Issuer mismatch or discovery error when the app starts the sign-in — the **Issuer URL** must match the `issuer` in Auth0's discovery document character for character: `https://`, your Auth0 domain, trailing slash. - Users of one connection can't sign in — that connection isn't enabled for this application. Turn it on under the application's **Connections** tab. + *Checked against Auth0's documentation on 2026-09-23. Not yet walked through a live tenant, so check the menu names as you go.* Any OpenID Connect provider works through the **Generic OIDC** option. @@ -183,10 +209,11 @@ Pick your provider: ### Step 3 — Deploy and test -1. Set the app's code source and click **Deploy App**; the short wizard asks for the backend size and an inactivity timeout. (Details: [Create an app manually](/data-apps/getting-started/#create-an-app-manually). Just testing sign-in? A **Streamlit** app with a one-line inline script is the quickest thing to deploy.) -2. When the status turns **Active**, click **Open App**. Your provider asks you to sign in, then sends you into the app. +1. A new app: set its code source and click **Deploy App**; the short wizard asks for the backend version, the backend size and an inactivity timeout (details: [Create an app manually](/data-apps/getting-started/#create-an-app-manually)). Just testing sign-in? A **Streamlit** app with a one-line inline script is the quickest thing to deploy. An app that's already running needs **Redeploy App** for the new authentication to take effect; a stopped one, **Start App**. +2. When the status turns **Active**, click **Open App**. Your provider asks you to sign in and, the first time, to allow the app to see your name and email address; then it sends you into the app. If the page still says the app is stopped right after a deploy, reload it — the status catches up a moment later. +3. Test with the accounts that matter: one that should get in, one that shouldn't. Once you're in, the app's own session cookie keeps you signed in, so a second try in the same window proves nothing — use a fresh private window, or open `https:///_proxy/sign_out` to end the app session and start over. -Changing the authentication settings of an app that's already deployed? Click **Redeploy App** so the change takes effect. + Know what a correct rejection looks like before you read it as a fault. With Google and an **Internal** audience, an account from outside your organization is stopped by Google with a message that the app is restricted to its organization — that is the app working. Do **not** switch the audience to **External** to make that message go away; it opens the app to every Google account there is. The reverse is the quiet failure: if an outside account lands in the app, your audience is External and the app is public to anyone signed in to Google. ### Provider settings at a glance @@ -225,7 +252,7 @@ Restrict access to your app using GitHub OAuth. Users authenticate via their Git ### Setup instructions 1. Go to your GitHub account **Settings > Developer Settings > OAuth Apps** and create a new OAuth App. -2. Set the **Authorization callback URL** to: `https://.hub./_proxy/callback` (e.g., `https://my-app-12345678.hub.north-europe.azure.keboola.com/_proxy/callback`). +2. Set the **Authorization callback URL** to the app's callback URL. Copy it from the **Callback URL** field under **Authentication**, or build it as `https://-.hub./_proxy/callback` (e.g., `https://my-app-12345678.hub.north-europe.azure.keboola.com/_proxy/callback`). 3. Copy the **Client ID** and **Client Secret** from the created OAuth App. 4. In your Keboola app configuration, select **GitHub** as the authentication method. 5. Paste the **Client ID** and **Client Secret**. @@ -256,7 +283,7 @@ Restrict access to your app using GitLab OAuth. Users authenticate via their Git ### Setup instructions 1. Go to your GitLab instance **Settings > Applications** and create a new application. -2. Set the **Redirect URI** to: `https://.hub./_proxy/callback` (e.g., `https://my-app-12345678.hub.north-europe.azure.keboola.com/_proxy/callback`). +2. Set the **Redirect URI** to the app's callback URL. Copy it from the **Callback URL** field under **Authentication**, or build it as `https://-.hub./_proxy/callback` (e.g., `https://my-app-12345678.hub.north-europe.azure.keboola.com/_proxy/callback`). 3. Ensure the `openid`, `profile`, and `email` scopes are selected. If you use group or project restrictions, also select `read_api`. 4. Copy the **Application ID** and **Secret**. 5. In your Keboola app configuration, select **GitLab** as the authentication method. @@ -287,7 +314,7 @@ Restrict access to your app using JumpCloud OIDC. Users authenticate via their J 1. In the **JumpCloud Admin Console**, go to **SSO** and create a new application (or use an existing one). 2. Configure the application as an **OIDC** application. -3. Set the **Redirect URI** to: `https://.hub./_proxy/callback` (e.g., `https://my-app-12345678.hub.north-europe.azure.keboola.com/_proxy/callback`). +3. Set the **Redirect URI** to the app's callback URL. Copy it from the **Callback URL** field under **Authentication**, or build it as `https://-.hub./_proxy/callback` (e.g., `https://my-app-12345678.hub.north-europe.azure.keboola.com/_proxy/callback`). 4. Copy the **Client ID** and **Client Secret** from the SSO tab. 5. In your Keboola app configuration, select **JumpCloud** as the authentication method. 6. Paste the **Client ID**, **Client Secret**, **Issuer URL**, and **Logout URL**. @@ -296,15 +323,17 @@ Restrict access to your app using JumpCloud OIDC. Users authenticate via their J ## Callback URL format -All authentication methods that use OAuth or OIDC require a callback URL. The format is always: +Every method that uses OAuth or OIDC needs a callback URL, and the app's configuration gives you the finished value: the **Callback URL** field under **Authentication**, with a copy button. Copy it rather than typing it. A single wrong character is the most common reason sign-in fails, and the provider reports it as a redirect mismatch rather than as a typo. + +The rest of this section is for reading a URL you already have, or for a stack where the field hasn't appeared yet. ``` -https://.hub./_proxy/callback +https://-.hub./_proxy/callback ``` For example: `https://my-app-12345678.hub.north-europe.azure.keboola.com/_proxy/callback` -`` stands for the whole host shown in the **App URL** block on the app's configuration page: the URL prefix, a hyphen, and the App ID (for example `toy-store-sales-74016144`). Take that host, add `https://` in front and `/_proxy/callback` at the end. +`-.hub.` is the whole host shown in the **App URL** block on the app's configuration page: the URL prefix, a hyphen, and the App ID, for example `toy-store-sales-74016144`. An app created without a URL prefix has no hyphenated part, so its callback URL is `https://.hub./_proxy/callback`. --- diff --git a/src/content/docs/data-apps/getting-started.md b/src/content/docs/data-apps/getting-started.md index 3a525404a..6726e9638 100644 --- a/src/content/docs/data-apps/getting-started.md +++ b/src/content/docs/data-apps/getting-started.md @@ -101,12 +101,14 @@ Prefer to set the app up yourself, without the chat? Manual creation lives on th ![The app's configuration page: the Overview tab with Authentication and a Git Repository section, plus the App Info panel showing backend version, size, auto-sleep, and App ID](/data-apps/build-in-ui-config.png) -6. Click **Deploy App**. A short wizard asks for the **backend size** and an **inactivity timeout**, then deploys the app. (The same wizard runs on **Redeploy**.) +6. Click **Deploy App**. A short wizard asks for the **backend version**, the **backend size** and an **inactivity timeout**, then deploys the app. (The same wizard runs on **Redeploy**.) -![The deploy/redeploy wizard: backend size and inactivity timeout](/data-apps/deploy-timeout-backedsize.png) +![The deploy/redeploy wizard: backend version, backend size and inactivity timeout](/data-apps/deploy-timeout-backedsize.png) 7. When the status turns **Active**, click **Open App** to open it at its public URL. Use **Redeploy** to apply any later config change; see [App actions](/data-apps/reference/#app-actions). +From here on, the app is something you run rather than something you build: [Operate and update an app](/data-apps/operate/) covers shipping changes, secrets, sleeping and versions. + --- **Next:** [Build an app locally →](/data-apps/build-locally/) diff --git a/src/content/docs/data-apps/index.md b/src/content/docs/data-apps/index.md index c3c0d21df..c8984f490 100644 --- a/src/content/docs/data-apps/index.md +++ b/src/content/docs/data-apps/index.md @@ -23,12 +23,14 @@ Dashboards and reports, internal tools, data narratives, configurators, and agen ## Two ways to build -- **[Build with Kai](/data-apps/getting-started/)** — describe the app in plain language and Kai reads your data, builds a live draft you preview and refine, and publishes when you're ready. No coding needed — the walkthrough takes about 10 minutes. The same **Create App** screen also offers [manual creation](/data-apps/getting-started/#create-an-app-manually) if you'd rather configure the app yourself. -- **[Build locally](/data-apps/build-locally/)** — develop with your own tools and Git account, use the [AI Kit](/ai/ai-kit/) coding-assistant plugins, and sync the app to your project. For developers who want full control — that page covers how Python/JS development works day to day. +- **[Build with Kai](/data-apps/getting-started/)** — describe the app in plain language and Kai reads your data, builds a live draft you preview and refine, and publishes when you're ready. No coding needed — the walkthrough takes about 10 minutes. The same **Create App** screen also offers [manual creation](/data-apps/getting-started/#create-an-app-manually) if you'd rather configure the app yourself. **You need:** a Keboola project. Nothing else. +- **[Build locally](/data-apps/build-locally/)** — develop with your own tools and Git account, use the [AI Kit](/ai/ai-kit/) coding-assistant plugins, and sync the app to your project. For developers who want full control — that page covers how Python/JS development works day to day. **You need:** a Git account and somewhere to host the repository; about half an hour the first time. + +Both routes end up in a Git repository, either one Keboola manages for the app or one you host. [Two ways to run an app](/data-apps/what-are-apps/#two-ways-to-run-an-app) explains what each gives you, including why the Kai builder appears on one and not the other. ## Run and share -Every app has its own settings page in **Apps**: who can open it ([Authentication](/data-apps/authentication/) — public, password, or your company SSO), its URL and how to [publish and share](/data-apps/publish-and-share/) it, and operational settings like backend size and auto-sleep ([Reference](/data-apps/reference/)). Deploying and redeploying is one click; logs are right on the app's detail. +Every app has its own settings page in **Apps**: who can open it ([Authentication](/data-apps/authentication/) — public, password, or your company SSO), its URL and how to [publish and share](/data-apps/publish-and-share/) it, and operational settings like backend size and auto-sleep ([Reference](/data-apps/reference/)). Deploying and redeploying is one click; logs are right on the app's detail. Once it's live, [Operate and update an app](/data-apps/operate/) covers the day-to-day work and [Troubleshooting](/data-apps/troubleshooting/) covers the days it goes wrong. ## Beyond dashboards diff --git a/src/content/docs/data-apps/operate.md b/src/content/docs/data-apps/operate.md new file mode 100644 index 000000000..2768891c1 --- /dev/null +++ b/src/content/docs/data-apps/operate.md @@ -0,0 +1,62 @@ +--- +title: Operate and update an app +slug: 'data-apps/operate' +description: "Day-to-day work on a deployed Keboola app: read its state, ship a code change, change settings, stop and start it, rotate a secret, delete it." +--- + +Once an app is deployed, everything you do with it starts on its page under **Apps**. This page walks through the routine tasks; [Apps reference](/data-apps/reference/) has the full list of settings and actions. + +Deploying, starting, stopping, deleting and setting secrets also work from a terminal with `kbagent`; drafts, copying and rollback are UI-only. The `kbagent` commands below all take `--project `, the name you gave the project when you [connected it](/cli/concepts/#connections-and-config), and `--app-id`, the numeric **App ID** from the **App Info** panel. + +## Read the app's state + +The header shows the app's status and the one or two actions that make sense for it: **Deploy App** for an app that has never run, **Start App** for a stopped one, **Open App** and **Redeploy App** for a running one, and **Modify with Kai** on apps Kai built. The **⋯** menu holds the rest, and its contents depend on the state too: **Copy app**, **Automate** (add it to a flow), **Debug mode** and **Delete app** are always there, with **Suspend app** on a running app. + +The tabs below the header split the app's life into views: **Overview** (the app's settings and its App URL), **Advanced Settings** (environment variables and secrets, theme, data mappings), **All Runs** (every start attempt), **Terminal Logs** (stdout and stderr while it runs), **Versions** (the configuration history), and **Drafts** while Kai has a draft open. The **App Info** panel on the right shows the backend version and size, the auto-sleep timeout, the last change, the owner, and the App ID. + +## Ship a code change + +How depends on where the code lives; see [Two ways to run an app](/data-apps/what-are-apps/#two-ways-to-run-an-app). + +- **Kai built the app.** Click **Modify with Kai** and describe the change. Kai works in a draft with its own live preview; when you're happy, publish it to production. The production app keeps serving the old version until you do. Details: [Build your first app with Kai](/data-apps/getting-started/#how-drafts-become-production). +- **Your own repository.** Push to the branch set under **Git Repository** on the app's page, then click **Redeploy App**. Keboola clones that branch again, runs your repository's `keboola-config/setup.sh` if it has one, and starts the new version. Push alone changes nothing. The app can report **stopped** for a moment while it restarts, so give it a reload before you worry. + +From a terminal, a redeploy is `kbagent data-app deploy --project --app-id --wait`. + +## Change settings + +Authentication, secrets, environment variables and the Git branch are edited on the app's page; the backend size and the inactivity timeout are chosen in the deploy wizard each time you deploy or start the app. Nothing you edit on the page takes effect until the app runs again, so after saving click **Redeploy App** on a running app or **Start App** on a stopped one. The wizard asks for backend version, backend size and inactivity timeout every time; keep the current values unless you mean to change them. + +Secrets deserve one note: after you save one, the field is masked, and revealing it shows an encrypted value starting with `KBC::ProjectSecure`. That's the secret stored [encrypted](/extend/encryption/), not a replacement, and the rest of the prefix depends on which cloud your stack runs on. To rotate it, paste the new value over the encrypted one and redeploy. How secret names become environment variables: [Secrets](/data-apps/reference/#secrets). + +From a terminal: `kbagent data-app secrets-set --project --app-id --secret '#API_KEY=…'`, then `kbagent data-app deploy`. + +## Stop, start, sleep + +- **Sleeping** is automatic. After the inactivity timeout (five minutes to 24 hours, set in the deploy wizard) the app suspends; the next visit wakes it and shows a short **waking up** page. You pay only for time the app is awake or waiting to suspend. +- **Stopping** is deliberate: **⋯ → Suspend app** stops the container and keeps the configuration, so the app stops serving until you bring it back with **Start App**. Use this when an app should be off for days; sleeping already covers being idle overnight. +- **Redeploy App** restarts a running app with the current configuration and, for apps on your own repository, the current branch head. + +From a terminal: `kbagent data-app stop` and `kbagent data-app start`, both with `--project` and `--app-id`. + +Sleep and wake behaviour in detail, including the wakeup error page: [Sleep and resume](/data-apps/reference/#sleep-and-resume). + +## See what changed, and go back + +The **Versions** tab lists the app's configuration history: who changed what, and when. An app is a component configuration like any other, so you can compare versions and [roll back](/components/#rollback-version) to an earlier one. A rollback changes the configuration only, so redeploy afterwards to put the old settings back in service. + +Code changes are tracked separately from configuration: for a Kai-built app they're in the Builder's chat and drafts, and for your own repository they're in your Git history. + +## Copy, automate, delete + +- **Copy app** duplicates the configuration into a new app, so you can try a change without touching the one people use. +- **Automate** adds the app to a flow, for example to redeploy it after the data it reads has been refreshed. +- **Delete app** stops the app and deletes its configuration. The App URL stops working immediately; there is no undo. The terminal equivalent, `kbagent data-app delete`, says the same thing in its own words: cascade, irreversible. + +## When something is off + +Start with [Troubleshooting](/data-apps/troubleshooting/): where the logs are, what the common start failures look like, and what to do about each. + +--- + +**Next:** [Troubleshooting →](/data-apps/troubleshooting/) diff --git a/src/content/docs/data-apps/publish-and-share.md b/src/content/docs/data-apps/publish-and-share.md index 0dfb7b7f4..b3a855e91 100644 --- a/src/content/docs/data-apps/publish-and-share.md +++ b/src/content/docs/data-apps/publish-and-share.md @@ -10,7 +10,7 @@ Once your app is ready, publish it and share the link with the people who need i An app is "published" once it's deployed and reachable at its URL, with the right people able to open it: -1. **Deploy the app.** From the app's configuration, click **Deploy App**. A short wizard asks for the **backend size** and an **inactivity timeout**, then deploys it; when the status turns **Active**, it's served at its public URL. See [App actions](/data-apps/reference/#app-actions). +1. **Deploy the app.** From the app's configuration, click **Deploy App**. A short wizard asks for the **backend version**, the **backend size** and an **inactivity timeout**, then deploys it; when the status turns **Active**, it's served at its public URL. See [App actions](/data-apps/reference/#app-actions). ![The Deploy App wizard: Backend Version (Python/JS), Backend Size, and Inactivity Timeout, with a Deploy App button](/data-apps/deploy-timeout-backedsize.png) @@ -25,10 +25,10 @@ Share the app URL — found on the app's **Overview** tab (the **App URL** block ## Manage a deployed app -From the app's header you can **Modify with Kai**, **Open App**, and **Start App** / **Redeploy App** depending on its state. The **⋯** menu holds the rest — **Copy app**, **Automate** (add it to a flow), **Debug mode**, and **Delete app**. See [App actions](/data-apps/reference/#app-actions) in the reference. +From the app's header you can **Modify with Kai**, **Open App**, and **Start App** / **Redeploy App** depending on its state. The **⋯** menu holds the rest: **Copy app**, **Automate** (add it to a flow), **Debug mode** and **Delete app**, plus **Suspend app** while the app is running. [Operate and update an app](/data-apps/operate/) walks through each one. ![The app header with Modify with Kai / Open App / Start App and the ⋯ menu open showing Copy app, Automate, Debug mode, and Delete app](/data-apps/app-actions-menu.png) --- -**Next:** [Apps reference →](/data-apps/reference/) +**Next:** [Operate and update an app →](/data-apps/operate/) diff --git a/src/content/docs/data-apps/reference.md b/src/content/docs/data-apps/reference.md index 148420acc..418b89195 100644 --- a/src/content/docs/data-apps/reference.md +++ b/src/content/docs/data-apps/reference.md @@ -181,9 +181,16 @@ Manage a deployed app from its actions menu. - **Deploy App** — starts the app. Once the deployment job finishes, open the app's public URL with **Open App**. - **Open App** — opens a new window with your app. -- **Redeploy** — apply changes made in the app configuration (they take effect only after a redeploy). -- **Suspend App** — stops the app. The container stops and the URL is no longer available, but the configuration is kept. -- **Delete App** — stops the deployment and deletes its configuration. +- **Redeploy App** — apply changes made in the app configuration (they take effect only after a redeploy). +- **Start App** — brings a stopped app back with the same settings. +- **Modify with Kai** — opens the Builder, on apps Kai built. +- **Suspend app** — stops the app. The container stops and the app no longer serves, but the configuration is kept. +- **Copy app** — duplicates the configuration into a new app. +- **Automate** — adds the app to a flow. +- **Debug mode** — runs the app with extra diagnostics. +- **Delete app** — stops the deployment and deletes its configuration. + +Which of these the header and the **⋯** menu offer depends on the app's state. [Operate and update an app](/data-apps/operate/) walks through them in the order you meet them. ## Sleep and resume @@ -201,7 +208,7 @@ If something goes wrong, a **wakeup error** page appears; click **Show More** fo ![Wakeup error](/data-apps/proxy-error-wakeing-up.png) -When you **Deploy** or **Redeploy**, a wizard prompts for the backend size and the auto-sleep timeout (five minutes to 24 hours; default five minutes). +When you **Deploy** or **Redeploy**, a wizard prompts for the backend version, the backend size and the auto-sleep timeout (five minutes to 24 hours; default five minutes). ![Deploy timeout and backend size](/data-apps/deploy-timeout-backedsize.png) diff --git a/src/content/docs/data-apps/troubleshooting.md b/src/content/docs/data-apps/troubleshooting.md new file mode 100644 index 000000000..f644238dc --- /dev/null +++ b/src/content/docs/data-apps/troubleshooting.md @@ -0,0 +1,59 @@ +--- +title: Troubleshooting +slug: 'data-apps/troubleshooting' +description: "What to do when a Keboola app doesn't start, doesn't behave, or won't let people in: where the evidence is, the usual causes, and the fix for each." +--- + +Most app problems fall into a handful of patterns. Find where the evidence is first, then your symptom below. + +## Where to look + +- **The deployment job.** Every **Deploy** and **Redeploy** runs as a job, and its event log keeps the container output from the start attempt, including the runtime's own `[ERROR]` lines. Open it from the app's **All Runs** tab or from **Jobs**. +- **Terminal Logs**, the app's tab: stdout and stderr while the app runs. Keboola keeps them only while the app is running. +- **From a terminal**, if you use the [Keboola CLI](/cli/): + + ```bash + kbagent data-app runs --project --app-id + kbagent data-app logs --project --app-id + ``` + + The first lists recent start attempts with their outcome; the second tails the container log. `` is the name you gave the project when you [connected it](/cli/concepts/#connections-and-config); `` is the numeric **App ID** from the **App Info** panel on the app's page. +- **Kai**, for an app it built: ask it why the app isn't running. It reads the same logs. + +## The app doesn't start + +| What you see | Why | Fix | +|---|---|---| +| **Data App is not running** right after a deploy, the run lasted about a second, and the log says `App must have keboola-config/nginx/ directory` (or `supervisord/`) | The repository lacks the `keboola-config/` folder, or part of it, so the container exits at once. This is the most common start failure we measure on customer stacks. | Add the folder; the app-building skill's [reference](https://github.com/keboola/ai-kit/blob/main/plugins/dataapp-developer/skills/dataapp-development/references/python-js-apps.md) lists what goes in it and explains every line. Then check the repository before deploying again: `kbagent data-app validate-repo --git-repo https://github.com// --git-branch main --type python-js`. | +| `fatal: Authentication failed` in the job log | Keboola couldn't clone the repository: the access token or SSH key for a private repository is missing, wrong, or expired. | Open **Git Repository** on the app, update **Username** and **Access Token** or the **SSH Private Key**, and redeploy. For a Keboola-managed repository this shouldn't happen; redeploy, and if it repeats, report it with the job ID. | +| The app starts and stops in a loop | The supervisord program can't start the process: a relative path where a full `/app/...` path is needed, a Python command without `uv run`, a `setup.sh` committed without the executable bit, or a `[program:nginx]` entry the image already provides. | Fix the config; the skill's [reference](https://github.com/keboola/ai-kit/blob/main/plugins/dataapp-developer/skills/dataapp-development/references/python-js-apps.md) spells out each rule and the reasoning behind it. | +| The install step fails | No `pyproject.toml` or `package.json` where `setup.sh` runs, or `pip install` in `setup.sh`; the image blocks bare `pip` (`externally-managed-environment`). | Commit the manifest; use `uv sync` or `npm install --omit=dev`. | +| The deploy job fails on a package conflict | Two dependencies want incompatible versions, or an unpinned package moved. | Pin versions. Streamlit apps: [Lock package versions](/data-apps/streamlit/lock-version/). | + +## The app runs but misbehaves + +| What you see | Why | Fix | +|---|---|---| +| `Cannot POST /`, "Method Not Allowed", or a blank page on first open | Keboola checks the app with a POST to `/`, and the root route only accepts GET. | Accept POST on `/`: Flask `methods=["GET", "POST"]`, Express `app.all('/')`. Streamlit handles it on its own. | +| Works locally, not in Keboola | The port in nginx's `proxy_pass` doesn't match the port the app listens on, or the app binds an interface nginx can't reach. | Make the ports match and listen on `127.0.0.1` or all interfaces. | +| A streaming response arrives all at once | nginx buffers the whole response before forwarding it. | `proxy_buffering off; proxy_cache off; proxy_request_buffering off;` in that `location` block. | +| The page loads but never updates | The WebSocket handshake isn't upgraded. | Add the WebSocket upgrade directives to that `location` block; the skill's [nginx reference](https://github.com/keboola/ai-kit/blob/main/plugins/dataapp-developer/skills/dataapp-development/references/python-js-apps.md) has the snippet. | +| An environment variable is undefined | The secret isn't in the app's configuration, or you're using the wrong name. | Add it; `#my-key` becomes `MY_KEY`. See [Secrets](/data-apps/reference/#secrets). | +| A bundled frontend serves stale or missing files | The build output isn't committed. | Build locally and commit the output; Keboola installs dependencies, it doesn't run your build. | +| The app loads, but every query comes back empty, and the logs look clean | Storage Access is off, so Keboola never injects `WORKSPACE_ID`, `QUERY_SERVICE_URL` and `KBC_WORKSPACE_MANIFEST_PATH`. The app deploys and reports running while serving no data. | Turn on **Storage Access** for the app and redeploy. It also has to be enabled for the project first, under **Project Settings > Features**. See [Data access](/data-apps/reference/#data-access). | +| A Streamlit app shows an error in the browser, but the logs are empty | Streamlit renders uncaught exceptions in the page and doesn't write them to stderr. | Wrap your entry point so exceptions are logged to stderr before Streamlit shows them. | + +## Sign-in problems + +- **Basic (Password):** the password is on the app's configuration page next to **Open App** once the app is deployed. +- **OIDC:** the Google, Entra, Okta and Auth0 tabs on [Authentication](/data-apps/authentication/) each end with an "If sign-in fails" list covering that provider's error texts, redirect-URI mismatches, and audience settings. +- **GitHub, GitLab, JumpCloud:** each has its own required fields and its own optional restrictions, which are the first thing to check when the right person is turned away. GitHub filters by organization, team, repository and allowed users; GitLab by group, project and allowed roles; JumpCloud by allowed roles. All three are in their sections of [Authentication](/data-apps/authentication/). +- **Nobody can get in after you changed the authentication settings:** the change takes effect on the next start. Click **Redeploy App** (running app) or **Start App** (stopped app). + +## Sleeping and waking + +An idle app suspends after its inactivity timeout. The next visit wakes it and shows a **waking up** page for a moment; if waking fails, a **wakeup error** page appears with a **Show More** link to the reason. Details and the timeout setting: [Sleep and resume](/data-apps/reference/#sleep-and-resume). + +--- + +**Next:** [Apps reference →](/data-apps/reference/) diff --git a/src/content/docs/data-apps/what-are-apps.md b/src/content/docs/data-apps/what-are-apps.md index a182eafac..d229158a3 100644 --- a/src/content/docs/data-apps/what-are-apps.md +++ b/src/content/docs/data-apps/what-are-apps.md @@ -38,9 +38,23 @@ How development actually works — code, configuration, data access, deployment Have an existing **Streamlit** app? Streamlit remains supported; its documentation lives in the [Streamlit apps](/data-apps/streamlit/) section. -## Where Kai fits +## Two ways to run an app -Kai can build, edit, and run apps for you. Throughout these docs, "build with Kai" is the recommended path for most users — it removes the low-level setup you'd otherwise do by hand. Developers who want full control can still build locally; see [Build locally](/data-apps/build-locally/). +If the Kai builder and the live preview are missing from your app, its code lives in a repository you host. Those two features need a repository Keboola manages for the app. Everything else works the same either way, and here is what each path gives you. (A Streamlit app is the exception to all of this: it can run from inline code with no repository at all. See [Streamlit apps](/data-apps/streamlit/).) + +**A Keboola-managed repository.** Keboola creates a private Git repository for the app on your stack, at `git..keboola.com/keboola/app-.git`. Kai commits to it, which is what makes the live preview, the drafts you refine before publishing, and **Modify with Kai** possible. You never touch Git yourself. This is the recommended path for most people, and the one [Build your first app with Kai](/data-apps/getting-started/) walks through. Kai isn't the only way in: `kbagent data-app create --use-managed-git-repo` provisions the same repository empty, mints a credential for it, and pushes your code, so you can hold a managed repository and still write the code yourself. + +**Your own repository.** Point the app at a repository you host, on GitHub, GitLab, or any Git server, and Keboola clones it on every deploy. You develop wherever you like, with your own editor and review process, and with coding assistants such as Claude Code using the [app-building skill](/data-apps/build-locally/#develop-with-an-ai-coding-tool). The Kai builder and its live preview aren't part of this path; you push a change and click **Redeploy App**. Your repository has to follow a small layout contract so Keboola knows how to start it; the app-building skill's [reference](https://github.com/keboola/ai-kit/blob/main/plugins/dataapp-developer/skills/dataapp-development/references/python-js-apps.md) spells it out, and [Build locally](/data-apps/build-locally/) covers developing and syncing your own repository; deploying and running it from a terminal with `kbagent data-app` is on [Operate and update an app](/data-apps/operate/). + +Which kind of repository an app uses is decided when the app is created. Everything after the code is the same on both paths: the same runtime, the same [authentication](/data-apps/authentication/) options, the same App URL, deploy, redeploy, sleep, and logs. + +| | A Keboola-managed repository | Your own repository | +|---|---|---| +| Who writes the code | Kai, or you pushing to the managed repo | You, or your coding assistant | +| Kai builder, live preview, drafts | Yes | No | +| Changing the app | Tell Kai, preview the draft, publish | Push, then **Redeploy App** | +| Layout rules for the repo | Scaffolded for you when Kai builds the app; yours to meet if you push to it yourself | The `keboola-config/` contract is yours to meet | +| Best for | Dashboards, internal tools, getting something in front of people fast | Existing code, teams with a review process, custom stacks | --- diff --git a/src/sidebar.mjs b/src/sidebar.mjs index 3b623e272..b9630f2d2 100644 --- a/src/sidebar.mjs +++ b/src/sidebar.mjs @@ -113,6 +113,8 @@ export const sidebar = [ items: [ { slug: "data-apps/authentication" }, { slug: "data-apps/publish-and-share" }, + { slug: "data-apps/operate" }, + { slug: "data-apps/troubleshooting" }, ], }, { slug: "data-apps/reference" },