Files

14 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
03-operator-experience 02 execute 2
03-01
packages/portal/app/api/slack/callback/route.ts
packages/portal/app/(dashboard)/onboarding/page.tsx
packages/portal/app/(dashboard)/onboarding/steps/connect-channel.tsx
packages/portal/app/(dashboard)/onboarding/steps/configure-agent.tsx
packages/portal/app/(dashboard)/onboarding/steps/test-message.tsx
packages/portal/app/(dashboard)/settings/api-keys/page.tsx
packages/portal/lib/queries.ts
packages/portal/components/onboarding-stepper.tsx
false
PRTA-03
PRTA-04
LLM-03
truths artifacts key_links
Operator can click Add to Slack and complete OAuth flow to connect their workspace
Operator can paste WhatsApp credentials and have them validated and stored
After connecting a channel, operator can send a test message that verifies end-to-end connectivity
Agent goes live automatically after test message succeeds
Operator completes the full onboarding sequence (connect -> configure -> test) in a guided wizard
Operator can add, view, and delete BYO LLM API keys from a settings page
path provides
packages/portal/app/api/slack/callback/route.ts Next.js Route Handler for Slack OAuth redirect
path provides
packages/portal/app/(dashboard)/onboarding/page.tsx Onboarding wizard with 3-step stepper
path provides
packages/portal/app/(dashboard)/settings/api-keys/page.tsx BYO API key management page
from to via pattern
packages/portal/app/(dashboard)/onboarding/steps/connect-channel.tsx /api/portal/channels/slack/install fetch to get OAuth URL, then window.location redirect channels/slack/install
from to via pattern
packages/portal/app/api/slack/callback/route.ts /api/portal/channels/slack/callback proxy the OAuth callback to FastAPI backend channels/slack/callback
from to via pattern
packages/portal/app/(dashboard)/onboarding/steps/test-message.tsx /api/portal/channels/{tenant_id}/test POST to send test message channels.*test
from to via pattern
packages/portal/app/(dashboard)/settings/api-keys/page.tsx /api/portal/tenants/{tenant_id}/llm-keys GET/POST/DELETE for BYO key CRUD (endpoints created in Plan 01 Task 3) tenants.*llm-keys
Channel connection wizard (Slack OAuth + WhatsApp manual setup), onboarding flow with 3-step stepper, and BYO API key management page.

Purpose: Operators can connect their messaging channels and onboard their AI employee through a guided wizard, plus manage their own LLM API keys -- all from the portal UI. Output: Onboarding wizard (connect channel -> configure agent -> test message), Slack OAuth callback handler, WhatsApp manual connect form, BYO key settings page.

<execution_context> @/home/adelorenzo/.claude/get-shit-done/workflows/execute-plan.md @/home/adelorenzo/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-operator-experience/03-CONTEXT.md @.planning/phases/03-operator-experience/03-RESEARCH.md @.planning/phases/03-operator-experience/03-01-SUMMARY.md

From packages/shared/shared/api/channels.py (created in Plan 01):

# GET /api/portal/channels/slack/install?tenant_id={id} -> { "authorize_url": "https://slack.com/oauth/v2/authorize?..." }
# GET /api/portal/channels/slack/callback?code={code}&state={state} -> { "success": true, "workspace_name": "..." }
# POST /api/portal/channels/whatsapp/connect -> { "success": true } (body: { tenant_id, phone_number_id, waba_id, system_user_token })
# POST /api/portal/channels/{tenant_id}/test -> { "success": true, "message": "Test message sent" } (body: { channel_type })

From packages/shared/shared/api/llm_keys.py (created in Plan 01 Task 3):

# GET /api/portal/tenants/{tenant_id}/llm-keys -> [{ id, provider, label, key_hint, created_at }]
# POST /api/portal/tenants/{tenant_id}/llm-keys -> { id, provider, label, key_hint, created_at } (body: { provider, label, api_key })
# DELETE /api/portal/tenants/{tenant_id}/llm-keys/{key_id} -> 204

From packages/shared/shared/api/billing.py (created in Plan 01):

# POST /api/portal/billing/checkout -> { "checkout_url": "https://checkout.stripe.com/..." }
# POST /api/portal/billing/portal -> { "portal_url": "https://billing.stripe.com/..." }

From packages/shared/shared/crypto.py (created in Plan 01):

class KeyEncryptionService:
    def encrypt(self, plaintext: str) -> str: ...
    def decrypt(self, ciphertext: str) -> str: ...
    def rotate(self, ciphertext: str) -> str: ...

From packages/portal/lib/api.ts:

// API client for FastAPI backend — use this for all portal API calls

From packages/portal/lib/queries.ts:

// TanStack Query hooks — add new hooks for channels, billing, usage here

Established patterns:

  • shadcn/ui components
  • react-hook-form + zod v4 + standardSchemaResolver
  • TanStack Query for data fetching
  • App Router with (dashboard) route group
  • proxy.ts for auth protection (Next.js 16 pattern)
Task 1: Slack OAuth callback route, onboarding wizard with 3-step stepper, and channel connection forms packages/portal/app/api/slack/callback/route.ts, packages/portal/app/(dashboard)/onboarding/page.tsx, packages/portal/app/(dashboard)/onboarding/steps/connect-channel.tsx, packages/portal/app/(dashboard)/onboarding/steps/configure-agent.tsx, packages/portal/app/(dashboard)/onboarding/steps/test-message.tsx, packages/portal/components/onboarding-stepper.tsx, packages/portal/lib/queries.ts 1. Create `packages/portal/app/api/slack/callback/route.ts`: - Next.js Route Handler (GET) that receives the OAuth redirect from Slack - Extract `code` and `state` from searchParams - Forward to FastAPI backend: GET /api/portal/channels/slack/callback?code={code}&state={state} - On success: redirect to /onboarding?step=2&channel=slack&connected=true - On error: redirect to /onboarding?step=1&error=slack_auth_failed
2. Create `packages/portal/components/onboarding-stepper.tsx`:
   - 3-step stepper component using shadcn/ui: "Connect Channel" -> "Configure Agent" -> "Test Message"
   - Visual progress indicator (numbered steps with active/complete/pending states)
   - Step state managed via URL searchParams (step=1|2|3) for shareable/refreshable URLs
   - Each step renders the corresponding step component

3. Create `packages/portal/app/(dashboard)/onboarding/page.tsx`:
   - Reads `step` from searchParams (default 1)
   - Reads `tenant_id` from session or query param
   - Renders OnboardingStepper with the appropriate step component
   - Guards: if no tenant selected, redirect to tenant selection

4. Create `packages/portal/app/(dashboard)/onboarding/steps/connect-channel.tsx`:
   - Two cards: "Add to Slack" and "Connect WhatsApp"
   - **Slack card:** Button that fetches /api/portal/channels/slack/install?tenant_id={id}, then does window.location.href = authorize_url (external redirect to Slack)
   - **WhatsApp card:** Expandable form with 3 fields (Phone Number ID, WhatsApp Business Account ID, System User Token) + step-by-step instructions text
     - On submit: POST /api/portal/channels/whatsapp/connect
     - Validation with zod + react-hook-form
   - On successful connection (either channel): advance to step 2 automatically
   - If returning from Slack OAuth (connected=true in searchParams): show success toast and advance

5. Create `packages/portal/app/(dashboard)/onboarding/steps/configure-agent.tsx`:
   - If tenant already has an agent: show existing agent summary with "Edit" link to Agent Designer
   - If no agent: redirect to Agent Designer page with return URL back to onboarding?step=3
   - Minimal step — the Agent Designer (from Phase 1) handles all agent configuration
   - "Next" button enabled only when at least one active agent exists for the tenant

6. Create `packages/portal/app/(dashboard)/onboarding/steps/test-message.tsx`:
   - Shows connected channel(s) with a "Send Test Message" button per channel
   - On click: POST /api/portal/channels/{tenant_id}/test with {channel_type}
   - Shows loading state while test runs, then success/failure result
   - On success: show "Your AI employee is live!" celebration message
   - Agent goes live automatically (is_active already true by default) — NO separate "Go Live" button per user decision
   - Per user decision: test message step is REQUIRED, not skippable

7. Add TanStack Query hooks to `packages/portal/lib/queries.ts`:
   - useSlackInstallUrl(tenantId) — GET /channels/slack/install
   - useConnectWhatsApp() — mutation POST /channels/whatsapp/connect
   - useSendTestMessage() — mutation POST /channels/{tenantId}/test
   - useChannelConnections(tenantId) — GET to list existing connections
cd /home/adelorenzo/repos/konstruct/packages/portal && npx next build 2>&1 | tail -20 - Slack OAuth callback route handler proxies to FastAPI and redirects appropriately - Onboarding page renders 3-step stepper with progress indicator - Connect Channel step shows Slack OAuth button and WhatsApp manual form - Configure Agent step links to existing Agent Designer - Test Message step sends test and shows result - Agent goes live automatically after successful test (no Go Live button) - All TanStack Query hooks defined - Portal builds without errors Task 2: BYO API key management settings page packages/portal/app/(dashboard)/settings/api-keys/page.tsx, packages/portal/lib/queries.ts 1. Create `packages/portal/app/(dashboard)/settings/api-keys/page.tsx`: - Tenant-level settings page (per user decision — simpler than per-agent for v1) - List existing BYO keys: show provider name, label, key_hint (last 4 chars), created date (NOT the key itself — never display decrypted keys) - "Add API Key" button opens a form: - Provider: select dropdown (OpenAI, Anthropic, Custom) - Label: text input (human-readable name, e.g., "Production OpenAI key") - API Key: password input (masked by default) - Submit: POST to /api/portal/tenants/{tenant_id}/llm-keys (backend endpoint created in Plan 01 Task 3) - Delete button per key with confirmation dialog - Use shadcn/ui Card, Table, Dialog, Button, Input, Select components - react-hook-form + zod for validation (provider required, label 3-100 chars, key not empty)
2. Add TanStack Query hooks to `packages/portal/lib/queries.ts`:
   - useLlmKeys(tenantId) — GET /api/portal/tenants/{tenant_id}/llm-keys
   - useAddLlmKey() — mutation POST /api/portal/tenants/{tenant_id}/llm-keys
   - useDeleteLlmKey() — mutation DELETE /api/portal/tenants/{tenant_id}/llm-keys/{keyId}

3. Add navigation link to settings/api-keys in the dashboard layout sidebar (if sidebar exists) or in the tenant detail page.
cd /home/adelorenzo/repos/konstruct/packages/portal && npx next build 2>&1 | tail -20 - BYO API key settings page renders with list of existing keys (redacted — shows key_hint only) - Add key form validates and submits to backend - Delete key with confirmation dialog works - Portal builds without errors Task 3: Verify onboarding wizard and BYO key management n/a Human verifies the onboarding wizard and BYO key management UI: 1. Start the portal: `cd packages/portal && npm run dev` 2. Navigate to /onboarding — verify 3-step stepper displays 3. Step 1: Verify "Add to Slack" button and WhatsApp form are present 4. Step 2: Verify it links to Agent Designer or shows existing agent 5. Step 3: Verify "Send Test Message" button is present 6. Navigate to /settings/api-keys — verify key list and add form render 7. Try adding a BYO key with the form — verify it submits without JS errors 8. Confirm there is NO separate "Go Live" button — agent goes live after test Human visual inspection of onboarding flow and settings page Operator confirms onboarding wizard works through all 3 steps and BYO key page renders correctly - Portal builds successfully: `cd packages/portal && npx next build` - Onboarding wizard navigable through all 3 steps - BYO API key page renders and accepts input - No separate "Go Live" button exists (per user decision) - Test message step is required (not skippable)

<success_criteria>

  • Operator can initiate Slack OAuth from the portal
  • Operator can paste WhatsApp credentials via guided form
  • Onboarding wizard completes in 3 steps: connect -> configure -> test
  • Agent goes live automatically after successful test message
  • Operator can manage BYO API keys from settings page (backed by Plan 01 Task 3 endpoints)
  • Portal builds without errors </success_criteria>
After completion, create `.planning/phases/03-operator-experience/03-02-SUMMARY.md`