Portal Community

System Architecture Overview

App Studio is composed of two major layers:

Zero Direct Database Access

App Studio has no DbContext and no Repository classes. Every read and write operation goes through IAppStudioService in the AIExtension.Service layer. This is a deliberate architectural constraint that enforces multi-tenant isolation, caching, and audit logging.

Frontend Package Structure

The App Studio frontend is built as composable TypeScript packages within the BizFirstAiStudio monorepo. Key functional areas:

AreaResponsibilityKey Files
Builder ShellThree-panel layout, toolbar, keyboard shortcutsBuilderLayout.tsx, BuilderToolbar.tsx
App TreeLeft panel tree view — AppPages, Panes, Widgets hierarchyAppTree.tsx, AppTreeStore.ts
CanvasLive preview pane — renders the selected AppPageCanvas.tsx, CanvasRenderer.ts
Properties EditorRight panel — context-sensitive property formsPropertiesPanel.tsx, PropertyForm.tsx
Widget RegistryCatalog of available widget types and their schemasWidgetRegistry.ts, WidgetDefinition.ts
Token ResolverEvaluates {{ }} expressions at render timeTokenResolver.ts, AppVariable.ts
Action ExecutorRuns actions triggered by widget eventsActionExecutor.ts, ActionConfig.ts
Layout EngineBreakpoint-aware grid/flex layout calculationLayoutEngine.ts, BreakpointConfig.ts
NavigationSidebar config, URL routing, route-to-variable wiringNavigationConfig.ts, RouteConfig.ts
PermissionsRole-based visibility rule evaluationPermissionsConfig.ts, VisibilityRuleEvaluator.ts
Custom JS SandboxIsolated JS execution environmentCustomJSSandbox.ts, SandboxedJSExecutor.ts
Export/ImportApp bundle serialization and deserializationAppExporter.ts, AppImporter.ts

Backend Service Layer

The C# backend for App Studio is organized under mvc-server/AppStudio/ in the BizFirstPayrollV3 solution:

ComponentResponsibility
IAppStudioServiceService contract — all App Studio backend operations
AppStudioDataServiceImplementation in AIExtension — handles caching, multi-tenancy, audit
AppControllerREST API endpoints for app CRUD, publish, export, import
WidgetServiceWidget definition storage and retrieval
AppExportServiceBuilds the JSON export bundle
AppImportServiceValidates and imports a JSON bundle
AppAccessCheckerServer-side enforcement of app-level role permissions
WorkflowTriggerActionHandlerExecutes trigger-workflow actions via Flow Studio API

Data Flow

// Builder save flow
Builder (TypeScript)
  └─► PUT /api/apps/{id}
        └─► AppController.SaveApp()
              └─► IAppStudioService.SaveAppAsync()
                    └─► AIExtension.AppStudioDataService
                          ├─► Validate multi-tenant isolation
                          ├─► Write to AIExtension tables
                          ├─► Invalidate Redis cache
                          └─► Write audit log entry

// Runtime data fetch flow
Published App (TypeScript runtime)
  └─► GET /api/apps/{id}/data?source=GetLeads
        └─► AppController.GetData()
              └─► IAppStudioService.GetGridDataAsync(query)
                    └─► AIExtension.AppStudioDataService
                          ├─► Check Redis cache
                          ├─► Query backing data (via platform services)
                          └─► Return typed result rows

Multi-Tenant Isolation

App Studio enforces tenant isolation at the service layer — not in the controller. Every IAppStudioService method receives the current tenantId from the authenticated request context. Apps are always scoped to a tenant — a user from Tenant A cannot access apps from Tenant B.

Caching Strategy

App definitions (the JSON config of an app) are cached in Redis by AppStudioDataService: