Groundfloor Docs

Getting Started

End-to-end tutorial from app registration to loading a federated remote in the Shell host.

Audience: Shell host + federated remote developers
Time: ~1–2 hours first run (excluding Control Plane stack setup)

This walkthrough takes you from zero to a published federated app loaded by the Shell host, calling Control Plane APIs with IdPlane auth.


What you will build

Portal (register app + publish remoteEntry.js)

Control Plane (manifest + bootstrap API)

Shell host (loads remote via Module Federation)

Federated remote (your React pages + optional API calls)

Prerequisites

Infrastructure (usually already running for your team)

ComponentDefault URLNotes
Control Plane APIhttp://localhost:8088make compose-up in groundfloor-client-portal
Customer Portalhttp://localhost:3000npm run dev:customer
IdPlanehttps://auth.groundfloor.cloudPlatform realm; see .env.example
Dataplanehttp://localhost:8080Sibling repo groundfloor-dataplane-oss
MinIO (files / publish)http://localhost:9000Phase 2 deps compose profile

Optional for LLM/secrets locally: Infisical + LiteLLM — see Phase 2 deps runbook.

Repos / downloads

SourceRole
groundfloor-client-portalControl Plane + Portal (register/publish)
Shell starter-kit ZIPFederated remote template — download from Portal → Apps → your Shell app → Download starter-kit
Shell host (optional locally)Loads published remotes; not required to build/publish a remote

You do not need the private Shell monorepo to create a Shell app.

Access

  • IdPlane user with access to a workspace (member with at least read)
  • Workspace UUID (from Portal URL: /workspaces/{uuid}/…)

Step 1 — Register the app (Portal)

  1. Sign in to the Customer Portal with IdPlane.
  2. Open a workspace → AppsRegister app.
  3. Set:
    • Name: e.g. My Federated App
    • Slug: e.g. my-federated-app (URL-safe, unique per workspace)
    • Kind: Shell (federated)
  4. Paste a manifest (minimum viable):
{
  "version": "1.0",
  "appId": "my-federated-app",
  "name": "My Federated App",
  "routes": [
    { "path": "home", "title": "Home", "icon": "Home", "layout": [] }
  ],
  "theme": {
    "primaryColor": "#2563EB",
    "accentColor": "#7C3AED",
    "mode": "light"
  },
  "remoteUrl": ""
}
  1. Save. Note app id (UUID) and slug on the app detail page.

See 09-manifest-and-routes.md for field details.


Step 2 — Build the federated remote (starter-kit)

  1. In Customer Portal, open your Shell app → Download starter-kit (ZIP).
  2. Unzip and install:
unzip shell-starter-kit-*.zip
cd shell-starter-kit
npm install   # or pnpm install
  1. Match Portal:
    • Set appId in groundfloor.manifest.json to this app’s slug (same as Portal manifest).
    • Set APP_ID in vite.config.ts to the same value.
    • Align routes[] with pages under src/.
  2. Build a Portal-ready bundle:
npm run release
# → release.zip with remoteEntry.js at the zip root

What is remoteEntry.js?

You do not create or edit this file by hand. It is the Module Federation entry produced by Vite when you build the starter-kit:

After…Where it appearsWhat it is
npm run build / npm run releasedist/assets/remoteEntry.jsBundled JS the Shell host loads
npm run release (recommended)Also copied to release/remoteEntry.js and packed into release.zip at the zip rootWhat you upload in Portal → Releases

Confirm it exists:

ls dist/assets/remoteEntry.js   # after build
ls release/remoteEntry.js       # after npm run release
unzip -l release.zip | head     # should list remoteEntry.js at top level

Contents: minified/bundled JavaScript (federation bootstrap + your src/App.tsx graph). Treat it like main.js from any SPA build — inspect in DevTools if needed; do not hand-author it. Your editable source is src/ + groundfloor.manifest.json + vite.config.ts.

  1. For local Shell host testing without publishing, run npm run dev (serves http://localhost:4175/assets/remoteEntry.js) or npm run preview:release, and set SHELL_REMOTE_DEV_URL on the Shell host to that URL.

Step 3 — Configure the Shell host

Set environment variables (.env.local or deploy config):

CONTROLPLANE_URL=http://localhost:8088
SHELL_WORKSPACE_ID=<workspace-uuid-from-portal>
SHELL_REMOTE_DEV_URL=http://localhost:3002/remoteEntry.js   # optional until published

IdPlane (Shell host browser client):

NEXT_PUBLIC_IDPLANE_URL=https://auth.groundfloor.cloud
NEXT_PUBLIC_IDPLANE_REALM=groundfloor_dev
NEXT_PUBLIC_IDPLANE_CLIENT_ID=groundfloor-portal   # or dedicated Shell client
NEXT_PUBLIC_API_URL=http://localhost:8088

Ensure the Shell client's id is listed in Control Plane IDPLANE_AUDIENCE.

Wire bootstrap on layout load — see 02-shell-bootstrap.md.


Step 4 — Publish the remote (Portal)

  1. Portal → workspace → your app → Releases / Publish build.
  2. Upload remoteEntry.js or a .zip with remoteEntry.js at the zip root.
  3. Wait for finalize; confirm build number and remote URL on app detail.

Verify bootstrap (no auth):

export CONTROLPLANE_URL=http://localhost:8088
export WORKSPACE_ID=<uuid>
export APP_SLUG=my-federated-app

curl -s "${CONTROLPLANE_URL}/v1/public/workspaces/${WORKSPACE_ID}/apps/by-slug?slug=${APP_SLUG}" \
  | jq '{slug, remoteUrl: .manifest.remoteUrl, build: .release.build_number}'

manifest.remoteUrl must be non-empty after publish.


Step 5 — Load in Shell

  1. Start Shell host dev server.
  2. Open /apps/my-federated-app/home (or your Shell's route convention).
  3. Shell should:
    • Fetch bootstrap JSON
    • Load remoteEntry.js from manifest.remoteUrl
    • Render your federated page inside the Shell chrome

If unpublished, Shell falls back to SHELL_REMOTE_DEV_URL.


Step 6 — Call Control Plane from your remote (optional)

  1. Obtain IdPlane token from Shell auth context — 03-authentication.md.
  2. Configure @groundfloor/api-client:
import { configureControlPlaneClient, setControlPlaneAuthProvider } from "@groundfloor/api-client";

configureControlPlaneClient({ baseURL: process.env.NEXT_PUBLIC_API_URL });
setControlPlaneAuthProvider(async () => getAccessToken()); // Shell / IdPlane auth helper
  1. Try a read-only call, e.g. list vault collections or secrets keys:
// GET /v1/workspaces/{id}/vault/collections

For LLM: mint virtual key (admin) → store in Secrets → call LiteLLM — 07-llm-gateway.md.


Checklist

StepDone?
App registered (shell_federated)
Manifest validates (routes, theme, appId)
Remote builds to remoteEntry.js
Published at least once
Bootstrap curl returns remoteUrl
Shell env: CONTROLPLANE_URL, SHELL_WORKSPACE_ID
Shell loads federated route
IdPlane token reaches Control Plane APIs (optional)

Next steps

GoalDocument
Bootstrap details02-shell-bootstrap.md
Auth wiring03-authentication.md
Customer data04-data-vault.md
File uploads05-files.md
Secrets / LLM06-secrets.md, 07-llm-gateway.md
curl recipes11-local-dev-recipes.md
When things break12-troubleshooting.md

Control Plane dev stack (maintainers)

If you need to run Control Plane itself from source:

cd groundfloor-client-portal
make install && npm install && npm run codegen
docker compose -f deploy/docker-compose.phase2-deps.yml --profile all up -d
make e2e-up
make compose-up
npm run dev:customer
curl http://localhost:8088/health

See repo README.md for full details.

On this page