4.7 KiB
4.7 KiB
Staff Management — Integration Guide
1. Register the routes in your Express app
// apps/api/src/index.ts (or server.ts)
import express from 'express'
import teamRouter from './routes/team'
import webhookRouter from './routes/webhooks'
const app = express()
// Webhook MUST use raw body — register BEFORE express.json()
app.use(
'/webhooks',
express.raw({ type: 'application/json' }),
webhookRouter
)
// All other routes use JSON
app.use(express.json())
// Team routes — mounted under /api/v1/team (matches api-routes.md)
app.use('/api/v1/team', teamRouter)
2. Install the Clerk webhook (Clerk Dashboard → Webhooks)
- Go to clerk.com → your app → Webhooks → Add endpoint
- URL:
https://api.RentalDriveGo.com/webhooks/clerk - Events to subscribe:
user.created - Copy the Signing Secret and add to
.env:
CLERK_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxx
- Install
svixfor signature verification:
npm install svix
3. Environment variables needed
# Clerk
CLERK_SECRET_KEY=sk_live_...
CLERK_WEBHOOK_SECRET=whsec_...
# Frontend
NEXT_PUBLIC_API_URL=https://api.RentalDriveGo.com/api/v1
# Dashboard URL (used in invite redirect)
DASHBOARD_URL=https://app.RentalDriveGo.com
4. Add the page to the Next.js dashboard app
apps/dashboard/
├── app/
│ └── dashboard/
│ └── team/
│ └── page.tsx ← copy frontend/pages/team.tsx here
├── components/
│ └── team/
│ ├── InviteModal.tsx ← copy from frontend/components/team/
│ ├── EditMemberModal.tsx
│ └── PermissionsMatrix.tsx
└── hooks/
└── useTeam.ts ← copy from frontend/hooks/
Add the route to your dashboard sidebar navigation:
// components/Sidebar.tsx — add to nav items
{ href: '/dashboard/team', label: 'Team', icon: UsersIcon }
5. requireRole middleware placement
The requireRole middleware is already applied inside the team router.
Only expose it if you need it elsewhere (e.g., PATCH /pricing-rules → requireRole('MANAGER')):
import { requireRole } from './middleware/requireRole'
// Example: license approval endpoint (OWNER or MANAGER only)
router.post(
'/customers/:id/approve-license',
requireRole('MANAGER'),
approveLicenseHandler
)
6. Invite acceptance flow (frontend)
When a user clicks the magic link in their invitation email, Clerk redirects them to:
https://app.RentalDriveGo.com/onboarding/accept-invite?__clerk_ticket=...
Create this page in your Next.js app:
// app/onboarding/accept-invite/page.tsx
'use client'
import { useEffect } from 'react'
import { useClerk } from '@clerk/nextjs'
import { useRouter } from 'next/navigation'
export default function AcceptInvite() {
const { handleRedirectCallback } = useClerk()
const router = useRouter()
useEffect(() => {
handleRedirectCallback({}).then(() => {
// Clerk webhook fires user.created → activates Employee record in DB
// Redirect to dashboard after a short delay
setTimeout(() => router.replace('/dashboard'), 1000)
})
}, [])
return (
<div className="flex items-center justify-center min-h-screen">
<p className="text-sm text-zinc-500">Setting up your account…</p>
</div>
)
}
7. Prisma type extensions (optional, for req.employee)
To get TypeScript to recognize req.companyId and req.employee on Express requests,
add a type declaration file:
// types/express.d.ts
import { Employee, Company } from '@prisma/client'
declare global {
namespace Express {
interface Request {
companyId: string
company: Company
employee: Employee
}
}
}
8. Summary of files delivered
| File | Purpose |
|---|---|
backend/services/teamService.ts |
All business logic — invite, update role, deactivate, remove, Clerk webhook handler |
backend/routes/team.ts |
Express router — all /team endpoints |
backend/routes/webhooks.ts |
Clerk webhook listener — activates employee on invite acceptance |
backend/middleware/requireRole.ts |
Role-rank guard middleware — reusable across all routers |
frontend/hooks/useTeam.ts |
React data hook — fetch, invite, updateRole, deactivate, reactivate, remove |
frontend/pages/team.tsx |
Full /dashboard/team Next.js page |
frontend/components/team/InviteModal.tsx |
Invite new member modal with role picker |
frontend/components/team/EditMemberModal.tsx |
Edit role, deactivate, reactivate, remove modal with confirmation step |
frontend/components/team/PermissionsMatrix.tsx |
Static role × feature permissions table |