Files
carmanagement/INTEGRATION.md
T
Administrator 65394f6436 project design
2026-04-30 18:28:05 +00:00

4.7 KiB
Raw Blame History

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)

  1. Go to clerk.com → your app → WebhooksAdd endpoint
  2. URL: https://api.rentflow.com/webhooks/clerk
  3. Events to subscribe: user.created
  4. Copy the Signing Secret and add to .env:
CLERK_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxx
  1. Install svix for 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.rentflow.com/api/v1

# Dashboard URL (used in invite redirect)
DASHBOARD_URL=https://app.rentflow.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-rulesrequireRole('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.rentflow.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