{"id":20875036,"url":"https://github.com/servicestack/studio","last_synced_at":"2025-09-04T04:46:58.912Z","repository":{"id":66141399,"uuid":"255179589","full_name":"ServiceStack/Studio","owner":"ServiceStack","description":"ServiceStack Studio","archived":false,"fork":false,"pushed_at":"2022-06-02T12:31:24.000Z","size":508,"stargazers_count":7,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-08-28T18:58:29.501Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ServiceStack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-12T22:12:56.000Z","updated_at":"2022-01-12T08:11:12.000Z","dependencies_parsed_at":"2023-02-24T08:30:16.556Z","dependency_job_id":null,"html_url":"https://github.com/ServiceStack/Studio","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ServiceStack/Studio","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ServiceStack%2FStudio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ServiceStack%2FStudio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ServiceStack%2FStudio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ServiceStack%2FStudio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ServiceStack","download_url":"https://codeload.github.com/ServiceStack/Studio/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ServiceStack%2FStudio/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273554284,"owners_count":25126312,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-04T02:00:08.968Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-18T06:41:23.464Z","updated_at":"2025-09-04T04:46:58.886Z","avatar_url":"https://github.com/ServiceStack.png","language":"TypeScript","readme":"# ServiceStack Studio\n\nis a capability-based UI to manage multiple remote ServiceStack instances from either a Chromium Desktop App or cross-platform .NET Core Web App. \n\nThe richer metadata in ServiceStack Services allows Studio to logically group Services around Data Models, enabling its high-level semantic features like its native data-grid like UX over all AutoQuery Services to quickly discover, search, create, update and delete entities based on the available AutoQuery APIs and whether Authenticated Users have access to them.\n\n\u003e YouTube: [youtu.be/2FFRLxs7orU](https://youtu.be/2FFRLxs7orU)\n\n[![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-home.png)](https://youtu.be/2FFRLxs7orU)\n\n**Studio** replaces the [ServiceStack Admin UI](https://github.com/ServiceStack/Admin) where it provides a UX-friendly UI for accessing AutoQuery \u0026 Crud Services but will also gain UI features for taking advantage of various ServiceStack Plugins \u0026 Features, e.g. in this initial release it includes UI's for **Managing DB Validation Rules** \u0026 for viewing the **Executable Audit History of Tables** updated through AutoCrud Services.\n\n### Requires v5.9+\n\n**Studio** capability-based Admin UI is enabled via the `/metadata/app` endpoint which returns metadata information about which plugins are enabled, what features they're configured with and what User Roles they're protected behind (if any). As such it's only able to manage **v5.9+** ServiceStack instances.\n\nYou'll need the latest [app dotnet tool](https://docs.servicestack.net/netcore-windows-desktop) which is bundled with the latest Chromium which provides the Desktop UI:\n\n    $ dotnet tool update -g app\n\nWhich you'll need to run once to register the `app://` url scheme, e.g:\n\n    $ app -version\n\n### Starting ServiceStack Studio\n\nThis initial release of ServiceStack Studio primarily provides a UI around AutoQuery Services and the latest features in this release like **Executable Audit History** and declarative **RDBMS validators**.\n\nIf you don't have a project using the **v5.9+** features on hand you can launch a copy of [NetCoreApps/NorthwindCrud](https://github.com/NetCoreApps/NorthwindCrud) which uses the new AutoCrud features to generate AutoQuery Services around all its RDBMS tables, that can be run locally with:\n\n    $ x download NetCoreApps/NorthwindCrud\n    $ cd NorthwindCrud\n    $ dotnet run\n\nWhere you can use `app` URL scheme support to launch **Studio** \u0026 automatically register the **NorthwindCrud** instance with:\n\n[app://studio?connect=https://localhost:5001](app://studio?connect=https://localhost:5001)\n\nThis URL scheme gets translated \u0026 is equivalent to running **Studio** on the command-line with:\n\n    $ app open studio -connect https://localhost:5001\n\nWhich downloads the [Studio Gist Desktop App](https://gist.github.com/gistlyn/d8e7a56027ed6ec3060d9a9896931909), loads it as a [Gist VFS](https://docs.servicestack.net/virtual-file-system#gistvirtualfiles) whose static assets are then served by the .NET Core Server and loaded in the CEF Chromium browser.\n\nThe `connect` param is used by **Studio** to auto register the remote **NorthwindCrud** instance where it auto downloads its App Metadata containing its enabled plugins \u0026 features \u0026 within a few seconds you should see it appear on the home page:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-home.png)\n\n#### Desktop-less x-plat app\n\nWhilst not optimized for it, **Studio** can also be launched headless in your default Browser using the `x` x-plat tool:\n\n[xapp://studio?connect=https://localhost:5001](xapp://studio?connect=https://localhost:5001)\n\n    $ x open studio -connect https://localhost:5001\n\nWhere you'll then be able to view it by going to `https://localhost:5002`. Note if not launched in a browser **Studio** will have limited capacity and features, but will eventually be a supported mode for accessing **Studio** from macOS or Linux.\n\n### Home Page\n\nFrom the home page you'll see all the top-level Admin Sections available that's enabled on the remote instance, in the initial release there's a UI for accessing **AutoQuery Services** and a UI for maintaining **DB Validation Rules**.\n\n### AutoQuery UI\n\nStudio uses the rich declarative metadata of AutoQuery \u0026 Crud Services to infer the **data model** that each AutoQuery Service operates on and the **Operation Type** they provide. As a result it can logically group each Service around the Data Model they operate on to provide a more intuitive \u0026 natural UI for each of the different AutoQuery/CRUD operation types.\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/autoquery-noauth.png)\n\nWhat UI features \u0026 tables are visible is reflected by whether the AutoQuery Service for that type exists and whether the currently authenticated User has access to them (i.e. Have the role required by each Service). So an unauthenticated user will see Northwind Crud's read-only **Region** table with no ability to update it \u0026 the **Territory** table, which as it isn't protected by a role will be visible to everyone, \nbut as all CRUD Write operations require authentication, all edit controls require authentication - as shown in the screenshot above where they're replaced with auth **Sign In** buttons.\n\nHere are the relevant [NorthwindCrud auto-generation rules](https://github.com/NetCoreApps/NorthwindCrud/blob/master/Startup.cs) which defines this behavior:\n\n```csharp\nvar readOnlyTables = new[] { \"Region\" };\nGenerateCrudServices = new GenerateCrudServices {\n    ServiceFilter = (op,req) =\u003e {\n        // Require all Write Access to Tables to be limited to Authenticated Users\n        if (op.IsCrudWrite())\n        {\n            op.Request.AddAttributeIfNotExists(new ValidateRequestAttribute(\"IsAuthenticated\"), \n                x =\u003e x.Validator == \"IsAuthenticated\");\n        }\n    },\n    //Don't generate the Services or Types for Ignored Tables\n    IncludeService = op =\u003e !ignoreTables.Any(table =\u003e op.ReferencesAny(table)) \u0026\u0026\n        !(op.IsCrudWrite() \u0026\u0026 readOnlyTables.Any(table =\u003e op.ReferencesAny(table))),\n}\n```\n\nClicking on any of the **Auth** icons or the **Sign In** button on the top right will open up the Sign In dialog.\n\n### Integrated Auth Component\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/auth.png)\n\nThe **Sign In** dialog supports most of ServiceStack's built-in Auth Providers with a different Auth Dialog tab depending which Auth Providers are enabled. \nIt looks at \"auth family type\" to determine how to Authenticate with each Auth Provider so it should still support your Custom Auth Providers if they inherit from existing Auth Providers, otherwise they can explicitly specify which Type of Auth they use by overriding the `Type` property getter with one of the following:\n\n  - **Bearer** - Authenticate with HTTP Authentication Bearer Token (e.g. JWT or API Key)\n  - **credentials** - Authenticate with Username/Password at `/auth/credentials`\n  - **oauth** - Authenticate with OAuth\n  - **session** - Alternative [session-based Auth Provider](https://docs.servicestack.net/authentication-and-authorization#session-authentication-overview)\n\nThe **session** tab is also displayed if a `credentials` or `auth` provider is enabled. It should serve as a fallback Auth option if your Custom Auth Provider doesn't fit into the existing family types as it opens the `/auth` page of the remote ServiceStack instance:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/auth-session.png)\n\nWhere you can login to the remote site via the new fallback `/login` page or uses your custom Login Page if exists. If your remote instance is configured to allow Studio CORS access, i.e:\n\n```csharp\nappHost.Plugins.Add(new CorsFeature(allowOriginWhitelist:new[]{ \"https://localhost:5002\" }));\n```\n\nClicking on the **copy** button will then be able to post the session Id back to Studio \u0026 close the auth popup otherwise you'd need to \nmanually close the popup and paste the session in.\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/auth-session-copy.png)\n\nThe **OAuth** tab is a little different since it requires an OAuth redirect and since most 3rd Party OAuth providers disallow embedding in iframes,\nit needs to popup an external url in your default browser which still provides a nice auth UX as you'd typically already be Signed In with your \nDefault browser, where it will redirect you back to your `/auth` page where you can copy either the **Session Id** or the OAuth **Access Token** \nif you enable including OAuth Access Tokens in your `AuthenticateResponse` DTO with:\n\n```csharp\nappHost.Plugins.Add(new AuthFeature(...) {\n    IncludeOAuthTokensInAuthenticateResponse = true, // Include OAuth Keys in authenticated /auth page\n});\n```\n\nThis allows you to [Authenticate via OAuth Access Token](https://docs.servicestack.net/authentication-and-authorization#authentication-via-oauth-accesstokens) where you can test \nthe same Authentication that Mobile and Desktop using pre-existing Sign In Widgets who also authenticate via OAuth Access Tokens obtained by their native UI widget:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/auth-page.png)\n\n**Studio** is able to provide a seamless UX where it's able to monitor the Windows clipboard for changes \u0026 when detected close the window, return focus back to Studio who uses it to automatically Sign In with the copied token.\n\n### Desktop User State \u0026 Preferences\n\nAs is expected from a normal Desktop App, the User State of the App is preserved across restarts, which Studio maintains in its `$HOME/.servicestack/studio/site.settings` JSON file which preserves amongst other things what remote ServiceStack instances you've connected to \u0026 last queries made on each table, etc. When \nnot running in a Desktop App it will save it to your browsers `localStorage`. You can force a save with `Ctrl+S` or by clicking on the **save icon** on the top right.\n\n### AutoCrud Querying\n\nThe same querying behavior, supported filters, custom fields, paging, order by's, etc. demonstrated in **SharpData** above are also available in **Studio**, but implemented differently, where instead of calling the SharpData API directly, the filters are translated into the equivalent AutoQuery request and \nthe remote AutoQuery Services are called instead, but as they both result in the same UX and end result, users knowledge is transferable:\n\n#### Search Filters\n\n - Use `=null` or `!=null` to search `NULL` columns\n - Use `\u003c=`, `\u003c`, `\u003e`, `\u003e=`, `\u003c\u003e`, `!=` prefix to search with that operator\n - Use `,` trailing comma to perform an `IN (values)` search (integer columns only)\n - Use `%` suffix or prefix to perform a `LIKE` search\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-query-filters.png)\n\n### Export to Excel\n\nLikewise the fast, direct export into Excel is also available, one difference is that the total results returned in a query is controlled by the remote ServiceStack AutoQuery plugin whereas **SharpData** allows for unlimited sized queries:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-excel.png)\n\n### AutoCrud Partial Updates\n\nThe UI is designed to look similar to a generic RDBMS Admin UI Table Editor where you can edit records in a table grid. If a `IPatchDb\u003cTable\u003e` AutoQuery Service exists for the Data Model \u0026 the Authenticated User has access to it. \n\nIf enabled all fields (excl PK) on that Request DTO will be editable in the UI, otherwise they'll appear Read-only like the **Id** column:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-crud-partial.png)\n\n### AutoCrud Create\n\nIf the user has access to the `ICreateDb\u003cTable\u003e` Service they'll be able to add records by clicking the *+* icon on the top-right of the resultset which brings up the Create Entity modal:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-crud-create.png)\n\n### AutoCrud Update and Delete\n\nIf the user has access to the `IUpdateDb\u003cTable\u003e` Service they'll be able to update records by clicking on the **edit** icon which will bring up the Edit Entity dialog. If they have access to the `IDeleteDb\u003cTable\u003e` Service they'll also be able to delete the entity from the same screen:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-crud-update.png)\n\n### API Log Viewer\n\nAll API Requests the UI makes to remote ServiceStack instances are made via a generic .NET Core back-end Service Proxy which attaches the Signed In Authentication Info to each Request. Each API Request Studio makes is recorded in the log viewer at the bottom, showing the Verb and Parameters each API was called with:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-request-log.png)\n\n\u003e You can copy the URL from **GET** API Requests or open them up in a new browser to view it in isolation. \n\n### Executable Audit History\n\nIf you Sign In as the **Admin** User (i.e. using `AuthSecret=zsecret`) you'll get super user access to access the other protected features like being able to view an **Audit History** of updates made to each record via AutoQuery that's enabled in **NorthwindCrud** with:\n\n```csharp\n// Add support for auto capturing executable audit history for AutoCrud Services\ncontainer.AddSingleton\u003cICrudEvents\u003e(c =\u003e new OrmLiteCrudEvents(c.Resolve\u003cIDbConnectionFactory\u003e()));\ncontainer.Resolve\u003cICrudEvents\u003e().InitSchema();\n```\n\nWhere users in the `AutoQueryFeature.AccessRole` (default: Admin) role will be able to view the Audit history of each row:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-audit.png)\n\n\u003e If creating \u0026 deleting an entity with the same Id, the Audit History of the previous entity will be retained \u0026 visible\n\n### Validators UI\n\nAs an **Admin** you'll also have access to the [DB Validation Source](https://forums.servicestack.net/t/autocrud-preview/8298/29?u=mythz) Admin UI which will let you add declarative Type and Property Validators for each Request DTO in Studio. This is enabled in NorthwindCrud in [Configure.Validation.cs](https://github.com/NetCoreApps/NorthwindCrud/blob/master/Configure.Validation.cs):\n\n```csharp\n// Add support for dynamically generated db rules\nservices.AddSingleton\u003cIValidationSource\u003e(c =\u003e \n    new OrmLiteValidationSource(c.Resolve\u003cIDbConnectionFactory\u003e()));\n\n//...\nappHost.Plugins.Add(new ValidationFeature());\nappHost.Resolve\u003cIValidationSource\u003e().InitSchema();\n```\n\nManagement of this feature is limited to users in the `ValidationFeature.AccessRole` (default: Admin).\n\nClicking on the Validation **Lock Icon** on the top right will take you to the Validation Editor for that AutoQuery Request DTO which will include quick links to jump to different AutoQuery/Crud Services for the same Data Model.\n\nIn the validation editor you'll be able to create **Type** and **Property** Validation Rules that either make use of an existing **Validator** or you can enter a custom `#Script` expression that must validate to `true`. The Validator UI is smart and will list all built-in and Custom Script Methods returning `ITypeValidator` or `IPropertyValidator` that's registered in the remote instance. The pre-defined list of validators are displayed in a list of \"quick pick\" buttons that enables fast adding/editing of validation rules.\n\n#### Verified Rules\n\nThe `ModifyValidationRules` Service that Studio calls performs a lot of validation to ensure the Validation rule is accurate including executing the validator to make sure it returns the appropriate validator type and checking the syntax on any **Script** validation rules to ensure it's valid.\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-validator-property.png)\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-db-validators.png)\n\nThe `ModifyValidationRules` back-end Service also takes care of invalidating the validation rule cache so that any saved Validators are immediately applied. \n\nDespite being sourced from a DB, after the first access the validation rules are cached in memory where they'd have similar performance to validators declaratively added on Request DTOs in code.\n\nAfter you add your validation rules you will be able to click the **AutoQuery** icon on the top right to return to the AutoQuery editor. Be mindful of what Validation Rule you're adding to which DTO, e.g. a validation rule added to **CreateCategory** Service will only be applied to that Service which is used when creating entities, e,g. not for full entity or partial field updates.\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/studio-validators-create.png)\n\n### Metadata App Export / Discovery\n\nThe way a generic capability-based Admin UI's like Studio is possible is via the `/metadata/app` API descriptor which describes what plugins and features are enabled on the remote ServiceStack instance. All built-in plugins which provide functionality that can be remotely accessed add their info to the App's metadata. \n\nThis functionality is also available to your own plugins should you wish to attach info about your plugin where you can use the `AddToAppMetadata` extension method to return a populated `CustomPlugin` DTO describing the features made available by your plugin:\n\n```csharp\npublic class MyPlugin : IPlugin\n{\n    public void Register(IAppHost appHost)\n    {\n        appHost.AddToAppMetadata(meta =\u003e {\n            meta.CustomPlugins[nameof(MyPlugin)] = new CustomPlugin {\n                AccessRole = RoleNames.AllowAnyUser,                   // Required Role to access Services\n                ServiceRoutes = new Dictionary\u003cstring, string[]\u003e {\n                    { nameof(MyPluginService), new[] { \"/myplugin/{Id}\" } }, // Available Plugin Services\n                },\n                Enabled = new List\u003cstring\u003e { \"feature1\", \"feature2\" }, // What plugin features are enabled\n                Meta = new Dictionary\u003cstring, string\u003e {\n                    [\"custom\"] = \"meta\" // additional custom metadata you want returned for this plugin\n                }\n            };\n        });\n    }\n}\n```\n\n### Studio Desktop App vs ServiceStack.Admin\n\nThe primary limitations with [ServiceStack Admin](https://github.com/ServiceStack/Admin) was its deployment model where it had to be explicitly registered as a plugin in each ServiceStack instance, this means it could only be used on ServiceStack instances that explicitly had it registered, also it maintained the long release cadence of ServiceStack major releases which means the UI couldn't be updated frequently resulting in a stale long feedback loop.\n\n### Frequent out-of-band release cadence\n\nTo overcome this ServiceStack Studio is delivered as a [Gist Desktop App](https://sharpscript.net/docs/gist-desktop-apps) which, like a website will be running the latest version each time it's run. To reduce its download footprint the `app` and `x` dotnet tools now include the new [ServiceStack.Desktop](https://github.com/ServiceStack/ServiceStack/tree/master/src/ServiceStack.Desktop) project which includes the common framework libraries that most Vue \u0026 React Apps use which saves it from needing to be included in each Download. It also includes Google Material Design Icons SVGs \u0026 a copy of [fontawesome free icons](https://fontawesome.com/how-to-use/on-the-web/setup/hosting-font-awesome-yourself) that all Desktop Apps will be able to use without the bandwidth cost for using them.\n\n### Light Footprint + Always use latest version\n\n[ServiceStack/Studio](https://github.com/ServiceStack/Studio) is a [vue-lite](https://github.com/NetCoreTemplates/vue-lite) App that only uses SVG icons as they're small, high-quality at every scale, are customizable \u0026 have built-in css classes making them easy to use declaratively where it takes advantage of [ServiceStack's built-in SVG](https://docs.servicestack.net/svg) support which allows optimal css bundles containing only the SVGs your App's use. All SVG icons used in Studio are defined in its [_init.ss](https://github.com/ServiceStack/Studio/blob/master/wwwroot/_init.ss) startup script which defines which Material Design SVG to make available under which css bundle. It also registers its own custom SVG icons not contained in ServiceStack.Desktop's embedded resources and includes them as part of its `/css/app.css` bundle.\n\nAs a result of its architecture Studio gets bundled down to a **55kb .zip** which includes its 46kb (Uncompressed) `Studio.dll` plugin containing all its C# back-end logic (thanks to all ServiceStack .dll's being deployed with the dotnet tools as well). As it's [published as a Gist](https://gist.github.com/gistlyn/d8e7a56027ed6ec3060d9a9896931909) it adds a bit more overhead (and Gist APIs aren't particularly fast) so there's a slight delay in loading from a Gist but still is able to load its home page in around **2-3s**, which includes the start time of the ServiceStack .NET Core App and the Chromium CEF Browser. The number of restarts should be minimal thanks to Studio being designed as a single UI to manage all your ServiceStack instances so you can reuse the same running Desktop App to manage multiple remote ServiceStack instances.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fservicestack%2Fstudio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fservicestack%2Fstudio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fservicestack%2Fstudio/lists"}