Development Documentation
View as:

Hybrid portal — May 2026: The cloud portal at /dashboard is the canonical entry point for every developer. Read-only views (feature envs, PRs, pipelines, audit, agents) and cloud-side writes (provision, deploy, refresh, teardown, cherry-pick, RBAC) run server-side under the platform-admin SPN — zero local install required. The Fabric Dev tray app described below is only needed when you need to edit code locally (TMDL, dbt models) or run things against local DuckDB. See the canonical developer journey below.

Developer Dashboard

The Developer Dashboard is split in two halves: the cloud portal at /dashboard (Entra-gated, always on) and the local Fabric Dev tray app that owns the loopback FastAPI UI and handles fabric-dev:// deep links from the cloud side.

What it does

The dashboard gives you all feature environments at a glance (status, branch, profile, age), typed forms with validation for every scripts/fabric subcommand (provision, teardown, deploy, refresh, cherry-pick, and more), a cherry-pick queue for promoting commits across environment branches, a Jobs tray that streams live stdout/stderr from any running script, and access that is gated via the FP GER Develop Entra group — the same group required to run the CLI directly.

Canonical developer journey (Day 0 → Day 4)

This is the v1 acceptance flow from the hybrid portal spec §9.

DayStepCloud URLRuns where
0IT adds you to FP GER Develop. Open the portal. Live grid of every feature env. Zero install./dashboardCloud
1Click New feature env. Choose profile + developers + seed strategy, submit. ~90 s to provision Fabric workspaces under the platform-admin SPN. Progress visible in Runs./feature-envs/newCloud
2On the env detail page, click Open locally. Browser dispatches fabric-dev://open-feature?slug=... to the tray; tray creates a git worktree and opens VS Code. Edit TMDL / dbt models./feature-envs/detail?slug=…Cloud → tray → editor
2 (later)Push the feature branch. Click Deploy (scope: Both) on the detail page. fabric-cicd runs cloud-side; log streams in-page./feature-envs/detail?slug=…Cloud
3In the worktree: dbt build --target local against DuckDB for bronze→gold modelling. Tray heartbeat appears at /operations/agents.Local (tray)
4Approve + merge the PR. Teardown on the detail page cleans up workspaces. Tray's fabric-dev://teardown-local?slug=... removes the local worktree (after OS confirm)./feature-envs/detail?slug=…Cloud → tray

Onboarding (3 steps)

1. Sign in to the cloud portal

Visit /dashboard and sign in with your Geris Entra account. You can already use every read-only view and every cloud-side action (provision, refresh, deploy, teardown, cherry-pick) from any browser — phone included.

2. Install the Fabric Dev tray app (only when you need to edit locally)

See Local Tray App for the MSIX install steps. After install:

  • The tray icon (blue "F") starts at every login.
  • fabric-dev: URLs from the portal are dispatched automatically.
  • Click Sign in (az login) in the tray menu once to register your Entra session.

The tray bundles the existing loopback dashboard (formerly scripts/fabric-ui.cmd) and the fabric-dev:// URL handler in one MSIX. The legacy pip install -r requirements.txt + double-click fabric-ui.cmd flow is retired.

3. Optional — clone the repo for dbt/TMDL editing

git clone https://geris-devops@dev.azure.com/geris-devops/insights-requests/_git/fabric_monorepo
cd fabric_monorepo

On first fabric-dev:// click that needs a worktree, the tray app prompts you for this path and persists the choice at %APPDATA%/fabric-dev/config.json (Windows) / ~/Library/Application Support/fabric-dev/ (macOS) / ~/.config/fabric-dev/ (Linux).

How to add a new command

The loopback UI served by the tray app at http://127.0.0.1:8765 is separate from the cloud portal. Commands in the local UI are declared in scripts/fabric_ui/jobs/registry.py and are NOT the same as cloud portal API routes. The legacy fabric-ui.cmd launcher is fully retired — the tray app owns the loopback UI lifecycle now. See Local Tray App.

All local dashboard commands are declared in scripts/fabric_ui/jobs/registry.py. Add a new Command entry to the REGISTRY list:

from scripts.fabric_ui.jobs.registry import Command, Arg, REGISTRY

REGISTRY.append(
    Command(
        name="my-command",
        label="My new command",
        script=["bash", "scripts/my_script.sh"],
        args=[
            Arg("feature", "feature-picker", required=True, positional=True,
                help="Target feature environment."),
            Arg("mode", "enum", required=True, cli_flag="--mode",
                choices=("fast", "full")),
        ],
        lock_key=lambda args: f"feature:{args.get('feature', '_unknown')}",
        exclusive=True,
        destructive=False,
        contributor_required=True,
        help="Short description shown in the form header.",
    )
)

The dashboard picks up the new entry on next launch — no template changes needed. Argument types available:

TypeRendered as
stringFree-text input
feature-pickerDropdown populated from live environment list
enumSelect with fixed choices
upn-chipsMulti-value UPN input (email addresses)
fileFile picker
flagCheckbox

Set destructive=True to require the user to type the feature name as confirmation before the form submits.

Security

  • Loopback only. uvicorn binds to 127.0.0.1 — the dashboard is never reachable from the network.
  • CSRF protection. Every state-changing request requires a session-scoped CSRF token set by the launcher.
  • Host / Origin allowlist. The server rejects requests whose Host or Origin header is not localhost:8765 or 127.0.0.1:8765, blocking DNS-rebinding attacks.
  • az gate. On every form submission the server calls az account show to verify an active session and then checks the caller's Entra group membership (FP GER Develop) via Microsoft Graph. Cached for 15 minutes; force_auth_recheck=True commands bypass the cache.
  • No git writes. The dashboard never commits, pushes, or modifies any file in the repository. All mutations happen through the same scripts the CLI calls.

Related Pages