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 Keycloak 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
Keycloakhttps://dev-auth.groundfloor.coPlatform 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

RepoRole
groundfloor-client-portalControl Plane + Portal (register/publish)
groundfloor-v2.5Shell host + starter-kit remote template

Access

  • Keycloak 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 Keycloak.
  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 (Shell starter-kit)

In groundfloor-v2.5/starter-kit (or your fork):

pnpm install   # or npm install
  1. Set appId and routes in groundfloor.manifest.json to match Portal (same appId as manifest).
  2. Implement pages under src/ matching routes[].path.
  3. Build:
pnpm run build
# Output: dist/assets/remoteEntry.js (path may vary — confirm in build output)
  1. For local Shell dev without publishing, run the remote dev server if your template provides one, and set SHELL_REMOTE_DEV_URL on the Shell host.

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

Keycloak (Shell host browser client):

NEXT_PUBLIC_KEYCLOAK_URL=https://dev-auth.groundfloor.co
NEXT_PUBLIC_KEYCLOAK_REALM=groundfloor_dev
NEXT_PUBLIC_KEYCLOAK_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 KEYCLOAK_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 Keycloak 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 () => {
  await keycloak.updateToken(30);
  return keycloak.token ?? null;
});
  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
Keycloak 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