Files
konstruct/.planning/phases/05-employee-design/05-04-PLAN.md

6.9 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, gap_closure, requirements, must_haves
phase plan type wave depends_on files_modified autonomous gap_closure requirements must_haves
05-employee-design 04 execute 1
packages/portal/proxy.ts
packages/portal/app/(dashboard)/agents/page.tsx
packages/portal/components/wizard-steps/step-review.tsx
true true
EMPL-04
truths artifacts key_links
customer_operator is redirected away from /agents/new (and all sub-paths) by proxy.ts before reaching creation UI
customer_operator does not see the New Employee button on the agents list page
Wizard deploy failure displays a visible error message to the user
path provides contains
packages/portal/proxy.ts RBAC redirect for /agents/new paths /agents/new
path provides contains
packages/portal/app/(dashboard)/agents/page.tsx Role-gated New Employee button useSession
path provides
packages/portal/components/wizard-steps/step-review.tsx Visible error handling on deploy failure
from to via pattern
packages/portal/proxy.ts CUSTOMER_OPERATOR_RESTRICTED /agents/new added to restricted array "/agents/new"
from to via pattern
packages/portal/components/wizard-steps/step-review.tsx error UI div re-thrown error sets createAgent.isError throw
Close two verification gaps from Phase 5 Employee Design:
  1. Frontend RBAC gap: customer_operator can navigate to /agents/new and sub-paths (proxy.ts missing restriction) and sees the New Employee button (no role guard)
  2. Wizard deploy error handling: catch block swallows errors so the error UI never renders

Purpose: Complete EMPL-04 compliance (RBAC-enforced access) and fix silent deploy failure UX Output: Three patched files — proxy.ts, agents/page.tsx, step-review.tsx

<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/05-employee-design/05-VERIFICATION.md

From packages/portal/proxy.ts (line 23):

const CUSTOMER_OPERATOR_RESTRICTED = ["/billing", "/settings/api-keys", "/users", "/admin"];

From packages/portal/app/(dashboard)/agents/page.tsx (line 74):

<Button onClick={() => router.push("/agents/new")}>
  <Plus className="h-4 w-4 mr-2" />
  New Employee
</Button>

From packages/portal/components/wizard-steps/step-review.tsx (lines 28-53):

const handleDeploy = async () => {
  try {
    const agent = await createAgent.mutateAsync({
      tenantId,
      data: { /* ... */ },
    });
    router.push(`/agents/${agent.id}?tenant=${tenantId}`);
  } catch (err) {
    console.error("Failed to deploy agent:", err);
  }
};

Error display div (lines 141-145):

{createAgent.error && (
  <div className="rounded-md bg-destructive/10 border border-destructive/20 p-3">
    <p className="text-sm text-destructive">{createAgent.error.message}</p>
  </div>
)}

Session pattern used in portal:

import { useSession } from "next-auth/react";
const { data: session } = useSession();
const role = (session?.user as { role?: string })?.role;
Task 1: Add /agents/new to proxy RBAC restrictions and hide New Employee button for operators packages/portal/proxy.ts, packages/portal/app/(dashboard)/agents/page.tsx 1. In proxy.ts, add "/agents/new" to the CUSTOMER_OPERATOR_RESTRICTED array (line 23). The existing startsWith check on line 59 already handles sub-paths, so adding "/agents/new" will automatically block /agents/new/templates, /agents/new/wizard, and /agents/new/advanced.
  1. In agents/page.tsx, add role-based visibility to the New Employee button:
    • Import useSession from "next-auth/react"
    • Get session via useSession() hook
    • Extract role: const role = (session?.user as { role?: string })?.role
    • Wrap the New Employee Button in a conditional: only render when role is "platform_admin" or "customer_admin" (i.e., hide when role is "customer_operator" or undefined)
    • Use: {role && role !== "customer_operator" && (<Button ...>)}

Do NOT change any other behavior. The button still navigates to /agents/new. The proxy redirect is the security layer; the button hide is UX polish. cd /home/adelorenzo/repos/konstruct/packages/portal && grep -q '"/agents/new"' proxy.ts && grep -q 'useSession' app/(dashboard)/agents/page.tsx && echo "PASS" customer_operator is redirected by proxy.ts when navigating to /agents/new or any sub-path; New Employee button is hidden for customer_operator role

Task 2: Fix wizard deploy error handling to surface errors to user packages/portal/components/wizard-steps/step-review.tsx In step-review.tsx, fix the handleDeploy catch block (lines 50-52) to re-throw the error so TanStack Query's mutateAsync sets the mutation's isError/error state. This allows the existing error display div at lines 141-145 to render.

Change the catch block from:

} catch (err) {
  console.error("Failed to deploy agent:", err);
}

To:

} catch (err) {
  console.error("Failed to deploy agent:", err);
  throw err;
}

This is the minimal fix. The mutateAsync call throws on error; catching without re-throwing prevents TanStack Query from updating mutation state. Re-throwing lets createAgent.error get set, which triggers the existing error div to display.

Do NOT add useState for local error handling — the existing createAgent.error UI is correctly wired, it just never receives the error. cd /home/adelorenzo/repos/konstruct/packages/portal && grep -A2 'catch (err)' components/wizard-steps/step-review.tsx | grep -q 'throw err' && echo "PASS" Deploy failures in wizard now surface error message to user via the existing error display div; createAgent.isError becomes true on failure

1. grep for "/agents/new" in CUSTOMER_OPERATOR_RESTRICTED array in proxy.ts 2. grep for useSession import in agents/page.tsx 3. grep for "throw err" in step-review.tsx catch block 4. Confirm no other files were modified

<success_criteria>

  • proxy.ts CUSTOMER_OPERATOR_RESTRICTED includes "/agents/new"
  • agents/page.tsx New Employee button conditionally rendered based on session role
  • step-review.tsx catch block re-throws error so mutation error state is set
  • All three changes are minimal, surgical fixes to close the two verification gaps </success_criteria>
After completion, create `.planning/phases/05-employee-design/05-04-SUMMARY.md`