17 KiB
17 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, user_setup, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | user_setup | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-foundation | 04 | execute | 2 |
|
|
true |
|
|
|
Purpose: Give operators a real admin interface to create tenants and configure AI employees. Per user decision, the portal starts in Phase 1 with Auth.js v5 — no hardcoded credentials or throwaway auth.
Output: Working portal at localhost:3000 with login, tenant management (create/list/view/edit/delete), and Agent Designer (name, role, persona, system prompt, tool assignments, escalation rules). Backed by FastAPI API endpoints with integration tests.
<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/01-foundation/01-CONTEXT.md @.planning/phases/01-foundation/01-RESEARCH.md @.planning/phases/01-foundation/01-01-SUMMARY.mdFrom packages/shared/models/tenant.py:
class Tenant(Base):
id: Mapped[uuid.UUID]
name: Mapped[str] # unique
slug: Mapped[str] # unique
settings: Mapped[dict] # JSON
created_at: Mapped[datetime]
updated_at: Mapped[datetime]
class Agent(Base):
id: Mapped[uuid.UUID]
tenant_id: Mapped[uuid.UUID] # FK -> Tenant
name: Mapped[str]
role: Mapped[str]
persona: Mapped[str | None]
system_prompt: Mapped[str | None]
model_preference: Mapped[str] # "quality" | "fast"
tool_assignments: Mapped[list] # JSON
escalation_rules: Mapped[list] # JSON
is_active: Mapped[bool]
created_at: Mapped[datetime]
updated_at: Mapped[datetime]
From packages/shared/models/auth.py:
class PortalUser(Base):
id: Mapped[uuid.UUID]
email: Mapped[str] # unique
hashed_password: Mapped[str]
name: Mapped[str]
is_admin: Mapped[bool]
created_at: Mapped[datetime]
updated_at: Mapped[datetime]
From packages/shared/db.py:
async def get_session() -> AsyncGenerator[AsyncSession, None]: ...
**Auth endpoint:**
- `POST /auth/verify`: Accepts `{ email: str, password: str }`, validates against PortalUser table using bcrypt, returns `{ id, email, name, is_admin }` or 401. Used by Auth.js Credentials provider.
- `POST /auth/register`: Accepts `{ email, password, name }`, creates PortalUser with bcrypt-hashed password. Returns 201 with user info. (Needed for initial setup — consider restricting to admin-only in production.)
**Tenant endpoints (PRTA-01):**
- `GET /tenants`: List all tenants (paginated, 20 per page). No RLS — platform admin sees all tenants.
- `POST /tenants`: Create tenant. Accepts `{ name: str, slug: str, settings: dict? }`. Validates name length 2-100, slug format (lowercase, hyphens, 2-50 chars). Returns 201 with tenant object.
- `GET /tenants/{id}`: Get tenant by ID. Returns 404 if not found.
- `PUT /tenants/{id}`: Update tenant. Accepts partial updates. Returns updated tenant.
- `DELETE /tenants/{id}`: Delete tenant. Returns 204. Cascade deletes agents and channel_connections.
**Agent endpoints (PRTA-02):**
- `GET /tenants/{tenant_id}/agents`: List agents for a tenant.
- `POST /tenants/{tenant_id}/agents`: Create agent. Accepts `{ name, role, persona?, system_prompt?, model_preference?, tool_assignments?, escalation_rules? }`. Name required, min 1 char. Role required, min 1 char. Returns 201.
- `GET /tenants/{tenant_id}/agents/{id}`: Get agent by ID.
- `PUT /tenants/{tenant_id}/agents/{id}`: Update agent. Accepts partial updates.
- `DELETE /tenants/{tenant_id}/agents/{id}`: Delete agent. Returns 204.
Use Pydantic v2 request/response schemas (TenantCreate, TenantResponse, AgentCreate, AgentResponse, etc.). Use SQLAlchemy 2.0 `select()` style — never 1.x `session.query()`.
2. Create `tests/integration/test_portal_tenants.py` (PRTA-01):
- Test create tenant with valid data returns 201
- Test create tenant with duplicate slug returns 409
- Test list tenants returns created tenants
- Test get tenant by ID returns correct tenant
- Test update tenant name
- Test delete tenant returns 204 and tenant is gone
- Test create tenant with invalid slug (uppercase, too short) returns 422
- Use `httpx.AsyncClient` with the FastAPI app
3. Create `tests/integration/test_portal_agents.py` (PRTA-02):
- Test create agent with all fields returns 201
- Test create agent with minimal fields (name + role only) returns 201 with defaults
- Test list agents for a tenant returns only that tenant's agents
- Test get agent by ID
- Test update agent persona and system prompt
- Test delete agent
- Test Agent Designer fields are all stored and retrievable: name, role, persona, system_prompt, model_preference, tool_assignments (JSON array), escalation_rules (JSON array)
- Use `httpx.AsyncClient`
cd /home/adelorenzo/repos/konstruct && pytest tests/integration/test_portal_tenants.py tests/integration/test_portal_agents.py -x -q
- Tenant CRUD endpoints all functional with proper validation and error responses
- Agent CRUD endpoints support all Agent Designer fields
- Auth verify endpoint validates email/password against PortalUser table
- Integration tests prove all CRUD operations work correctly
- Pydantic schemas enforce input validation
Task 2: Next.js portal with Auth.js v5, tenant management, and Agent Designer
packages/portal/package.json,
packages/portal/tsconfig.json,
packages/portal/tailwind.config.ts,
packages/portal/app/layout.tsx,
packages/portal/app/page.tsx,
packages/portal/app/(auth)/login/page.tsx,
packages/portal/app/dashboard/layout.tsx,
packages/portal/app/dashboard/page.tsx,
packages/portal/app/tenants/page.tsx,
packages/portal/app/tenants/[id]/page.tsx,
packages/portal/app/tenants/new/page.tsx,
packages/portal/app/agents/page.tsx,
packages/portal/app/agents/[id]/page.tsx,
packages/portal/app/agents/new/page.tsx,
packages/portal/app/api/auth/[...nextauth]/route.ts,
packages/portal/lib/auth.ts,
packages/portal/lib/api.ts,
packages/portal/lib/queries.ts,
packages/portal/components/tenant-form.tsx,
packages/portal/components/agent-designer.tsx,
packages/portal/components/nav.tsx,
packages/portal/middleware.ts
1. Initialize Next.js 16 project in `packages/portal/`:
- `npx create-next-app@latest . --typescript --tailwind --eslint --app`
- Install: `@tanstack/react-query react-hook-form zod next-auth@5 @hookform/resolvers`
- Initialize shadcn/ui: `npx shadcn@latest init` then add components: button, input, textarea, card, table, form, label, select, dialog, toast, navigation-menu, separator, badge
2. Create `packages/portal/lib/auth.ts`:
- Auth.js v5 with Credentials provider per research Pattern 7
- Credentials provider calls `POST ${API_URL}/api/portal/auth/verify` with email + password
- JWT session strategy (stateless, no DB session table needed for Phase 1)
- Custom pages: signIn -> "/login"
- Export `{ handlers, auth, signIn, signOut }`
3. Create `packages/portal/app/api/auth/[...nextauth]/route.ts`:
- Re-export `handlers.GET` and `handlers.POST` from lib/auth.ts
4. Create `packages/portal/middleware.ts`:
- Protect all routes except `/login` and `/api/auth/*`
- Redirect unauthenticated users to `/login`
5. Create `packages/portal/app/(auth)/login/page.tsx`:
- Email + password login form using shadcn/ui Input, Button, Card
- Form validation with React Hook Form + Zod (email format, password min 8 chars)
- Error display for invalid credentials
- On success, redirect to /dashboard
6. Create `packages/portal/lib/api.ts`:
- API client configured with base URL from env (NEXT_PUBLIC_API_URL)
- Typed fetch wrapper with error handling
7. Create `packages/portal/lib/queries.ts`:
- TanStack Query hooks: `useTenants()`, `useTenant(id)`, `useCreateTenant()`, `useUpdateTenant()`, `useDeleteTenant()`
- TanStack Query hooks: `useAgents(tenantId)`, `useAgent(tenantId, id)`, `useCreateAgent()`, `useUpdateAgent()`, `useDeleteAgent()`
- Proper invalidation on mutations
8. Create `packages/portal/components/nav.tsx`:
- Sidebar navigation with links: Dashboard, Tenants, Employees (label it "Employees" not "Agents" — per the AI employee branding)
- Active state highlighting
- Logout button calling signOut
9. Create `packages/portal/app/dashboard/layout.tsx`:
- Layout with sidebar nav + main content area
- TanStack QueryClientProvider wrapping children
10. Create `packages/portal/app/dashboard/page.tsx`:
- Simple dashboard landing page with tenant count and agent count stats
11. Create tenant management pages:
- `app/tenants/page.tsx`: Table listing all tenants with name, slug, created date. "New Tenant" button. Row click navigates to detail.
- `app/tenants/new/page.tsx`: Tenant creation form (name, slug). Slug auto-generated from name (lowercase, hyphenated).
- `app/tenants/[id]/page.tsx`: Tenant detail with edit form and delete button. Shows agents for this tenant.
12. Create `packages/portal/components/tenant-form.tsx`:
- Reusable form for create/edit tenant. React Hook Form + Zod validation.
13. Create Agent Designer pages — PER USER DECISION this is a PROMINENT, DEDICATED module:
- `app/agents/page.tsx`: Card grid of all agents across tenants. Each card shows agent name, role, tenant name, active status. "New Employee" button.
- `app/agents/new/page.tsx`: Full Agent Designer form. Grouped into sections:
- **Identity:** Name (text), Role (text) — e.g., "Customer Support Lead"
- **Personality:** Persona (textarea — personality description), System Prompt (textarea — raw system prompt override)
- **Configuration:** Model Preference (select: "quality" / "fast"), Tenant (select dropdown)
- **Capabilities:** Tool Assignments (JSON editor or tag-style input — list of tool names)
- **Escalation:** Escalation Rules (JSON editor or structured form — condition + action pairs)
- **Status:** Active toggle
- `app/agents/[id]/page.tsx`: Edit existing agent with same form, pre-populated. Delete button.
14. Create `packages/portal/components/agent-designer.tsx`:
- The Agent Designer form component. React Hook Form + Zod validation.
- Zod schema: name (min 1), role (min 1), persona (optional), system_prompt (optional), model_preference (enum: quality|fast), tool_assignments (string array), escalation_rules (array of {condition: string, action: string}), is_active (boolean).
- Use the "employee" language in labels and placeholders: "Employee Name", "Job Title" (for role), "Job Description" (for persona), "Statement of Work" (for system_prompt) — per user's specific vision that the Agent Designer is about defining an employee.
- shadcn/ui components: Card for section grouping, Textarea for persona/system_prompt, Input for name/role, Select for model_preference, Badge for tool tags.
15. Create `packages/portal/app/layout.tsx`:
- Root layout with Tailwind, font, metadata (title: "Konstruct Portal")
16. `packages/portal/app/page.tsx`:
- Redirect to /dashboard if authenticated, /login if not
17. Update `docker-compose.yml` to add portal service on port 3000 with env vars.
cd /home/adelorenzo/repos/konstruct/packages/portal && npm run build
- Portal builds successfully with Next.js 16
- Login page authenticates against FastAPI /auth/verify via Auth.js v5 Credentials provider
- Protected routes redirect to /login when unauthenticated
- Tenant CRUD: list, create, view, edit, delete all functional
- Agent Designer: all fields (name, role, persona, system prompt, model preference, tool assignments, escalation rules) saveable and loadable
- Agent Designer uses employee-centric language (Employee Name, Job Title, Job Description, Statement of Work)
- Agent Designer is a prominent top-level module, not buried in settings
- shadcn/ui styling with Tailwind CSS
- `pytest tests/integration/test_portal_tenants.py tests/integration/test_portal_agents.py -x` proves API CRUD works
- `cd packages/portal && npm run build` compiles without errors
- Portal pages render tenant list, tenant create/edit, agent designer
- Auth.js v5 login flow works with email/password
<success_criteria>
- Operator can log in, create tenants, and configure AI employees through the portal
- Agent Designer prominently accessible with all required fields
- All API CRUD operations validated by integration tests
- Portal builds cleanly with Next.js 16 </success_criteria>