2026-04-25 19:04:42 +02:00
2026-04-25 19:04:42 +02:00
2026-04-12 13:47:27 +02:00
2026-04-09 22:16:22 +02:00
2026-04-12 18:13:26 +02:00
2026-04-25 18:09:02 +02:00
2026-04-09 22:16:22 +02:00
2026-04-10 21:56:31 +02:00
2026-04-09 22:16:22 +02:00
2026-04-12 18:13:26 +02:00
2026-04-09 22:16:22 +02:00
2026-04-10 21:56:31 +02:00
2026-04-11 12:21:34 +02:00
2026-04-11 12:21:34 +02:00
2026-04-09 22:16:22 +02:00
2026-04-09 22:16:22 +02:00
2026-04-09 22:16:22 +02:00

PieCed Portal

Customer self-service portal for the PieCed IT multi-tenant OpenClaw platform.

Stack

Layer Choice
Framework Next.js 15 LTS (App Router, standalone output, Turbopack)
Auth NextAuth v5 + ZITADEL OIDC (CODE flow)
Tenant mgmt Direct K8s API → PiecedTenant CRs (Option A)
Usage data LiteLLM /team/info + /global/spend/logs
i18n next-intl 4.x (en/de)
Styling Tailwind CSS 4
Deployment Container in pieced-system, exposed at app.pieced.ch

Setup

1. ZITADEL Application

In ZITADEL console (auth.pieced.ch), project "OpenClaw Platform":

  1. Create Application → PieCed Portal → Web → Authentication Method: CODE
  2. Redirect URI: https://app.pieced.ch/api/auth/callback/zitadel
  3. Post-logout URI: https://app.pieced.ch/login
  4. Note Client ID and Client Secret

2. OpenBao Secrets

bao kv put pieced/portal/oidc \
  client_id="<from step 1>" \
  client_secret="<from step 1>" \
  nextauth_secret="$(openssl rand -base64 32)"

3. Build & Push

docker build -t registry.c5ai.ch/pieced/pieced-portal:0.1.0 .
docker push registry.c5ai.ch/pieced/pieced-portal:0.1.0

Update image tag in pieced-gitops/apps/portal/deployment.yaml, push, ArgoCD syncs.

4. DNS

Ensure app.pieced.ch A record → MetalLB ingress IP (or ExternalDNS handles it).

Local Development

cp .env.example .env.local
# Fill in values — K8s client uses ~/.kube/config locally
npm install
npm run dev

Project Structure

src/
├── app/
│   ├── api/
│   │   ├── auth/[...nextauth]/route.ts   # NextAuth handler
│   │   ├── tenants/route.ts              # Tenant CRUD (K8s API)
│   │   └── usage/route.ts                # Usage stub
│   ├── [locale]/
│   │   ├── layout.tsx                    # Locale layout + NavShell
│   │   ├── page.tsx                      # Redirect → /dashboard
│   │   ├── login/page.tsx                # ZITADEL sign-in
│   │   ├── dashboard/page.tsx            # Customer dashboard
│   │   └── admin/page.tsx                # Platform admin tenant list
│   ├── layout.tsx                        # Root layout
│   └── globals.css                       # Tailwind 4 theme
├── components/
│   ├── layout/nav-shell.tsx              # Header + navigation
│   └── ui/                               # Reusable UI components
├── i18n/
│   ├── routing.ts                        # next-intl 4.x routing config
│   ├── navigation.ts                     # Localized Link, redirect, etc.
│   └── request.ts                        # Server-side i18n config
├── lib/
│   ├── auth.ts                           # NextAuth v5 + ZITADEL config
│   ├── k8s.ts                            # K8s client for PiecedTenant CRs
│   ├── litellm.ts                        # LiteLLM API client
│   └── session.ts                        # Session helpers
├── messages/
│   ├── en.json
│   └── de.json
└── types/index.ts                        # Shared TypeScript types

Session Roadmap

  • 6.1 ← This session: scaffold, auth, basic pages
  • 6.2: Instance management, package config, usage display
  • 6.3: Onboarding flow (create ZITADEL org → PiecedTenant CR)
  • 6.4: Workspace editor (SOUL.md, AGENTS.md, TOOLS.md)
  • 6.5: Admin panel (tenant lifecycle, billing overview)
Description
No description provided
Readme 7 MiB
Languages
TypeScript 95.2%
JavaScript 3.5%
Shell 1%
CSS 0.2%