docs(05-employee-design): create gap closure plan for RBAC and error handling fixes
This commit is contained in:
@@ -103,12 +103,13 @@ Plans:
|
|||||||
3. A template-deployed agent is immediately functional — responds in connected channels with the template's persona, tools, and escalation rules
|
3. A template-deployed agent is immediately functional — responds in connected channels with the template's persona, tools, and escalation rules
|
||||||
4. The wizard and templates are accessible to both platform admins and customer admins (respecting RBAC)
|
4. The wizard and templates are accessible to both platform admins and customer admins (respecting RBAC)
|
||||||
5. Created agents appear in the Agent Designer for further customization after initial setup
|
5. Created agents appear in the Agent Designer for further customization after initial setup
|
||||||
**Plans**: 3 plans
|
**Plans**: 4 plans
|
||||||
|
|
||||||
Plans:
|
Plans:
|
||||||
- [ ] 05-01-PLAN.md — Backend: AgentTemplate model, migration 007 with 7 seed templates, template list/deploy API, system prompt builder, unit + integration tests
|
- [ ] 05-01-PLAN.md — Backend: AgentTemplate model, migration 007 with 7 seed templates, template list/deploy API, system prompt builder, unit + integration tests
|
||||||
- [ ] 05-02-PLAN.md — Frontend: three-option entry screen, template gallery with one-click deploy, 5-step wizard (Role/Persona/Tools/Channels/Escalation), Advanced mode relocation
|
- [ ] 05-02-PLAN.md — Frontend: three-option entry screen, template gallery with one-click deploy, 5-step wizard (Role/Persona/Tools/Channels/Escalation), Advanced mode relocation
|
||||||
- [ ] 05-03-PLAN.md — Human verification: test all three creation paths, RBAC enforcement, system prompt auto-generation
|
- [ ] 05-03-PLAN.md — Human verification: test all three creation paths, RBAC enforcement, system prompt auto-generation
|
||||||
|
- [ ] 05-04-PLAN.md — Gap closure: add /agents/new to proxy RBAC restrictions, hide New Employee button for operators, fix wizard deploy error handling
|
||||||
|
|
||||||
## Progress
|
## Progress
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5
|
|||||||
| 2. Agent Features | 6/6 | Complete | 2026-03-24 |
|
| 2. Agent Features | 6/6 | Complete | 2026-03-24 |
|
||||||
| 3. Operator Experience | 5/5 | Complete | 2026-03-24 |
|
| 3. Operator Experience | 5/5 | Complete | 2026-03-24 |
|
||||||
| 4. RBAC | 3/3 | Complete | 2026-03-24 |
|
| 4. RBAC | 3/3 | Complete | 2026-03-24 |
|
||||||
| 5. Employee Design | 3/3 | Complete | 2026-03-25 |
|
| 5. Employee Design | 3/4 | Gap Closure | 2026-03-25 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
182
.planning/phases/05-employee-design/05-04-PLAN.md
Normal file
182
.planning/phases/05-employee-design/05-04-PLAN.md
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
---
|
||||||
|
phase: 05-employee-design
|
||||||
|
plan: 04
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- packages/portal/proxy.ts
|
||||||
|
- packages/portal/app/(dashboard)/agents/page.tsx
|
||||||
|
- packages/portal/components/wizard-steps/step-review.tsx
|
||||||
|
autonomous: true
|
||||||
|
gap_closure: true
|
||||||
|
requirements: [EMPL-04]
|
||||||
|
|
||||||
|
must_haves:
|
||||||
|
truths:
|
||||||
|
- "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"
|
||||||
|
artifacts:
|
||||||
|
- path: "packages/portal/proxy.ts"
|
||||||
|
provides: "RBAC redirect for /agents/new paths"
|
||||||
|
contains: "/agents/new"
|
||||||
|
- path: "packages/portal/app/(dashboard)/agents/page.tsx"
|
||||||
|
provides: "Role-gated New Employee button"
|
||||||
|
contains: "useSession"
|
||||||
|
- path: "packages/portal/components/wizard-steps/step-review.tsx"
|
||||||
|
provides: "Visible error handling on deploy failure"
|
||||||
|
key_links:
|
||||||
|
- from: "packages/portal/proxy.ts"
|
||||||
|
to: "CUSTOMER_OPERATOR_RESTRICTED"
|
||||||
|
via: "/agents/new added to restricted array"
|
||||||
|
pattern: '"/agents/new"'
|
||||||
|
- from: "packages/portal/components/wizard-steps/step-review.tsx"
|
||||||
|
to: "error UI div"
|
||||||
|
via: "re-thrown error sets createAgent.isError"
|
||||||
|
pattern: "throw"
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
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
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
@/home/adelorenzo/.claude/get-shit-done/workflows/execute-plan.md
|
||||||
|
@/home/adelorenzo/.claude/get-shit-done/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@.planning/STATE.md
|
||||||
|
@.planning/phases/05-employee-design/05-VERIFICATION.md
|
||||||
|
|
||||||
|
<interfaces>
|
||||||
|
<!-- Key code the executor needs to patch. Extracted from codebase. -->
|
||||||
|
|
||||||
|
From packages/portal/proxy.ts (line 23):
|
||||||
|
```typescript
|
||||||
|
const CUSTOMER_OPERATOR_RESTRICTED = ["/billing", "/settings/api-keys", "/users", "/admin"];
|
||||||
|
```
|
||||||
|
|
||||||
|
From packages/portal/app/(dashboard)/agents/page.tsx (line 74):
|
||||||
|
```typescript
|
||||||
|
<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):
|
||||||
|
```typescript
|
||||||
|
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):
|
||||||
|
```typescript
|
||||||
|
{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:
|
||||||
|
```typescript
|
||||||
|
import { useSession } from "next-auth/react";
|
||||||
|
const { data: session } = useSession();
|
||||||
|
const role = (session?.user as { role?: string })?.role;
|
||||||
|
```
|
||||||
|
</interfaces>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Add /agents/new to proxy RBAC restrictions and hide New Employee button for operators</name>
|
||||||
|
<files>packages/portal/proxy.ts, packages/portal/app/(dashboard)/agents/page.tsx</files>
|
||||||
|
<action>
|
||||||
|
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.
|
||||||
|
|
||||||
|
2. 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.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
<automated>cd /home/adelorenzo/repos/konstruct/packages/portal && grep -q '"/agents/new"' proxy.ts && grep -q 'useSession' app/\(dashboard\)/agents/page.tsx && echo "PASS"</automated>
|
||||||
|
</verify>
|
||||||
|
<done>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</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Fix wizard deploy error handling to surface errors to user</name>
|
||||||
|
<files>packages/portal/components/wizard-steps/step-review.tsx</files>
|
||||||
|
<action>
|
||||||
|
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:
|
||||||
|
```typescript
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to deploy agent:", err);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To:
|
||||||
|
```typescript
|
||||||
|
} 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.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
<automated>cd /home/adelorenzo/repos/konstruct/packages/portal && grep -A2 'catch (err)' components/wizard-steps/step-review.tsx | grep -q 'throw err' && echo "PASS"</automated>
|
||||||
|
</verify>
|
||||||
|
<done>Deploy failures in wizard now surface error message to user via the existing error display div; createAgent.isError becomes true on failure</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
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
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/05-employee-design/05-04-SUMMARY.md`
|
||||||
|
</output>
|
||||||
Reference in New Issue
Block a user